Compare commits

..

31 Commits

Author SHA1 Message Date
353df045d8 Merge branch 'master' of http://192.168.10.243:3000/owrainfo/confirms 2026-03-03 21:41:09 +09:00
f02f8c0457 현장 확인 업로드 2026-03-03 21:41:02 +09:00
243ca0c45e 현장 확인 업로드 수정 2026-03-03 21:39:51 +09:00
e54b5bbbb8 1 2026-02-24 13:59:36 +09:00
69e6aa5fe6 현장확인 v2 항목 추가 2026-02-23 18:54:53 +09:00
af7846ea7c 화면 수정 2026-02-23 18:46:33 +09:00
b237c4b934 화면 수정 2026-02-20 20:47:35 +09:00
d91738c667 현장 확인 > 처리 가능 수량 관리 api 및 수정 2026-02-20 13:49:43 +09:00
c129362724 컨텐츠 영역 확장 2026-02-19 14:24:40 +09:00
49d33b55b8 좌측 메뉴 조금더 줄임 2026-02-19 14:22:35 +09:00
c3b4e0e712 화면 수정 2026-02-19 13:57:33 +09:00
f988ecabd2 701 화면 수정 2026-02-12 21:11:11 +09:00
99a072f732 오류 수정 2026-02-11 21:51:10 +09:00
b0e7cf0df0 테스트 2026-02-11 19:49:16 +09:00
ed80e90bb3 blockUI 추가 2026-02-11 19:29:44 +09:00
c17110087c blockUI success일때 추가 2026-02-11 19:23:53 +09:00
3cd6b238d2 현장확인 동기화 슬롯 api 추가 2026-02-11 18:26:48 +09:00
906f208734 수정 2026-02-10 14:17:03 +09:00
54e8c50a11 view 2026-02-10 14:13:29 +09:00
5504ca154a 워커 서비스 로그 통합 2026-02-10 11:56:01 +09:00
d666315497 주석 제거 2026-02-09 18:16:22 +09:00
424b0e9411 로그 생성 2026-02-09 18:15:45 +09:00
85fdb38281 환경별 로그 2026-02-09 18:14:22 +09:00
4f78d5493c 환경별 버킷 설정 2026-02-09 15:51:37 +09:00
56a7fe94d5 환경별 버킷 설정 수정 2026-02-09 15:50:32 +09:00
23286f6890 Merge branch 'master' of http://192.168.10.243:3000/owrainfo/confirms 2026-02-09 15:40:23 +09:00
38ea1c1129 env 환경에 따라 object storage 경로 변경 2026-02-09 15:39:52 +09:00
c6da9c12be 링크이동 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/57
2026-02-09 14:33:42 +09:00
f6857ae959 링크이동 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/56
2026-02-09 11:00:52 +09:00
98d74658e9 사이드메뉴 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/55
2026-02-09 09:49:55 +09:00
922c85962c 현장확인 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/54
2026-02-06 10:39:16 +09:00
157 changed files with 5395 additions and 3526 deletions

1
README
View File

@@ -1 +1,2 @@
여기 작업 하면 어떻게 되나?
1111

View File

@@ -42,11 +42,13 @@ class NaverWorker extends BaseCommand
// 1. DB 연결 상태 체크 (더 견고하게)
try {
if ($this->db->connID === false || !@$this->db->connID->ping()) {
// connID가 없거나, 가벼운 쿼리 실행 실패 시 재연결 시도
if ($this->db->connID === false || !$this->db->simpleQuery('SELECT 1')) {
$this->db->reconnect();
CLI::write(CLI::color('🔄 Database reconnected.', 'yellow'));
}
} catch (\Throwable $e) {
// 어떤 이유로든 에러 발생 시 재연결 시도
$this->db->reconnect();
}

View File

@@ -16,7 +16,7 @@ class App extends BaseConfig
*
* E.g., http://example.com/
*/
public string $baseURL = 'http://test2-admin.confirms.co.kr';
public string $baseURL = 'http://localtest2-admin.confirms.co.kr';
/**
* Allowed Hostnames in the Site URL other than the hostname in the baseURL.
@@ -199,4 +199,37 @@ class App extends BaseConfig
* @see http://www.w3.org/TR/CSP/
*/
public bool $CSPEnabled = false;
/**
* --------------------------------------------------------------------------
* Constructor - .env 값 로드
* --------------------------------------------------------------------------
*/
public function __construct()
{
parent::__construct();
// .env 파일의 값으로 속성 오버라이드
if (env('app.baseURL')) {
$this->baseURL = env('app.baseURL');
}
if (env('app.appTimezone')) {
$this->appTimezone = env('app.appTimezone');
}
if (env('app.forceGlobalSecureRequests') !== null) {
$this->forceGlobalSecureRequests = filter_var(
env('app.forceGlobalSecureRequests'),
FILTER_VALIDATE_BOOLEAN
);
}
if (env('app.CSPEnabled') !== null) {
$this->CSPEnabled = filter_var(
env('app.CSPEnabled'),
FILTER_VALIDATE_BOOLEAN
);
}
}
}

View File

@@ -82,8 +82,18 @@ defined('EXIT__AUTO_MAX') || define('EXIT__AUTO_MAX', 125); // highest automa
/**
* 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');
// 환경별 버킷 설정
$environment = getenv('CI_ENVIRONMENT') ?: 'production';
if ($environment === 'development') {
define('NCLOUD_S3_BUCKET', 'confirms-object-test');
define('NCLOUD_OBJECT_STORAGE_URL', 'https://kr.object.ncloudstorage.com/confirms-object-test');
} else {
define('NCLOUD_S3_BUCKET', 'confirms-object');
define('NCLOUD_OBJECT_STORAGE_URL', 'https://kr.object.ncloudstorage.com/confirms-object');
}
// .env 파일에서 NCLOUD 설정 읽기
define('NCLOUD_S3_KEY', getenv('ncloud.s3.key') ?: 'ncp_iam_BPAMKR3l50hXJiQ6qpSP');
define('NCLOUD_S3_SECRET', getenv('ncloud.s3.secret') ?: 'ncp_iam_BPKMKRW2GU59UE59I1QftVGst6NJgnmbSc');
define('NCLOUD_S3_ENDPOINT', getenv('ncloud.s3.endpoint') ?: 'https://kr.object.ncloudstorage.com');

View File

@@ -76,8 +76,10 @@ $routes->group('', ['namespace' => 'App\Controllers\Article'], static function (
$routes->post('chgStatus', 'Receipt::chgStatus'); // 상태변경
$routes->post('sendSms', 'Receipt::sendSms'); // 문자발송
$routes->post('saveRecInfo', 'Receipt::saveRecInfo'); // 거주인정보저장
$routes->get('getImages', 'Receipt::getImages'); // 이미지 목록 조회
$routes->post('uploadFile', 'Receipt::uploadFile'); // 파일업로드
$routes->post('removeUploadFile', 'Receipt::removeUploadFile'); // 파일삭제
$routes->post('updateImageOrder', 'Receipt::updateImageOrder'); // 이미지 순서 업데이트
$routes->get('downloadAllImages', 'Receipt::downloadAllImages'); // 이미지 일괄 다운로드
$routes->post('saveImgLocation', 'Receipt::saveImgLocation'); // 촬영위치 저장
});
@@ -661,6 +663,12 @@ $routes->group('manage', ['namespace' => 'App\Controllers\Manage'], function ($r
/** API - 로그인로그관리 */
$routes->get('loginlog/getLogList', 'LoginLog::getLogList');
$routes->get('loginlog/excel', 'LoginLog::excel');
/** Worker 로그 관리 */
$routes->get('workerlog', 'WorkerLog::index');
$routes->get('workerlog/stream', 'WorkerLog::stream');
$routes->get('workerlog/download', 'WorkerLog::download');
$routes->post('workerlog/delete', 'WorkerLog::delete');
});
/**

View File

@@ -109,42 +109,68 @@ class Processible extends BaseController
// 지역별 수량 저장
public function saveArea()
{
log_message('info', '[Processible::saveArea] 진입');
try {
$rows = $this->request->getPost('rows');
$rows = json_decode($rows, true);
// dd($rows);
// exit;
if (count($rows) > 0) {
foreach ($rows as $row):
// API 형식으로 변환 및 DB 저장을 한 번에 처리
$syncSlotData = [];
foreach ($rows as $row) {
// DB 저장
$this->model->saveArea($row);
endforeach;
// 동시에 API 데이터 구성
$syncSlotData[] = [
'baseDate' => $row['sc_date'],
'legalDivisionNumber' => $row['region_cd'],
'slots' => [
'am' => [
'max' => (int) $row['am_cnt'],
'reserved' => 0
],
'pm' => [
'max' => (int) $row['pm_cnt'],
'reserved' => 0
]
]
];
}
log_message('info', '[Processible::saveArea] 슬롯 동기화 시작 | Count: ' . count($syncSlotData));
$naverClient = new \App\Libraries\NaverApiClient();
$apiResponse = $naverClient->syncSiteSlot($syncSlotData);
// API 응답 처리
if ($apiResponse === null) {
log_message('error', '[Processible::saveArea] Naver API 슬롯 동기화 실패 | Data: ' . json_encode($syncSlotData, JSON_UNESCAPED_UNICODE));
return $this->response->setJSON([
'code' => '1',
'msg' => '저장은 완료되었으나 네이버 슬롯 동기화에 실패했습니다. 로그를 확인하세요.',
'syncData' => $syncSlotData,
'hint' => '로그 위치: writable/logs/ 에서 ERROR 확인'
]);
}
log_message('info', '[Processible::saveArea] Naver API 슬롯 동기화 성공 | Response: ' . json_encode($apiResponse, JSON_UNESCAPED_UNICODE));
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
'msg' => 'success',
'syncData' => $syncSlotData,
'apiResponse' => $apiResponse
]);
} else {
log_message('info', '[Processible::saveArea] 저장가능한 데이터가 없습니다.');
return $this->response->setJSON([
'code' => '9',
'msg' => '저장가능한 데이터가 없습니다.'
]);
}
} catch (\Exception $e) {
log_message('error', '[Processible::saveArea] 예외: ' . $e->getMessage());
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 기본 수량 저장
public function saveCount()
{
try {
@@ -152,18 +178,24 @@ class Processible extends BaseController
$rows = $this->request->getPost('rows');
$rows = json_decode($rows, true);
// dd($rows);
// exit;
if (count($rows) > 0) {
$results = [];
$hasError = false;
foreach ($rows as $row):
$this->model->saveCount($row);
$result = $this->model->saveCount($row);
$results[] = $result;
if (!$result['success']) {
$hasError = true;
}
endforeach;
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
'code' => $hasError ? '9' : '0',
'msg' => $hasError ? '일부 저장 실패' : 'success',
'debug' => $results // 디버깅 정보 포함
]);
} else {

View File

@@ -23,6 +23,8 @@ class Receipt extends BaseController
public function lists(): string
{
error_log('========== Receipt::lists() CALLED ==========');
$usr_id = $this->request->getGet('usr_id') ?: '';
$sBonbu = $this->request->getGet('bonbu') ?: '';
$sTeanm = $this->request->getGet('dept_sq') ?: '';
@@ -54,6 +56,8 @@ class Receipt extends BaseController
public function getResultList()
{
error_log('========== Receipt::getResultList() CALLED ==========');
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
@@ -92,9 +96,13 @@ class Receipt extends BaseController
'srchTxt' => $this->request->getGet('srchTxt'), // 검색어
];
error_log('[Receipt::getResultList] START - start=' . $start . ' length=' . $end);
$totalCount = $this->model->getTotalCount($data);
error_log('[Receipt::getResultList] TotalCount = ' . $totalCount);
$datas = $this->model->getResultList($start, $end, $data);
error_log('[Receipt::getResultList] END - returned ' . count($datas) . ' rows');
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
@@ -717,6 +725,26 @@ class Receipt extends BaseController
$rsrv_sq = $this->request->getPost('rsrv_sq');
$rcpt_sq = $this->request->getPost('rcpt_sq');
$img_type = $this->request->getPost('img_type');
$img_sub_type = $this->request->getPost('img_sub_type');
$file_order = $this->request->getPost('file_order');
log_message('info', '[Receipt::uploadFile] Request received - rcpt_key:{rcpt_key}, rsrv_sq:{rsrv_sq}, rcpt_sq:{rcpt_sq}, img_type:{img_type}, img_sub_type:{img_sub_type}, file_order:{file_order}', [
'rcpt_key' => $rcpt_key,
'rsrv_sq' => $rsrv_sq,
'rcpt_sq' => $rcpt_sq,
'img_type' => $img_type,
'img_sub_type' => $img_sub_type,
'file_order' => $file_order,
]);
// 필수 파라미터 검증
if (empty($rsrv_sq)) {
log_message('error', '[Receipt::uploadFile] rsrv_sq is empty');
return $this->response->setJSON([
'code' => '9',
'msg' => 'rsrv_sq(예약일련번호)가 필요합니다.'
]);
}
$files = $this->request->getFiles();
$uploadPath = "/upload/result/" . $rsrv_sq . "/";
@@ -738,7 +766,7 @@ class Receipt extends BaseController
// 워터마크 이미지 조회
$watermark_info = [];
if (!empty($receipt) && ($receipt['comp_sq'] ?? '') == '2') {
if (!empty($receipt) && !empty($receipt['rcpt_cpid'])) {
$watermark_info = $this->model->getWatermarkList($receipt['rcpt_cpid']);
}
@@ -758,15 +786,20 @@ class Receipt extends BaseController
if ($uploadData !== false) {
$arrUploadfile[] = $uploadData;
log_message('info', '[Receipt::uploadFile] upload success name={name} stored={stored}', [
log_message('info', '[Receipt::uploadFile] upload success name={name} stored={stored} cloud_url={url}', [
'name' => $file->getName(),
'stored' => $uploadData['file_name'] ?? '(unknown)',
'url' => $uploadData['object_storage_url'] ?? '(none)',
]);
} else {
log_message('error', '[Receipt::uploadFile] do_upload2 failed name={name} error={error}:{errorString}', [
log_message('error', '[Receipt::uploadFile] Cloud upload failed name={name}', [
'name' => $file->getName(),
'error' => $file->getError(),
'errorString' => $file->getErrorString(),
]);
// 클라우드 업로드 실패 시 즉시 에러 반환
return $this->response->setJSON([
'code' => '9',
'msg' => '클라우드 스토리지 업로드 실패: ' . $file->getName() . '\n네트워크 연결 또는 권한을 확인해주세요.'
]);
}
@@ -786,26 +819,80 @@ class Receipt extends BaseController
$dir = rtrim(dirname($uploadFile['object_key']), '/'); // upload/result/*
$thumbKey = $dir . '/' . $base . '_thumb.jpg';
try {
// 원본 이미지 다운로드 (클라우드에서)
$imageDataBlob = file_get_contents($object_storage_url);
if (!$imageDataBlob) {
throw new \Exception('Failed to download original image from cloud storage');
}
if (class_exists('\Imagick')) {
// Imagick 사용
$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();
// 썸네일 클라우드 업로드
$thumbUploaded = $lib->upload_object_storage_imagick2($thumbKey, $thumb_im);
if (!$thumbUploaded) {
log_message('warning', '[Receipt::uploadFile] Thumbnail cloud upload failed: {key}', ['key' => $thumbKey]);
}
} elseif (extension_loaded('gd')) {
// GD 라이브러리 사용
$source = imagecreatefromstring($imageDataBlob);
if ($source !== false) {
$imgWidth = imagesx($source);
$imgHeight = imagesy($source);
// 썸네일 크기 계산 (105x80 비율 유지)
$thumb_width = 105;
$thumb_height = 80;
// 썸네일 이미지 생성
$thumb = imagecreatetruecolor($thumb_width, $thumb_height);
imagecopyresampled($thumb, $source, 0, 0, 0, 0, $thumb_width, $thumb_height, $imgWidth, $imgHeight);
// JPEG로 변환
ob_start();
imagejpeg($thumb, null, 85);
$thumb_im = ob_get_clean();
// 메모리 해제
imagedestroy($source);
imagedestroy($thumb);
// 썸네일 클라우드 업로드
$thumbUploaded = $lib->upload_object_storage_imagick2($thumbKey, $thumb_im);
if (!$thumbUploaded) {
log_message('warning', '[Receipt::uploadFile] Thumbnail cloud upload failed: {key}', ['key' => $thumbKey]);
}
log_message('info', '[Receipt::uploadFile] Thumbnail created with GD: {key}', ['key' => $thumbKey]);
} else {
log_message('warning', '[Receipt::uploadFile] GD failed to create image from string');
}
} else {
log_message('warning', '[Receipt::uploadFile] No image library available (Imagick or GD), skipping thumbnail generation');
}
} catch (\Exception $e) {
log_message('error', '[Receipt::uploadFile] Thumbnail generation failed: {message}', [
'message' => $e->getMessage(),
]);
}
}
// 워터마크 삽입
$watermark_imgs = ['I3', 'I4'];
if (in_array($img_type, $watermark_imgs)) {
if (!empty($watermark_info)) {
if (in_array($img_type, $watermark_imgs) && !empty($watermark_info)) {
$common->watermarking($object_storage_url, $watermark_info, '', $receipt['rcpt_cpid'], $uploadFile['object_key']);
}
}
// 촬영정보 가져오기
$arrExifData = @exif_read_data($object_storage_url);
@@ -880,19 +967,34 @@ class Receipt extends BaseController
'meta_data' => $metaData, // 이미지메타데이터
'receipt' => $receipt,
'img_type' => $img_type,
'cloud_upload_yn' => 'Y', // 클라우드 업로드 성공 (여기까지 왔으면 성공)
];
$this->model->saveImg($uploadParam);
$img_sq = $this->model->saveImg($uploadParam);
}
}
// 성공 응답 - JavaScript에서 사용할 이미지 정보 포함
$lastUploadedFile = end($arrUploadfile);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
'msg' => 'success',
'img_sq' => $img_sq ?? null,
'img_path' => $uploadPath,
'img_filenm' => $lastUploadedFile['file_name'] ?? '',
'cloud_upload_yn' => 'Y',
'img_location' => ''
]);
} catch (\Exception $e) {
log_message('error', '[Receipt::uploadFile] Exception occurred: {message} at {file}:{line}', [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
'trace' => $e->getTraceAsString(),
]);
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
@@ -988,6 +1090,69 @@ class Receipt extends BaseController
}
}
// 업로드파일 목록 조회 (AJAX용)
public function getImages()
{
try {
$rsrv_sq = $this->request->getGet('rsrv_sq') ?? $this->request->getPost('rsrv_sq');
$img_type = $this->request->getGet('img_type') ?? $this->request->getPost('img_type');
if (empty($rsrv_sq)) {
return $this->response->setJSON([
'success' => false,
'msg' => 'rsrv_sq가 필요합니다.'
]);
}
// 전체 이미지 리스트 조회
$images = $this->model->getImageList2($rsrv_sq);
// img_type이 지정된 경우 필터링
if (!empty($img_type)) {
$images = array_filter($images, function($img) use ($img_type) {
return $img['img_type'] === $img_type;
});
$images = array_values($images); // 인덱스 재정렬
}
// 이미지 URL 생성
foreach ($images as &$img) {
$temp = explode(".", $img['img_filenm']);
$thumbName = $temp[0] . "_thumb.jpg";
$localOriginalPath = $img['img_path'] . $img['img_filenm'];
$localThumbPath = $img['img_path'] . $thumbName;
// 모든 파일은 클라우드에 저장됨
if (($img['cloud_upload_yn'] ?? 'Y') === 'Y') {
$img['original_url'] = NCLOUD_OBJECT_STORAGE_URL . $localOriginalPath;
$img['thumbnail_url'] = NCLOUD_OBJECT_STORAGE_URL . $localThumbPath;
} else {
// 혹시 모를 레거시 로컬 파일 (로컬 파일 시스템 체크)
$localThumbFullPath = FCPATH . $localThumbPath;
if (file_exists($localThumbFullPath)) {
$img['thumbnail_url'] = $localThumbPath;
} else {
$img['thumbnail_url'] = $localOriginalPath;
}
$img['original_url'] = $localOriginalPath;
}
}
return $this->response->setJSON([
'success' => true,
'images' => $images
]);
} catch (\Exception $e) {
log_message('error', '[Receipt::getImages] Error: ' . $e->getMessage());
return $this->response->setJSON([
'success' => false,
'msg' => $e->getMessage()
]);
}
}
// 업로드파일 삭제
public function removeUploadFile()
{
@@ -1016,17 +1181,76 @@ class Receipt extends BaseController
$lib->deleteFile($thumbPath);
}
$this->model->removeUploadFile($rcpt_sq, $img_sq);
$result = $this->model->removeUploadFile($rcpt_sq, $img_sq);
if (!$result['success']) {
return $this->response->setJSON([
'code' => '1',
'msg' => $result['msg'] ?? '삭제 실패'
]);
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
log_message('error', 'removeUploadFile error: ' . $e->getMessage());
return $this->response->setJSON([
'code' => '1',
'msg' => '삭제 중 에러가 발생했습니다: ' . $e->getMessage()
]);
}
}
// 이미지 순서 업데이트
public function updateImageOrder()
{
try {
$rcpt_sq = $this->request->getPost('rcpt_sq');
$img_type = $this->request->getPost('img_type');
$orders = $this->request->getPost('orders');
log_message('info', '[updateImageOrder] 요청 데이터 - rcpt_sq: ' . $rcpt_sq . ', img_type: ' . $img_type . ', orders: ' . $orders);
if (!$rcpt_sq || !$img_type || !$orders) {
log_message('error', '[updateImageOrder] 필수 파라미터 누락');
return $this->response->setJSON([
'code' => '1',
'msg' => '필수 파라미터가 누락되었습니다.'
]);
}
// JSON 파싱
$orderData = json_decode($orders, true);
if (!is_array($orderData)) {
return $this->response->setJSON([
'code' => '1',
'msg' => '순서 데이터 형식이 올바르지 않습니다.'
]);
}
// 순서 업데이트
$result = $this->model->updateImageOrder($rcpt_sq, $img_type, $orderData);
if (!$result['success']) {
return $this->response->setJSON([
'code' => '1',
'msg' => $result['msg'] ?? '순서 업데이트 실패'
]);
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
'success' => true,
'msg' => '순서가 저장되었습니다.'
]);
} catch (\Exception $e) {
log_message('error', 'updateImageOrder error: ' . $e->getMessage());
return $this->response->setJSON([
'code' => '1',
'msg' => '순서 업데이트 중 에러가 발생했습니다: ' . $e->getMessage()
]);
}
}

View File

@@ -0,0 +1,221 @@
<?php
namespace App\Controllers\Manage;
use App\Controllers\BaseController;
class WorkerLog extends BaseController
{
/**
* Worker 로그 통합 뷰어
*/
public function index()
{
$this->data['title'] = 'Worker 로그 통합 관리';
// 로그 디렉토리 목록
$logDirs = [
'api_receiver' => ROOTPATH . 'worker/logs',
'naver_worker' => WRITEPATH . 'logs/worker'
];
// 날짜 필터 (기본값: 오늘)
$date = $this->request->getGet('date') ?? date('Y-m-d');
$logType = $this->request->getGet('type') ?? 'all';
$logs = [];
// API Receiver 로그 읽기
if ($logType === 'all' || $logType === 'api_receiver') {
$apiLogFile = $logDirs['api_receiver'] . '/' . $date . '.log';
if (file_exists($apiLogFile)) {
$logs['api_receiver'] = $this->parseLogFile($apiLogFile);
}
}
// Naver Worker 로그 읽기
if ($logType === 'all' || $logType === 'naver_worker') {
$workerLogFile = $logDirs['naver_worker'] . '/' . $date . '.log';
if (file_exists($workerLogFile)) {
$logs['naver_worker'] = $this->parseLogFile($workerLogFile);
}
// Failed 로그도 읽기
$failedLogFile = $logDirs['naver_worker'] . '/' . $date . '_failed.log';
if (file_exists($failedLogFile)) {
$logs['naver_worker_failed'] = $this->parseLogFile($failedLogFile);
}
}
// 모든 로그를 시간순으로 통합 정렬
$allLogs = [];
foreach ($logs as $type => $entries) {
foreach ($entries as $entry) {
$entry['source'] = $type;
$allLogs[] = $entry;
}
}
// 시간 역순 정렬 (최신순)
usort($allLogs, function($a, $b) {
return strtotime($b['timestamp']) - strtotime($a['timestamp']);
});
$this->data['logs'] = $allLogs;
$this->data['date'] = $date;
$this->data['logType'] = $logType;
$this->data['logDirs'] = $logDirs;
// 사용 가능한 날짜 목록 (최근 30일)
$this->data['availableDates'] = $this->getAvailableLogDates($logDirs);
return view('pages/manage/worker_log', $this->data);
}
/**
* 로그 파일 파싱
*/
private function parseLogFile($filePath)
{
$logs = [];
$lines = file($filePath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
foreach ($lines as $line) {
// 로그 포맷: [2025-12-22 10:30:45] [INFO] [NaverWorker::run:95] 메시지
if (preg_match('/\[(.+?)\]\s*\[(.+?)\]\s*(?:\[(.+?)\]\s*)?(.+)/', $line, $matches)) {
$logs[] = [
'timestamp' => $matches[1],
'level' => $matches[2],
'location' => $matches[3] ?? '',
'message' => $matches[4]
];
} else {
// 파싱 실패한 경우 원본 그대로
$logs[] = [
'timestamp' => date('Y-m-d H:i:s'),
'level' => 'UNKNOWN',
'location' => '',
'message' => $line
];
}
}
return $logs;
}
/**
* 로그 파일이 존재하는 날짜 목록 가져오기
*/
private function getAvailableLogDates($logDirs)
{
$dates = [];
foreach ($logDirs as $dir) {
if (!is_dir($dir)) continue;
$files = scandir($dir);
foreach ($files as $file) {
if (preg_match('/(\d{4}-\d{2}-\d{2})(?:_failed)?\.log$/', $file, $matches)) {
$dates[$matches[1]] = true;
}
}
}
$dates = array_keys($dates);
rsort($dates); // 최신순 정렬
return array_slice($dates, 0, 30); // 최근 30일만
}
/**
* 실시간 로그 스트리밍 (Ajax)
*/
public function stream()
{
$type = $this->request->getGet('type') ?? 'naver_worker';
$lastId = (int) ($this->request->getGet('lastId') ?? 0);
$logDirs = [
'api_receiver' => ROOTPATH . 'worker/logs',
'naver_worker' => WRITEPATH . 'logs/worker'
];
$logFile = $logDirs[$type] . '/' . date('Y-m-d') . '.log';
$newLogs = [];
if (file_exists($logFile)) {
$lines = file($logFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// lastId 이후의 로그만 반환
if ($lastId < count($lines)) {
$newLines = array_slice($lines, $lastId);
foreach ($newLines as $line) {
if (preg_match('/\[(.+?)\]\s*\[(.+?)\]\s*(?:\[(.+?)\]\s*)?(.+)/', $line, $matches)) {
$newLogs[] = [
'timestamp' => $matches[1],
'level' => $matches[2],
'location' => $matches[3] ?? '',
'message' => $matches[4]
];
}
}
}
}
return $this->response->setJSON([
'success' => true,
'logs' => $newLogs,
'lastId' => $lastId + count($newLogs)
]);
}
/**
* 로그 파일 다운로드
*/
public function download()
{
$date = $this->request->getGet('date') ?? date('Y-m-d');
$type = $this->request->getGet('type') ?? 'naver_worker';
$logDirs = [
'api_receiver' => ROOTPATH . 'worker/logs',
'naver_worker' => WRITEPATH . 'logs/worker'
];
$logFile = $logDirs[$type] . '/' . $date . '.log';
if (!file_exists($logFile)) {
return $this->response->setStatusCode(404)->setBody('로그 파일을 찾을 수 없습니다.');
}
return $this->response->download($logFile, null);
}
/**
* 로그 파일 삭제
*/
public function delete()
{
$date = $this->request->getPost('date');
$type = $this->request->getPost('type');
if (!$date || !$type) {
return $this->response->setJSON(['success' => false, 'message' => '필수 파라미터 누락']);
}
$logDirs = [
'api_receiver' => ROOTPATH . 'worker/logs',
'naver_worker' => WRITEPATH . 'logs/worker'
];
$logFile = $logDirs[$type] . '/' . $date . '.log';
if (file_exists($logFile)) {
unlink($logFile);
return $this->response->setJSON(['success' => true, 'message' => '로그 파일이 삭제되었습니다.']);
}
return $this->response->setJSON(['success' => false, 'message' => '로그 파일을 찾을 수 없습니다.']);
}
}

View File

@@ -49,7 +49,6 @@ class Common
$wmTextAlpha = 0.5; // 워터마크 텍스트 투명도
try {
$img = new \Imagick();
if (is_string($imagePath) && is_file($imagePath)) {
$img->readImage($imagePath);
@@ -96,19 +95,23 @@ class Common
}
}
if (empty($wmImagePath))
if (empty($wmImagePath)) {
return;
}
// 워터마크 이미지 경로 처리
if (substr($wmImagePath, 0, 1) == '/') {
$wmImagePath = substr($wmImagePath, 1);
}
// ROOTPATH와 결합하여 절대 경로 생성 (img 폴더는 프로젝트 루트에 있음)
$fullWmPath = ROOTPATH . $wmImagePath;
// echo FCPATH.$wmImagePath;
if (!is_file($fullWmPath)) {
return;
}
$wm = new \Imagick($wmImagePath);
$wm = new \Imagick($fullWmPath);
$hWm = $wm->getImageHeight();
$wWm = $wm->getImageWidth();
@@ -119,12 +122,16 @@ class Common
$img->compositeImage($wm, \Imagick::COMPOSITE_OVER, $wmImgLeft, $wmImgTop);
$wm->destroy();
// 워터마크 텍스트가 있는 경우에만 텍스트 그리기
if (!empty($wmText)) {
$draw = new \ImagickDraw();
$basePath = defined('BASEPATH') ? BASEPATH : (defined('ROOTPATH') ? ROOTPATH . 'system/' : '');
$wmFont = $basePath . 'fonts/' . $wmFont;
if (is_file($wmFont)) {
$draw->setFont($wmFont);
// 폰트 경로: img/watermark/fonts/
if (!empty($wmFont)) {
$fontPath = ROOTPATH . 'img/watermark/fonts/' . $wmFont;
if (is_file($fontPath)) {
$draw->setFont($fontPath);
}
}
$draw->setFontSize($wmFontSize);
@@ -141,6 +148,7 @@ class Common
$img->drawImage($draw);
$draw->destroy();
}
// $img->writeImage();
@@ -149,14 +157,9 @@ class Common
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 {
if (!$ok) {
log_message('error', '[watermarking] upload failed key={key} cpid={cpid}', [
'key' => $key,
'cpid' => $cpid,
@@ -166,7 +169,11 @@ class Common
// $object_upload = $this->upload->upload_object_storage($imagePath , $imagePath , 'data');
} catch (\Throwable $e) {
log_message('error', '[watermarking] ' . $e->getMessage());
log_message('error', '[watermarking] Exception: {message} at {file}:{line}', [
'message' => $e->getMessage(),
'file' => $e->getFile(),
'line' => $e->getLine(),
]);
}
}

View File

@@ -54,7 +54,7 @@ class MyUpload
}
/**
* 파일 업로드 요청
* 파일 업로드 요청 (Object Storage 전용)
* 추가일 2025.12.24
* 작성자 - yangsh
*/
@@ -73,39 +73,40 @@ class MyUpload
$newName = $file->getRandomName();
// ✅ PHP 임시 업로드 파일 경로 (writable로 move() 필요 없음)
// ✅ PHP 임시 업로드 파일 경로
$tmpFile = $file->getTempName();
if (!is_file($tmpFile)) {
$this->set_error('upload_temp_file_missing');
log_message('error', 'do_upload2 temp file missing: ' . $tmpFile);
log_message('error', '[MyUpload] Temp file missing: ' . $tmpFile);
return false;
}
// ✅ 클라우드에 올라갈 "Key"를 직접 만든다 (로컬 경로 절대 넣지 말기)
// 예시: upload/tmp/랜덤파일명 또는 upload/apt_file/{rcpt_no}/...
// ✅ 클라우드에 올라갈 "Key"
$objectKey = $filePath . $newName;
// 클라우드 업로드 (필수)
$up = $this->upload_object_storage($objectKey, $tmpFile, 'file');
if ($up === false) {
$this->set_error('upload_destination_cloud_error');
$this->set_error('cloud_upload_failed');
log_message('error', '[MyUpload] Cloud upload failed: ' . $objectKey);
@unlink($tmpFile);
return false;
}
// (선택) tmp 파일 삭제
// 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
'file_name' => basename($objectKey),
'base_name' => pathinfo($objectKey, PATHINFO_FILENAME),
'ext' => pathinfo($objectKey, PATHINFO_EXTENSION),
];
log_message('debug', 's3_data=' . json_encode($this->s3_data ?? null, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));
log_message('info', '[MyUpload] Cloud upload success: ' . $objectKey);
return $this->s3_data;
}
@@ -386,6 +387,7 @@ class MyUpload
'Key' => ltrim($object_storage_upload_path, '/'),
'Body' => $blobData,
'ACL' => 'public-read',
'ContentType' => 'image/jpeg',
]);

View File

@@ -48,6 +48,7 @@ class NaverApiClient
return $this->request('PUT', $url, $updateData);
}
/**
* [POST] 4.매물검증 결과관리
* API:POST /kiso/center/verification-article/{매물번호}/report?charger={담당자명}
@@ -434,16 +435,42 @@ class NaverApiClient
return $this->request('POST', $url, $postData);
}
/**
* 현장확인 슬롯 동기화
* API (가) - /kiso/center/site-slot
* 신규/변경 일자별 데이터 전송
* @syncData array
* @param string $baseDate 기준일자(ISO 8601 형식: YYYY-MM-DD 예: 2024-01-31)
* @param string $legalDivisionNumber 구역번호 "1111000000"
* @param object slots 오전/오후/ 슬롯 정보
[
{
"baseDate": "2025-04-30",
"legalDivisionNumber": "1111000000",
"slots": {
"am": { "max": 10, "reserved": 0 },
"pm": { "max": 100, "reserved": 0 }
}
}
]
*/
public function syncSiteSlot($syncData){
$url = $this->baseUrl . "/kiso/center/site-verification/slots";
return $this->request('POST', $url, $syncData);
}
/**
* CURL 공통 실행 함수
*/
private function request(string $method, string $url, ?array $data = null): ?array
{
/**
* curl --location 'https://test-b2b.land.naver.com/kiso/center/verification-article/2500000001?charger=admin' \
--header 'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9' \
*/
// 요청 데이터 로깅
if ($data) {
log_message('info', "[Naver API $method REQUEST] URL: $url | Data: " . json_encode($data, JSON_UNESCAPED_UNICODE));
} else {
log_message('info', "[Naver API $method REQUEST] URL: $url");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
@@ -491,11 +518,19 @@ class NaverApiClient
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$curlError = curl_error($ch);
$curlErrno = curl_errno($ch);
curl_close($ch);
// CURL 오류 체크
if ($curlErrno !== 0) {
log_message('error', "[Naver API $method CURL ERROR] URL: $url | Error ($curlErrno): $curlError");
return null;
}
// 결과 로그 기록 (성공/실패 모두 기록하여 추적 가능하게 함)
if ($httpCode === 200 || $httpCode === 202) {
log_message('info', "[Naver API $method SUCCESS] URL: $url | Response: $response");
log_message('info', "[Naver API $method SUCCESS] URL: $url | Code: $httpCode | Response: $response");
} else {
log_message('error', "[Naver API $method FAIL] URL: $url | Code: $httpCode | Response: $response");
return null;

View File

@@ -0,0 +1,154 @@
<?php
namespace App\Models\Entities;
use CodeIgniter\Model;
class WatermarkModel extends Model
{
protected $table = 'watermark';
protected $primaryKey = ['cpid', 'wm_type']; // 복합키
protected $useAutoIncrement = false;
protected $returnType = 'array';
protected $useSoftDeletes = false;
protected $allowedFields = [
'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'
];
protected $useTimestamps = false;
protected $validationRules = [
'cpid' => 'required|max_length[20]',
'wm_type' => 'required|integer',
'wm_img_path' => 'required|max_length[300]',
'wm_img_height' => 'required|integer',
'wm_img_width' => 'required|integer',
'wm_position' => 'required|max_length[2]',
'wm_img_opacity' => 'required|integer',
'wm_space' => 'required|integer',
'img_width_min' => 'required|integer',
'img_width_max' => 'required|integer'
];
protected $validationMessages = [];
protected $skipValidation = false;
/**
* 워터마크 정보 조회 (복합키)
*
* @param string $cpid
* @param int $wm_type
* @return array|null
*/
public function getWatermark($cpid, $wm_type)
{
return $this->where('cpid', $cpid)
->where('wm_type', $wm_type)
->first();
}
/**
* cpid로 워터마크 목록 조회
*
* @param string $cpid
* @return array
*/
public function getWatermarksByCpid($cpid)
{
return $this->where('cpid', $cpid)->findAll();
}
/**
* 워터마크 타입별 조회
*
* @param int $wm_type
* @return array
*/
public function getWatermarksByType($wm_type)
{
return $this->where('wm_type', $wm_type)->findAll();
}
/**
* 워터마크 정보 저장/업데이트
*
* @param array $data
* @return bool
*/
public function saveWatermark($data)
{
if (!isset($data['cpid']) || !isset($data['wm_type'])) {
return false;
}
// 복합키로 기존 데이터 확인
$existing = $this->getWatermark($data['cpid'], $data['wm_type']);
if ($existing) {
// 업데이트
return $this->where('cpid', $data['cpid'])
->where('wm_type', $data['wm_type'])
->set($data)
->update();
} else {
// 삽입
return $this->insert($data);
}
}
/**
* 워터마크 삭제 (복합키)
*
* @param string $cpid
* @param int $wm_type
* @return bool
*/
public function deleteWatermark($cpid, $wm_type)
{
return $this->where('cpid', $cpid)
->where('wm_type', $wm_type)
->delete();
}
/**
* cpid로 모든 워터마크 삭제
*
* @param string $cpid
* @return bool
*/
public function deleteAllByCpid($cpid)
{
return $this->where('cpid', $cpid)->delete();
}
/**
* 이미지 크기 범위로 워터마크 조회
*
* @param string $cpid
* @param int $img_width
* @return array|null
*/
public function getWatermarkByImageSize($cpid, $img_width)
{
return $this->where('cpid', $cpid)
->where('img_width_min <=', $img_width)
->where('img_width_max >=', $img_width)
->findAll();
}
}

View File

@@ -249,7 +249,7 @@ class ProcessibleModel extends Model
public function saveCount($data)
{
$this->db->transStart();
// $this->db->transStart();
$usr_sq = session('usr_sq');
@@ -257,7 +257,12 @@ class ProcessibleModel extends Model
(sc_date, region_cd, am_cnt, pm_cnt, day_cnt, insert_usr, insert_tm, update_usr, update_tm)
VALUES
(?, ?, ?, ?, ?, ?, NOW(), ?, NOW())
ON DUPLICATE KEY UPDATE am_cnt=values(am_cnt), pm_cnt=values(pm_cnt), day_cnt=values(day_cnt), update_usr=values(update_usr)
ON DUPLICATE KEY UPDATE
am_cnt = VALUES(am_cnt),
pm_cnt = VALUES(pm_cnt),
day_cnt = VALUES(day_cnt),
update_usr = VALUES(update_usr),
update_tm = NOW()
";
$datas = [
@@ -270,17 +275,49 @@ class ProcessibleModel extends Model
$usr_sq
];
if ($this->db->query($sql, $datas) === false) {
// 쿼리 실행
$result = $this->db->query($sql, $datas);
// 실행된 쿼리 로그 출력
$lastQuery = $this->db->getLastQuery();
log_message('info', '[ProcessibleModel::saveCount] Query: ' . $lastQuery);
log_message('info', '[ProcessibleModel::saveCount] Affected Rows: ' . $this->db->affectedRows());
if ($result === false) {
$error = $this->db->error();
log_message('error', '[ProcessibleModel::saveCount] Error: ' . json_encode($error));
return [
'success' => false,
'msg' => '저장실패',
'msg' => '저장실패: ' . ($error['message'] ?? '알 수 없는 오류'),
'query' => (string) $lastQuery,
'error' => $error
];
}
$this->db->transComplete();
// $this->db->transComplete();
return [
'success' => true,
'query' => (string) $lastQuery,
'affected_rows' => $this->db->affectedRows()
];
}
/**
* 슬롯 동기화
*
*/
public function getSyncSlotData($baseDate, $region_cd)
{
$sql = "SELECT sc_date, region_cd, am_cnt, pm_cnt, day_cnt FROM service_count WHERE sc_date = ? AND region_cd IN ?";
$datas = [
$baseDate,
$region_cd
];
$query = $this->db->query($sql, $datas);
return $query->getResultArray();
}
}

View File

@@ -409,10 +409,9 @@ class ReceiptModel extends Model
}
// log_message('debug', '[getTotalCount] SQL = ' . $builder->getCompiledSelect());
$row = $builder->get()->getRowArray();
error_log('[getTotalCount] SQL = ' . $this->db->getLastQuery());
return (int) ($row['cnt'] ?? 0);
}
@@ -538,10 +537,10 @@ class ReceiptModel extends Model
$builder->join('result b', 'b.rcpt_sq = a.rcpt_sq', 'inner');
$builder->join('region_codes c', 'a.rcpt_dong = c.region_cd', 'inner');
$builder->join('departments d', 'b.dept_sq = d.dept_sq', 'left');
$builder->join('users u', 'b.usr_sq = u.usr_sq', 'left');
$builder->join('result_imgs e', "e.rsrv_sq = b.rsrv_sq AND e.img_type = 'I1' AND e.use_yn = 'Y'", 'left');
$builder->join('receipt_transimage_log l', 'a.rcpt_key = l.rcpt_key', 'left');
$builder->join('departments d', 'b.dept_sq = d.dept_sq', 'left outer');
$builder->join('users u', 'b.usr_sq = u.usr_sq', 'left outer');
$builder->join('result_imgs e', "e.rsrv_sq = b.rsrv_sq AND e.img_type = 'I1' AND e.use_yn = 'Y'", 'left outer');
$builder->join('receipt_transimage_log l', 'a.rcpt_key = l.rcpt_key', 'left outer');
$login_dept_info = $this->getDeptDetail($dept_sq); // 로그인 사용자 소속부서정보
@@ -573,8 +572,8 @@ class ReceiptModel extends Model
$builder->where('a.rcpt_tm >=', $data['sdate'] . ' 00:00:00');
$builder->where('a.rcpt_tm <=', $data['edate'] . ' 23:59:59');
} else {
$builder->where('b.rsrv_date >=', $data['sdate'] . ' 00:00:00');
$builder->where('b.rsrv_date <=', $data['edate'] . ' 23:59:59');
$builder->where('b.rsrv_date >=', $data['sdate'] );
$builder->where('b.rsrv_date <=', $data['edate'] );
}
// 지역
@@ -753,9 +752,12 @@ class ReceiptModel extends Model
$builder->limit($end, $start);
// log_message('debug', '[getResultList] SQL = ' . $builder->getCompiledSelect());
$result = $builder->get()->getResultArray();
return $builder->get()->getResultArray();
error_log('[getResultList] SQL = ' . $this->db->getLastQuery());
error_log('[getResultList] Result count = ' . count($result));
return $result;
}
@@ -1837,7 +1839,8 @@ class ReceiptModel extends Model
$receipt = $param['receipt'];
$cloud_upload_yn = 'Y';
// 실제 클라우드 업로드 성공 여부를 파라미터에서 받아옴 (기본값 'Y')
$cloud_upload_yn = $param['cloud_upload_yn'] ?? 'Y';
if ($param['img_type'] == 'I6' || $param['img_type'] == 'I7') {
$yn_sql = "update receipt " .
@@ -2011,7 +2014,15 @@ class ReceiptModel extends Model
// 이미지정보 조회
$row = $this->getUploadFileInfo($img_sq);
if (!empty($row)) {
if (empty($row)) {
$this->db->transComplete();
// 파일이 이미 삭제된 경우 성공으로 처리 (중복 삭제 요청 방지)
log_message('info', "[removeUploadFile] 파일 정보 없음 (이미 삭제됨): img_sq={$img_sq}");
return [
'success' => true,
'msg' => '이미 삭제된 파일입니다',
];
}
if ($row['img_type'] == 'I6' || $row['img_type'] == 'I7') {
$yn_sql = "update receipt " .
@@ -2027,7 +2038,7 @@ class ReceiptModel extends Model
" AND use_yn = 'Y'" .
" AND img_type = 'I8') WHEN 0 THEN 'N' ELSE 'Y' END" .
" WHERE rcpt_sq = ? ";
$yn_data = [$rcpt_sq];
$yn_data = [$img_sq, $rcpt_sq];
$this->db->query($yn_sql, $yn_data);
} else if ($row['img_type'] == 'I9') {
$yn_sql = "UPDATE receipt" .
@@ -2041,7 +2052,7 @@ class ReceiptModel extends Model
" END" .
" )" .
" WHERE rcpt_sq = ?";
$yn_data = [$rcpt_sq];
$yn_data = [$img_sq, $rcpt_sq];
$this->db->query($yn_sql, $yn_data);
} else if ($row['img_type'] == 'I11') {
$yn_sql = "update receipt " .
@@ -2049,28 +2060,19 @@ class ReceiptModel extends Model
" 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' => '삭제실패',
];
}
$deleteResult = $this->db->query($sql, $data);
if (in_array($row['img_type'], ['I1', 'I2', 'I8', 'I10', 'I11'])) {
$remark = "";
@@ -2096,18 +2098,77 @@ class ReceiptModel extends Model
$sql = "SELECT rcpt_stat FROM receipt WHERE rcpt_sq = ?";
$data = [$rcpt_sq];
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
$rowStat = $query->getRowArray();
$this->saveChangedHistory($rcpt_sq, $row['rcpt_stat'], 'C31', $usr_id, $remark);
$this->saveChangedHistory($rcpt_sq, $rowStat['rcpt_stat'], 'C31', $usr_id, $remark);
}
$this->db->transComplete();
if ($deleteResult === false || $this->db->transStatus() === false) {
return [
'success' => false,
'msg' => '삭제실패',
];
}
return [
'success' => true,
];
}
// 이미지 순서 업데이트
public function updateImageOrder($rcpt_sq, $img_type, $orderData)
{
log_message('info', '[ReceiptModel::updateImageOrder] 시작 - rcpt_sq: ' . $rcpt_sq . ', img_type: ' . $img_type . ', 개수: ' . count($orderData));
$this->db->transStart();
try {
$updateCount = 0;
foreach ($orderData as $item) {
$img_sq = $item['img_sq'] ?? null;
$view_odr = $item['view_odr'] ?? null;
if (!$img_sq || !$view_odr) {
log_message('warning', '[ReceiptModel::updateImageOrder] 스킵 - img_sq 또는 view_odr 없음');
continue;
}
$sql = "UPDATE result_imgs SET view_odr = ? WHERE img_sq = ? AND img_type = ?";
$data = [$view_odr, $img_sq, $img_type];
log_message('debug', '[ReceiptModel::updateImageOrder] 업데이트 - img_sq: ' . $img_sq . ', view_odr: ' . $view_odr);
$result = $this->db->query($sql, $data);
if ($result) {
$updateCount++;
}
}
$this->db->transComplete();
if ($this->db->transStatus() === false) {
log_message('error', '[ReceiptModel::updateImageOrder] 트랜잭션 실패');
return [
'success' => false,
'msg' => '순서 업데이트 실패',
];
}
log_message('info', '[ReceiptModel::updateImageOrder] 완료 - 업데이트 수: ' . $updateCount);
return [
'success' => true,
];
} catch (\Exception $e) {
log_message('error', '[ReceiptModel::updateImageOrder] Exception: ' . $e->getMessage());
return [
'success' => false,
'msg' => '순서 업데이트 중 오류 발생: ' . $e->getMessage(),
];
}
}

View File

@@ -144,7 +144,7 @@ class M701Model extends Model
// 매물번호
if (!empty($data['atcl_no'])) {
$sql .= "AND a.atcl = '{$data['atcl_no']}' ";
$sql .= "AND a.atcl_no = '{$data['atcl_no']}' ";
} else {
// 현재상태
if (!empty($data['stat_cd'])) {
@@ -364,7 +364,7 @@ class M701Model extends Model
// 매물번호
if (!empty($data['atcl_no'])) {
$sql .= "AND a.atcl = '{$data['atcl_no']}' ";
$sql .= "AND a.atcl_no = '{$data['atcl_no']}' ";
} else {
// 현재상태
if (!empty($data['stat_cd'])) {
@@ -553,7 +553,7 @@ class M701Model extends Model
// 매물번호
if (!empty($data['atcl_no'])) {
$sql .= "AND a.atcl = '{$data['atcl_no']}' ";
$sql .= "AND a.atcl_no = '{$data['atcl_no']}' ";
} else {
// 현재상태
if (!empty($data['stat_cd'])) {

View File

@@ -13,7 +13,7 @@ use Exception;
* 네이버 부동산 매물 처리 서비스
*
* 네이버 API 응답을 받아서 타입별 처리 로직으로 위임하는 오케스트레이터 역할
* - Type S: 현장확인 (A01)
* - Type S, S_VR: 현장확인 (A01)
* - Type V2: 일반/서류/비공동 (D04, F01 등)
*/
class NaverService
@@ -68,7 +68,7 @@ class NaverService
CLI::write(CLI::color('🟢 임시테이블 저장 완료', 'green'));
// 3. 타입별 분기 처리
if ($vType === 'S') {
if ($vType === 'S' || $vType === 'S_VR') {
return $this->typeSHandler->handle($articleNumber, $rawData, $payload);
} else {
return $this->typeV2Handler->handle($articleNumber, $rawData, $payload);

View File

@@ -40,8 +40,8 @@ class TypeSParameterMapper extends BaseParameterMapper
'rcpt_product_info5' => $price['premiumAmount'] ?? '0',
'rcpt_living_yn' => ($rawData['site']['isRegistration'] ?? false) ? 'Y' : 'N',
'rcpt_agent' => $realtor['realtorName'] ?? null,
'rcpt_sido' => mb_substr($address['legalDivision']['cityNumber'] ?? '', 0, 5),
'rcpt_gugun' => mb_substr($address['legalDivision']['divisionNumber'] ?? '', 0, 10),
'rcpt_sido' => $address['legalDivision']['cityNumber'] ?? null,
'rcpt_gugun' => $address['legalDivision']['divisionNumber'] ?? null,
'rcpt_dong' => $address['legalDivision']['sectorNumber'] ?? null,
'rcpt_hscp_nm' => $address['complexName'] ?? null,
'rcpt_hscp_no' => $address['complexNumber'] ?? null,

View File

@@ -55,3 +55,5 @@
<link href="/architectui/assets/styles/vendors.98288b227c064e6a107f.css" rel="stylesheet">
<link href="/architectui/assets/styles/main.98288b227c064e6a107f.css" rel="stylesheet">
<link href="/architectui/assets/styles/custom.css" rel="stylesheet">
<link href="/common/css/custom.css" rel="stylesheet">

View File

@@ -3,6 +3,7 @@
<head>
<?= $this->include('layouts/header') ?>
<?= $this->renderSection('page_styles') ?>
</head>
<body>
@@ -148,6 +149,8 @@
});
</script>
<?= $this->renderSection('page_scripts') ?>
</body>
</html>

View File

@@ -87,7 +87,7 @@
<div class="d-flex gap-1 ms-auto">
<button class="btn btn-sm btn-outline-success" id="excel-download" type="button">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i> 엑셀다운로드
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i> 엑셀다운로드
</button>
<button class="btn btn-sm btn-outline-light" type="button" id="btnSearch">
조회
@@ -513,7 +513,7 @@
data: null, render: function (data, type, row, meta) {
var str = `
<div class="d-flex justify-content-center gap-1">
<input type="text" id="am_cnt2__${meta.row}" value="${row.am_cnt}"/ style="width: 80px;">
<input type="text" id="am_cnt2_${meta.row}" value="${row.am_cnt}"/ style="width: 80px;">
</div>
`;
@@ -706,8 +706,8 @@
datas.push(data);
});
}
// console.log(datas)
// console.log(path);
console.log(datas)
// return
if (datas.length == 0) {

File diff suppressed because it is too large Load Diff

View File

@@ -103,30 +103,35 @@ $usr_nm = session('usr_nm');
}
</style>
<h1>확인매물 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">확인매물 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<!-- 검색 폼 -->
<div class="row g-3">
<div class="col-md-1">
<label class="form-label mb-1">매물ID</label>
<input type="text" class="form-control" name="rcpt_atclno" id="rcpt_atclno"
<input type="text" class="form-control form-control-sm" name="rcpt_atclno" id="rcpt_atclno"
onkeypress="atcl_no_enter(event)">
</div>
<div class="col-md-4">
<label class="form-label mb-1">일자별조회</label>
<div class="input-group input-group-sm">
<select class="form-select" name="schDateGb">
<select class="form-select form-select-sm" name="schDateGb">
<option value="1" selected>예약일자</option>
<option value="2">등록일자</option>
</select>
<input type="date" class="form-control" name="sdate" id="sdate" placeholder="시작일">
<input type="date" class="form-control form-control-sm" name="sdate" id="sdate" placeholder="시작일">
<span class="input-group-text">~</span>
<input type="date" class="form-control" name="edate" id="edate" placeholder="종료일">
<input type="date" class="form-control form-control-sm" name="edate" id="edate" placeholder="종료일">
</div>
</div>
@@ -193,7 +198,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">거래구분</label>
<select class="form-select" name="rcpt_product_info1">
<select class="form-select form-select-sm" name="rcpt_product_info1">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "NHN_DEAL_TYPE"): ?>
@@ -205,7 +210,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">동영상촬영여부</label>
<select class="form-select" name="exp_movie_yn">
<select class="form-select form-select-sm" name="exp_movie_yn">
<option value="">전체</option>
<option value="Y">촬영</option>
<option value="N">미촬영</option>
@@ -214,7 +219,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">홍보확인서여부</label>
<select class="form-select" name="conf_img_yn">
<select class="form-select form-select-sm" name="conf_img_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
@@ -223,7 +228,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">분양권</label>
<select class="form-select" name="parcel_out_yn">
<select class="form-select form-select-sm" name="parcel_out_yn">
<option value="">전체</option>
<option value="Y"> Y</option>
<option value="N"> N</option>
@@ -232,7 +237,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">CP ID</label>
<select class="form-select" name="rcpt_cpid">
<select class="form-select form-select-sm" name="rcpt_cpid">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "CP_ID"): ?>
@@ -244,7 +249,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">매물종류</label>
<select class="form-select" name="rcpt_product">
<select class="form-select form-select-sm" name="rcpt_product">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "ARTICLE_TYPE"): ?>
@@ -256,7 +261,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">면적확인</label>
<select class="form-select" name="exp_spc_yn">
<select class="form-select form-select-sm" name="exp_spc_yn">
<option value="">전체</option>
<option value="Y"> Y</option>
<option value="N"> N</option>
@@ -265,7 +270,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">체크리스트</label>
<select class="form-select" name="check_list_img_yn">
<select class="form-select form-select-sm" name="check_list_img_yn">
<option value="">전체</option>
<option value="Y"> Y
</option>
@@ -276,7 +281,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">평면도유무</label>
<select class="form-select" name="ground_plan_yn">
<select class="form-select form-select-sm" name="ground_plan_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
@@ -285,7 +290,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">평면도요청</label>
<select class="form-select" name="ground_plan">
<select class="form-select form-select-sm" name="ground_plan">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
@@ -294,7 +299,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">직거래</label>
<select class="form-select" name="direct_trad_yn">
<select class="form-select form-select-sm" name="direct_trad_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
@@ -303,7 +308,7 @@ $usr_nm = session('usr_nm');
<div class="col-md-1">
<label class="form-label mb-1">360촬영여부</label>
<select class="form-select" name="image_360_yn">
<select class="form-select form-select-sm" name="image_360_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
@@ -313,7 +318,7 @@ $usr_nm = session('usr_nm');
<!-- 검색유형 -->
<div class="col-md-1">
<label class="form-label mb-1">검색유형</label>
<select class="form-select" name="srchType">
<select class="form-select form-select-sm" name="srchType">
<option value="">선택</option>
<option value="1">중개사명</option>
<option value="2">주소</option>
@@ -324,7 +329,7 @@ $usr_nm = session('usr_nm');
<!-- 검색어 -->
<div class="col-md-2">
<label class="form-label mb-1">검색어</label>
<input type="text" class="form-control" name="srchTxt" placeholder="검색어 입력">
<input type="text" class="form-control form-control-sm" name="srchTxt" placeholder="검색어 입력">
</div>
<div class="col-md-1 d-grid">
@@ -341,18 +346,17 @@ $usr_nm = session('usr_nm');
</div>
<div class="main-card mb-3 card">
<div class="card-header d-flex align-items-center">
<div class="d-flex align-items-center flex-wrap" style="gap: 8px; flex: 1">
</div>
<div class="ml-auto">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center w-100 justify-content-between card-header-tab">
<h5 class="mb-0 fw-bold text-dark">검색 결과</h5>
<div class="d-flex align-items-center gap-2 ms-auto">
<button class="btn btn-sm btn-outline-success" id="excel-download">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
엑셀다운로드
</button>
</div>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table id="resultList" class="table table-hover table-striped table-bordered">

View File

@@ -487,7 +487,7 @@
})
},
success: function (result) {
blockUI.unblockPage()
if (result.code == '0') {
$("#btnSearch").trigger('click')
Swal.fire({
@@ -589,7 +589,7 @@
})
},
success: function (result) {
blockUI.unblockPage()
if (result.code == '0') {
regionModalHide()
$("#btnSearch").trigger('click')

View File

@@ -0,0 +1,284 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div class="page-title-icon">
<i class="pe-7s-monitor icon-gradient bg-mean-fruit"></i>
</div>
<div>
Worker 로그 통합 관리
<div class="page-title-subheading">
API Receiver 및 Worker 서비스의 로그를 한 곳에서 확인할 수 있습니다.
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="main-card mb-3 card">
<div class="card-header">
<div class="btn-actions-pane-left">
<div class="nav">
<button class="btn btn-sm btn-primary" onclick="refreshLogs()">
<i class="fa fa-sync"></i> 새로고침
</button>
<button class="btn btn-sm btn-success" id="autoRefreshBtn" onclick="toggleAutoRefresh()">
<i class="fa fa-play"></i> 자동 새로고침 시작
</button>
</div>
</div>
<div class="btn-actions-pane-right">
<button class="btn btn-sm btn-info" onclick="downloadLog()">
<i class="fa fa-download"></i> 로그 다운로드
</button>
</div>
</div>
<div class="card-body">
<!-- 필터 영역 -->
<div class="row mb-3">
<div class="col-md-4">
<label>날짜 선택</label>
<select class="form-control" id="dateSelect" onchange="changeDate()">
<?php foreach ($availableDates as $availDate): ?>
<option value="<?= $availDate ?>" <?= $availDate === $date ? 'selected' : '' ?>>
<?= $availDate ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-md-4">
<label>로그 타입</label>
<select class="form-control" id="typeSelect" onchange="changeType()">
<option value="all" <?= $logType === 'all' ? 'selected' : '' ?>>전체</option>
<option value="api_receiver" <?= $logType === 'api_receiver' ? 'selected' : '' ?>>API Receiver</option>
<option value="naver_worker" <?= $logType === 'naver_worker' ? 'selected' : '' ?>>Naver Worker</option>
</select>
</div>
<div class="col-md-4">
<label>레벨 필터</label>
<select class="form-control" id="levelFilter" onchange="filterByLevel()">
<option value="all">전체</option>
<option value="ERROR">ERROR</option>
<option value="INFO">INFO</option>
<option value="DEBUG">DEBUG</option>
</select>
</div>
</div>
<!-- 통계 영역 -->
<div class="row mb-3">
<div class="col-md-3">
<div class="card mb-3 widget-content bg-midnight-bloom">
<div class="widget-content-wrapper text-white">
<div class="widget-content-left">
<div class="widget-heading">전체 로그</div>
<div class="widget-subheading">Total Logs</div>
</div>
<div class="widget-content-right">
<div class="widget-numbers text-white">
<span id="totalCount"><?= count($logs) ?></span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card mb-3 widget-content bg-arielle-smile">
<div class="widget-content-wrapper text-white">
<div class="widget-content-left">
<div class="widget-heading">INFO</div>
<div class="widget-subheading">Information</div>
</div>
<div class="widget-content-right">
<div class="widget-numbers text-white">
<span id="infoCount"><?= count(array_filter($logs, fn($l) => $l['level'] === 'INFO')) ?></span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card mb-3 widget-content bg-grow-early">
<div class="widget-content-wrapper text-white">
<div class="widget-content-left">
<div class="widget-heading">ERROR</div>
<div class="widget-subheading">Errors</div>
</div>
<div class="widget-content-right">
<div class="widget-numbers text-white">
<span id="errorCount"><?= count(array_filter($logs, fn($l) => $l['level'] === 'ERROR')) ?></span>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card mb-3 widget-content bg-premium-dark">
<div class="widget-content-wrapper text-white">
<div class="widget-content-left">
<div class="widget-heading">DEBUG</div>
<div class="widget-subheading">Debug Logs</div>
</div>
<div class="widget-content-right">
<div class="widget-numbers text-white">
<span id="debugCount"><?= count(array_filter($logs, fn($l) => $l['level'] === 'DEBUG')) ?></span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 로그 테이블 -->
<div class="table-responsive" style="max-height: 600px; overflow-y: auto;">
<table class="table table-hover table-striped table-sm" id="logTable">
<thead class="thead-dark" style="position: sticky; top: 0; z-index: 10;">
<tr>
<th style="width: 150px;">시간</th>
<th style="width: 80px;">레벨</th>
<th style="width: 120px;">소스</th>
<th style="width: 150px;">위치</th>
<th>메시지</th>
</tr>
</thead>
<tbody id="logTableBody">
<?php if (empty($logs)): ?>
<tr>
<td colspan="5" class="text-center">로그가 없습니다.</td>
</tr>
<?php else: ?>
<?php foreach ($logs as $log): ?>
<tr class="log-row" data-level="<?= esc($log['level']) ?>">
<td><small><?= esc($log['timestamp']) ?></small></td>
<td>
<span class="badge badge-<?= $log['level'] === 'ERROR' ? 'danger' : ($log['level'] === 'INFO' ? 'success' : 'secondary') ?>">
<?= esc($log['level']) ?>
</span>
</td>
<td>
<span class="badge badge-<?= strpos($log['source'], 'failed') !== false ? 'warning' : 'info' ?>">
<?php
$sourceLabel = [
'api_receiver' => 'API Receiver',
'naver_worker' => 'Worker',
'naver_worker_failed' => 'Worker (Failed)'
];
echo $sourceLabel[$log['source']] ?? $log['source'];
?>
</span>
</td>
<td><small><?= esc($log['location']) ?></small></td>
<td>
<small style="word-break: break-all;">
<?= esc($log['message']) ?>
</small>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
let autoRefreshInterval = null;
let isAutoRefresh = false;
function changeDate() {
const date = document.getElementById('dateSelect').value;
const type = document.getElementById('typeSelect').value;
window.location.href = '<?= base_url('manage/workerlog') ?>?date=' + date + '&type=' + type;
}
function changeType() {
const date = document.getElementById('dateSelect').value;
const type = document.getElementById('typeSelect').value;
window.location.href = '<?= base_url('manage/workerlog') ?>?date=' + date + '&type=' + type;
}
function refreshLogs() {
location.reload();
}
function toggleAutoRefresh() {
if (isAutoRefresh) {
clearInterval(autoRefreshInterval);
isAutoRefresh = false;
document.getElementById('autoRefreshBtn').innerHTML = '<i class="fa fa-play"></i> 자동 새로고침 시작';
document.getElementById('autoRefreshBtn').classList.remove('btn-danger');
document.getElementById('autoRefreshBtn').classList.add('btn-success');
} else {
autoRefreshInterval = setInterval(refreshLogs, 10000); // 10초마다
isAutoRefresh = true;
document.getElementById('autoRefreshBtn').innerHTML = '<i class="fa fa-stop"></i> 자동 새로고침 중지';
document.getElementById('autoRefreshBtn').classList.remove('btn-success');
document.getElementById('autoRefreshBtn').classList.add('btn-danger');
}
}
function filterByLevel() {
const level = document.getElementById('levelFilter').value;
const rows = document.querySelectorAll('.log-row');
let visibleCount = 0;
let infoCount = 0;
let errorCount = 0;
let debugCount = 0;
rows.forEach(row => {
const rowLevel = row.getAttribute('data-level');
if (level === 'all' || rowLevel === level) {
row.style.display = '';
visibleCount++;
} else {
row.style.display = 'none';
}
// 통계 계산
if (rowLevel === 'INFO') infoCount++;
if (rowLevel === 'ERROR') errorCount++;
if (rowLevel === 'DEBUG') debugCount++;
});
// 통계 업데이트
if (level === 'all') {
document.getElementById('totalCount').textContent = visibleCount;
}
}
function downloadLog() {
const date = document.getElementById('dateSelect').value;
const type = document.getElementById('typeSelect').value;
window.location.href = '<?= base_url('manage/workerlog/download') ?>?date=' + date + '&type=' + type;
}
// 페이지 로드 시 스크롤을 테이블 하단으로 (최신 로그가 위에 있으므로 생략)
</script>
<style>
.table-responsive {
border: 1px solid #dee2e6;
}
.log-row:hover {
background-color: #f8f9fa !important;
}
.badge {
font-size: 0.75rem;
}
.widget-content {
padding: 1rem;
}
</style>
<?= $this->endSection() ?>

View File

@@ -32,6 +32,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<link rel="stylesheet" href="/common/css/custom.css">
<style>
table th {
vertical-align: middle;
@@ -62,18 +63,16 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
min-height: 100px;
}
/* 정보변경 이력 테이블 깜박임 방지 */
.apt-info-table {
table-layout: fixed;
width: 100%;
}
.swal2-cancel {
@@ -93,14 +92,6 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>확인매물 상세 내용</div>
</div>
</div>
</div>
<form name="rcptFrm" id="rcptFrm" method="post" action="" enctype="multipart/form-data" autocomplete="off"
onsubmit="return false;">
<input type="hidden" name="address_code" id="address_code" value="<?= $data['address_code'] ?>" />
@@ -113,30 +104,19 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-3 card">
<div class="card-header" style="width:100%; max-width:100%; min-width:600px; padding:0; border:0;">
<p class="left">
</p>
<table style="width:100%; min-width:600px; padding:0; border:0;" cellpadding="0" cellspacing="0"
border="0" width="100%">
<tbody>
<tr>
<td style="width: 50%;padding-left: 20px"><span class="tit">매물ID :</span> <span
class="num"><?= $data['atcl_no'] ?></span>
</td>
<td style="width: 20%;"><span class="tit">CP ID :</span> <span
class="num"><?= $data['cpid'] ?></span></td>
<td style="width: 30%; text-align: right;padding-right: 20px"><span class="tit">현재 상태
:</span> <span class="num"><?= $data['pre_stat'] ?></span></td>
</tr>
<tr>
<td height="15"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p></p>
<div class="main-card mb-2 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center w-100 justify-content-between card-header-tab">
<h4 class="mb-0 fw-bold text-dark">확인매물 상세 내용</h4>
<div class="d-flex align-items-center flex-nowrap gap-4 ms-auto" style="white-space:nowrap;">
<span class="text-muted me-2">매물ID:</span>
<span class="fw-bold text-primary fs-6 me-4"> <?= $data['atcl_no'] ?> </span>
<span class="text-muted me-2">CP ID:</span>
<span class="fw-bold text-primary fs-6 me-4"> <?= $data['cpid'] ?> </span>
<span class="text-muted me-2">현재 상태:</span>
<span class="fw-bold text-danger fs-6"> <?= $data['pre_stat'] ?> </span>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-title">공인 중개사 정보</h5>
@@ -158,16 +138,16 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
</div>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body">
<h5 class="card-title">매물 정보</h5>
<div class="table-responsive">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0 apt-info-table">
<colgroup>
<col style="width:120px">
<col style="width:320px">
<col style="width:120px">
<col style="width:320px">
<col width="15%" />
<col width="35%" />
<col width="15%" />
<col width="35%" />
</colgroup>
<tbody>
@@ -300,7 +280,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<th>가격</th>
<td>
<!-- 기본 가격 -->
<div class="align-items-center gap-2 mb-2" id="div_trade_type_price"
<div class="align-items-center gap-2 mb-0" id="div_trade_type_price"
style="display: none;">
<div class="input-group input-group-sm" style="max-width: 220px;">
<input type="text" class="form-control text-end" name="atcl_amt1"
@@ -319,7 +299,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php endif; ?>
</div>
<div class="d-flex align-items-center gap-1 mb-2"
<div class="d-flex align-items-center gap-1 mb-0"
id="div_trade_type_price_monthly" style="display: none;">
<div class="input-group input-group-sm" style="max-width: 220px;">
<input type="text" class="form-control text-end" name="atcl_amt2"
@@ -554,9 +534,9 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php
$apt_rlet_type_cd = ['A01', 'A02', 'A03', 'A04', 'B01', 'B02', 'B03'];
$villa_rlet_type_cd = ['A05', 'A06'];
if (in_array($detail_hscp['aptType'], $apt_rlet_type_cd)):
if (isset($detail_hscp['aptType']) && in_array($detail_hscp['aptType'], $apt_rlet_type_cd)):
?>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body ">
<h5 class="card-title">단지 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
@@ -578,9 +558,9 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php endif; ?>
<?php
if (in_array($detail_hscp['aptType'], $villa_rlet_type_cd)):
if (isset($detail_hscp['aptType']) && in_array($detail_hscp['aptType'], $villa_rlet_type_cd)):
?>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body ">
<h5 class="card-title">단지 정보</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
@@ -614,7 +594,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php endif; ?>
<?php endif; ?>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body ">
<h5 class="card-title">상태변경</h5>
<?php foreach ($codes as $c): ?>
@@ -627,7 +607,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
<div class="main-card mb-3 card" id="docu_chk" style="display: none;">
<div class="main-card mb-2 card" id="docu_chk" style="display: none;">
<div class="card-body">
<h5 class="card-title">서류확인 정보</h5>
@@ -645,14 +625,19 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php if (!empty($data['confirm_doc_img_url'])): ?>
<?php if ($data['confirm_doc_img_url_save_yn'] == 'Y'):
if (!empty($record)) {
$img_path = $record['file_path'] . $record['file_name'];
$ext = $record['file_ext'];
} else {
$img_path = '';
$ext = '';
}
if (strtolower($ext) == '.pdf'):
?>
<iframe src="<?= $server_addr ?><?= $img_path ?>" frameborder="0"
<iframe src="<?= $server_addr ?><?= $img_path ?>" frameborder="0" loading="lazy"
style="padding: 10px 0;width:100%; height:800px;"></iframe><br>
<?php elseif (!in_array($ext, ['.zip', '.ZIP', '.pdf', '.PDF'])): ?>
<?php if (!empty($arrRecord) && is_array($arrRecord)): ?>
<?php foreach ($arrRecord as $row):
$arr_img_path = $row['file_path'] . $row['file_name'];
?>
@@ -664,6 +649,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</a>
<?php endforeach; ?>
<?php endif; ?>
<?php endif; ?>
<?php else:
$img_path = $data['confirm_doc_img_url'];
@@ -671,18 +657,18 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
if (strtolower($ext) == '.pdf'):
?>
<iframe src="<?= $img_path ?>" frameborder="0"
<iframe src="<?= $img_path ?>" frameborder="0" loading="lazy"
style="padding: 10px 0;width:100%; height:800px;"></iframe>
<?php else: ?>
<?php endif; ?>
<img id="photo-display" src="<?= $img_path ?>" alt="Image"
<img id="photo-display" src="<?= $img_path ?>" alt="Image" loading="lazy"
style="width:100%;max-width:945px;min-width:100%;border:0;" />
<?php endif; ?>
<?php else: ?>
<a href="#" rel="lightbox[gallery]">
<img id="photo-display" src="/plugin/img/photo.gif" alt="Image"
<img id="photo-display" src="/plugin/img/photo.gif" alt="Image" loading="lazy"
style="width:100%; max-width:945px; border:0;">
</a>
@@ -702,7 +688,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<!-- 우측 : 정보 -->
<td valign="top" class="pt-2">
<table class="table table-sm w-100 tbl_basic2 table-bordered">
<table class="table table-sm tbl_basic2 table-bordered">
<colgroup>
<col width="30%">
<col>
@@ -734,7 +720,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<tr>
<th>홍보확인서<br>미확인여부상세</th>
<td>
<table class="table w-100 tbl_basic2 table-bordered">
<table class="table tbl_basic2 table-bordered">
<tr>
<?php
$checks = explode('|', $data['comment']);
@@ -864,14 +850,14 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</tbody>
</table>
</div>
<div class="card-footer d-flex justify-content-end gap-1">
<div class="card-footer d-flex justify-content-end">
<button type="button" class="btn btn-success btn-sm" onclick="saveDocu();">
저장
</button>
</div>
</div>
<div class="main-card mb-3 card" id="call_chk" style="display: none;">
<div class="main-card mb-2 card" id="call_chk" style="display: none;">
<div class="card-body">
<h5 class="card-title">전화확인 정보</h5>
@@ -1086,7 +1072,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
<div class="main-card mb-3 card" id="regibox">
<div class="main-card mb-2 card" id="regibox">
<div class="card-body">
<h5 class="card-title">등기부등본확인 정보</h5>
@@ -1103,12 +1089,12 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php if (!empty($data['cert_register'])): ?>
<?php if ($data['cert_register_save_yn'] == 'Y'): ?>
<?php if (strtolower($file_pdf) == 'pdf') { ?>
<iframe src="<?= $server_addr ?><?= $regi_pdf_path ?>" frameborder="0"
<iframe src="<?= $server_addr ?><?= $regi_pdf_path ?>" frameborder="0" loading="lazy"
style="padding: 10px 0;width:100%; height:800px;"></iframe><br />
<?php } else { ?>
<div id="regi_file_dis" style="padding: 10px 0px; height: 730px; overflow-y: auto;">
<?php if (empty($arrRegist)) { ?>
<img id="photo-display2" src="/img/photo.gif" alt="Image"
<img id="photo-display2" src="/img/photo.gif" alt="Image" loading="lazy"
style="width:100%;max-width:945px;min-width:100%;border:0;" />
<?php } else {
foreach ($arrRegist as $row) {
@@ -1124,12 +1110,12 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<?php } ?>
<?php else: ?>
<?php if (strtolower($file_pdf) == 'pdf') { ?>
<iframe src="<?= $regi_pdf_path ?>" frameborder="0"
<iframe src="<?= $regi_pdf_path ?>" frameborder="0" loading="lazy"
style="padding: 10px 0;width:100%; height:800px;"></iframe><br>
<?php } else { ?>
<div id="regi_file_dis" style="padding: 10px 0px; height: 730px; overflow-y: auto;">
<?php if (empty($arr_cert_register)) { ?>
<img id="photo-display2" src="/plugin/img/photo.gif" alt="Image"
<img id="photo-display2" src="/plugin/img/photo.gif" alt="Image" loading="lazy"
style="width:100%;max-width:945px;min-width:100%;border:0;" />
<?php } else {
foreach ($arr_cert_register as $img_path) { ?>
@@ -1162,7 +1148,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
?>
<div id="regi_file_dis" style="padding: 10px 0;">
<img id="photo-display2" src="<?= $regi_img_path ?>" alt="Image"
<img id="photo-display2" src="<?= $regi_img_path ?>" alt="Image" loading="lazy"
style="width:100%;max-width:945px;min-width:100%;border:0;" />
</div>
<div id="regi_file_pdf" style="padding: 10px 0; display:none;">
@@ -1348,13 +1334,13 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body ">
<h5 class="card-title">정보변경 이력</h5>
<div class="table-scroll">
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<tr>
<th width="90" style="text-align: center;">진행상태</th>
<th width="120" style="text-align: center;">진행상태</th>
<th width="150" style="text-align: center;">변경내용</th>
<th width="90" style="text-align: center;">처리자(ID)</th>
<th width="120" style="text-align: center;">처리일시</th>
@@ -1599,6 +1585,26 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
$(function () {
// DOM Ready 시 즉시 blockUI 해제
if (typeof blockUI !== 'undefined') {
blockUI.unblockPage();
}
$('.blockUI').remove();
$('body').css('overflow', '');
// 페이지 완전 로드 후에도 다시 한번 해제
$(window).on('load', function() {
setTimeout(function() {
if (typeof blockUI !== 'undefined') {
blockUI.unblockPage();
}
$('.blockUI').remove();
$('.blockOverlay').remove();
$('body').css('overflow', '');
$('body').removeClass('modal-open');
}, 100);
});
if (failChk == "20040") {
$("#fail_chk1").attr("checked", true);
} else if (failChk == "20041") {

View File

@@ -1,76 +1,35 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>확인매물 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">확인매물 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -246,23 +205,8 @@
</form>
</div>
</div>
</div>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header d-flex align-items-center">
<div class="d-flex align-items-center flex-wrap" style="gap: 8px; flex: 1">
</div>
<div class="ml-auto">
<button class="btn btn-sm btn-outline-success" id="excel-download">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
엑셀다운로드
</button>
</div>
</div>
<div class="card-body">
<table id="resultList" class="table table-hover table-striped table-bordered">
<thead>
@@ -290,10 +234,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -305,7 +255,38 @@
var table;
$(function () {
// 검색 조건 저장
function saveSearchForm() {
const data = $("#frm_srch_info").serializeArray();
localStorage.setItem("m701_search", JSON.stringify(data));
}
// 검색 조건 복원
function restoreSearchForm() {
const saved = localStorage.getItem("m701_search");
if (!saved) return;
const data = JSON.parse(saved);
data.forEach(function(item) {
$("[name='" + item.name + "']").val(item.value);
});
// 주요 select에 대해 change 이벤트 트리거
$("#srcSido, #srcGugun, #bonbu, #team, #vrfcreq_way").trigger("change");
}
$(function () {
// referrer에 '/m701'가 없으면 검색 조건 초기화
if (!document.referrer.includes('/m701')) {
localStorage.removeItem("m701_search");
}
restoreSearchForm();
// Bootstrap Tooltip 초기화 (빠른 표시)
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl, {
delay: { "show": 100, "hide": 100 }
})
})
$("#bonbu").on("change", function (e) {
@@ -479,6 +460,24 @@
initReceiptDate();
table = $('#resultList').DataTable({
layout: {
topStart: 'pageLength', // 좌측 상단(페이지당 개수) 제거 (필요시)
topEnd: function () {
// 직접 작성하신 버튼 HTML 구조를 생성
let btn = document.createElement('button');
btn.id = 'excel-download';
btn.className = 'btn btn-sm btn-outline-success';
btn.innerHTML = '<i class="fa fa-fw fa-file-excel-o" aria-hidden="true"></i> 엑셀다운로드';
// 클릭 이벤트 연결
btn.addEventListener('click', function() {
console.log('엑셀 다운로드 실행');
// 여기에 다운로드 로직 추가
});
return btn;
}
},
language: lang_kor,
serverSide: true,
processing: true,
@@ -526,15 +525,17 @@
{ 'targets': '_all', "defaultContent": "" },
],
columns: [
{ data: 'atcl_no' },
{ data: 'pre_stat' },
{ data: 'insert_tm' },
{ data: 'vrfc_type' },
{ data: null, render: fn_region_render },
{ data: null, render: fn_addr_render },
{ data: 'cpid' },
{ data: 'realtor_nm' },
{ data: 'usr_nm', width: "80px" },
{ data: 'atcl_no' , render: function (data, type, row) {
return `<a href='<?php echo site_url('m701/m701a/detail') ?>/${row.vr_sq}' class='text-decoration-none'>${data}</a>`;
}, className: 'tw-90' },
{ data: 'pre_stat', className: 'tw-120' },
{ data: 'insert_tm', className: 'tw-130' },
{ data: 'vrfc_type', className: 'tw-100' },
{ data: null, render: fn_region_render , className: 'tw-200' },
{ data: null, render: fn_addr_render , className: 'tw-180' },
{ data: 'cpid', className:'tw-80' },
{ data: 'realtor_nm' , className: 'tw-150' },
{ data: 'usr_nm', className: 'tw-80' },
{ data: null, render: fn_tm_render },
{ data: 'reg_charger' },
{ data: 'rgbk_check_tm' },
@@ -545,20 +546,28 @@
paging: true,
searching: false,
ordering: false,
autoWidth: false,
});
$('#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;
const vr_sq = rowData.vr_sq;
window.open("<?= site_url('m701/m701a/detail') ?>/" + vr_sq, '_blank');
const url = "<?= site_url('m701/m701a/detail') ?>/" + vr_sq;
// Ctrl+Click 또는 마우스 중간(휠) 클릭(e.button === 1) 시 새탭
if (e.ctrlKey || e.button === 1) {
window.open(url, '_blank');
return;
}
// 일반 클릭은 현재 탭
window.location.href = url;
});
$('#btnSearch').on('click', function () {
table.ajax.reload()
saveSearchForm();
table.ajax.reload();
});
// 엑셀 다운로드 click

View File

@@ -54,6 +54,10 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
text-align: left;
}
.tbl_basic2 td {
text-align: left;
}
.blockUI {
z-index: 1500 !important;
}
@@ -65,18 +69,16 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
min-height: 100px;
}
/* 정보변경 이력 테이블 깜박임 방지 */
.apt-info-table {
table-layout: fixed;
width: 100%;
}
.swal2-cancel {
@@ -104,14 +106,6 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>배정매물 상세 내용</div>
</div>
</div>
</div>
<form name="rcptFrm" id="rcptFrm" method="post" action="" enctype="multipart/form-data" autocomplete="off"
onsubmit="return false;">
<input type="hidden" name="address_code" id="address_code" value="<?= $data['address_code'] ?>" />
@@ -124,31 +118,19 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-3 card">
<div class="card-header" style="width:100%; max-width:100%; min-width:600px; padding:0; border:0;">
<p class="left">
</p>
<table style="width:100%; min-width:600px; padding:0; border:0;" cellpadding="0" cellspacing="0"
border="0" width="100%">
<tbody>
<tr>
<td style="width: 50%;padding-left: 20px"><span class="tit">매물ID :</span> <span
class="num"><?= $data['atcl_no'] ?></span>
</td>
<td style="width: 20%;"><span class="tit">CP ID :</span> <span
class="num"><?= $data['cpid'] ?></span></td>
<td style="width: 30%; text-align: right;padding-right: 20px"><span class="tit">현재 상태
:</span> <span class="num"><?= $data['pre_stat'] ?></span></td>
</tr>
<tr>
<td height="15"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p></p>
<div class="main-card mb-2 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center w-100 justify-content-between card-header-tab">
<h4 class="mb-0 fw-bold text-dark">배정매물 상세 내용</h4>
<div class="d-flex align-items-center flex-nowrap gap-4 ms-auto" style="white-space:nowrap;">
<span class="text-muted me-2">매물ID:</span>
<span class="fw-bold text-primary fs-6 me-4"> <?= $data['atcl_no'] ?> </span>
<span class="text-muted me-2">CP ID:</span>
<span class="fw-bold text-primary fs-6 me-4"> <?= $data['cpid'] ?> </span>
<span class="text-muted me-2">현재 상태:</span>
<span class="fw-bold text-danger fs-6"> <?= $data['pre_stat'] ?> </span>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-title">공인 중개사 정보</h5>
@@ -170,16 +152,16 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
</div>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body">
<h5 class="card-title">매물 정보</h5>
<div class="table-responsive">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0 apt-info-table">
<colgroup>
<col style="width:120px">
<col style="width:320px">
<col style="width:120px">
<col style="width:320px">
<col width="15%" />
<col width="35%" />
<col width="15%" />
<col width="35%" />
</colgroup>
<tbody>
@@ -523,7 +505,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
<div class="main-card mb-3 card" id="docu_chk" style="display: none;">
<div class="main-card mb-2 card" id="docu_chk" style="display: none;">
<div class="card-body">
<h5 class="card-title">서류확인 정보</h5>
@@ -766,7 +748,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
</div>
<div class="main-card mb-3 card" id="call_chk" style="display: none;">
<div class="main-card mb-2 card" id="call_chk" style="display: none;">
<div class="card-body">
<h5 class="card-title">전화확인 정보</h5>
@@ -940,7 +922,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<tr>
<th>메모</th>
<td>
<div class="d-flex flex-column gap-1" style="">
<div class="d-flex flex-column gap-1">
<textarea class="form-control" name="memo_tel" id="memo_tel" rows="2"
style="resize: none;"><?= $memo['memo'] ?></textarea>
@@ -976,7 +958,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
</div>
<div class="main-card mb-3 card" id="regibox">
<div class="main-card mb-2 card" id="regibox">
<div class="card-body">
<h5 class="card-title">등기부등본확인 정보</h5>
@@ -1188,7 +1170,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<div class="card-body ">
<h5 class="card-title">정보변경 이력</h5>
<div class="table-scroll">
@@ -1216,7 +1198,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
</div>
</div>
<div class="main-card mb-3 card">
<div class="main-card mb-2 card">
<button type="button" class="btn btn-light btn-sm">
목록
</button>

View File

@@ -1,76 +1,33 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>확인매물 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">배정매물 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -240,50 +197,6 @@
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header d-flex align-items-center">
<div class="d-flex align-items-center flex-wrap" style="gap:8px; flex:1;">
<select class="form-control form-control-sm" id="damdangT" style="width:150px;">
<option value="1">전화/서류 담당자</option>
<option value="2">등기부등본 담당자</option>
</select>
<select class="form-control form-control-sm" id="bonbu2" style="width:140px;">
<option value="">-본부-</option>
<?php foreach ($bonbu as $d): ?>
<option value="<?= $d['dept_sq'] ?>"><?= $d['dept_nm'] ?></option>
<?php endforeach; ?>
</select>
<select class="form-control form-control-sm" id="team2" style="width:160px;">
<option value="">-팀-</option>
</select>
<select class="form-control form-control-sm" id="damdang2" style="width:160px;">
<option value="">-담당자-</option>
</select>
<button type="button" class="btn btn-sm btn-outline-light" id="btn_part_change">
배정변경
</button>
<button type="button" class="btn btn-sm btn-outline-light" id="btn_part_omit">
서류누락
</button>
</div>
<div class="ml-auto">
<button class="btn btn-sm btn-outline-light" id="excel-download">
등기부등본 전송
</button>
<button class="btn btn-sm btn-outline-success" id="excel-download">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
엑셀다운로드
</button>
</div>
</div>
<div class="card-body">
<table id="resultList" class="table table-hover table-striped table-bordered">
<thead>
@@ -313,10 +226,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -328,7 +247,30 @@
var table;
// 검색 조건 저장
function saveSearchForm() {
const data = $("#frm_srch_info").serializeArray();
localStorage.setItem("m702_search", JSON.stringify(data));
}
// 검색 조건 복원
function restoreSearchForm() {
const saved = localStorage.getItem("m702_search");
if (!saved) return;
const data = JSON.parse(saved);
data.forEach(function(item) {
$("[name='" + item.name + "']").val(item.value);
});
// 주요 select에 대해 change 이벤트 트리거
$("#srcSido, #srcGugun, #bonbu, #team, #vrfcreq_way").trigger("change");
}
$(function () {
// referrer에 '/m702'가 없으면 검색 조건 초기화
if (!document.referrer.includes('/m702')) {
localStorage.removeItem("m702_search");
}
restoreSearchForm();
$("#bonbu").on("change", function (e) {
@@ -419,7 +361,7 @@
});
$("#bonbu, #team, #bonbu2, #team2").on("change", function (e) {
$(document).on("change", "#bonbu, #team, #bonbu2, #team2", function (e) {
const targetId = this.id;
@@ -505,6 +447,88 @@
initReceiptDate();
table = $('#resultList').DataTable({
layout: {
topStart: function() {
const container = document.createElement('div');
container.className = 'd-flex align-items-center flex-wrap';
container.style.cssText = 'gap:8px; flex:1;';
// 담당자 유형
const damdangT = document.createElement('select');
damdangT.id = 'damdangT';
damdangT.className = 'form-control form-control-sm';
damdangT.style.width = '150px';
damdangT.innerHTML = `
<option value="1">전화/서류 담당자</option>
<option value="2">등기부등본 담당자</option>
`;
// 본부
const bonbu2 = document.createElement('select');
bonbu2.id = 'bonbu2';
bonbu2.className = 'form-control form-control-sm';
bonbu2.style.width = '140px';
bonbu2.innerHTML = '<option value="">-본부-</option>';
// bonbuArr 배열을 사용하여 옵션 추가
bonbuArr.forEach(function(d) {
const opt = document.createElement('option');
opt.value = d.dept_sq;
opt.textContent = d.dept_nm;
bonbu2.appendChild(opt);
});
// 팀
const team2 = document.createElement('select');
team2.id = 'team2';
team2.className = 'form-control form-control-sm';
team2.style.width = '160px';
team2.innerHTML = '<option value="">-팀-</option>';
// 담당자
const damdang2 = document.createElement('select');
damdang2.id = 'damdang2';
damdang2.className = 'form-control form-control-sm';
damdang2.style.width = '160px';
damdang2.innerHTML = '<option value="">-담당자-</option>';
// 배정변경 버튼
const btnChange = document.createElement('button');
btnChange.type = 'button';
btnChange.id = 'btn_part_change';
btnChange.className = 'btn btn-sm btn-outline-light';
btnChange.textContent = '배정변경';
// 서류누락 버튼
const btnOmit = document.createElement('button');
btnOmit.type = 'button';
btnOmit.id = 'btn_part_omit';
btnOmit.className = 'btn btn-sm btn-outline-light';
btnOmit.textContent = '서류누락';
container.append(damdangT, bonbu2, team2, damdang2, btnChange, btnOmit);
return container;
},
topEnd: function () {
const container = document.createElement('div');
container.className = 'd-flex';
container.style.gap = '8px';
container.style.justifyContent = 'flex-end';
// 등기부등본 전송 버튼
const btnSend = document.createElement('button');
btnSend.className = 'btn btn-sm btn-outline-light';
btnSend.textContent = '등기부등본 전송';
// 엑셀 다운로드 버튼
const btnExcel = document.createElement('button');
btnExcel.id = 'excel-download';
btnExcel.className = 'btn btn-sm btn-outline-success';
btnExcel.innerHTML = '<i class="fa fa-fw fa-file-excel-o" aria-hidden="true"></i> 엑셀다운로드';
container.append(btnSend, btnExcel);
return container;
}
},
language: lang_kor,
serverSide: true,
processing: true,
@@ -550,13 +574,15 @@
{ 'targets': '_all', "defaultContent": "" },
],
columns: [
{ data: null, render: fn_chk_render, width: "50px", className: "dt-no-rowclick" },
{ data: 'atcl_no' },
{ data: null, render: fn_chk_render, className: "dt-no-rowclick tw-50" },
{ data: 'atcl_no' , function(data, type, row) {
return `<a href='<?php echo site_url('m702/m702a/detail') ?>/${row.vr_sq}' class='text-decoration-none'>${data}</a>`;
}, className:'tw-90' },
{ data: 'pre_stat' },
{ data: 'insert_tm' },
{ data: 'vrfc_type' },
{ data: null, render: fn_region_render },
{ data: null, render: fn_addr_render },
{ data: null, render: fn_region_render , className: 'tw-200' },
{ data: null, render: fn_addr_render , className: 'tw-180' },
{ data: 'cpid' },
{ data: 'realtor_nm' },
{ data: 'usr_nm', width: "80px" },
@@ -582,6 +608,7 @@
});
$('#btnSearch').on('click', function () {
saveSearchForm();
table.ajax.reload()
});

View File

@@ -1,6 +1,6 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<link rel="stylesheet" href="/common/css/custom.css">
<style>
table th {
vertical-align: middle;
@@ -20,43 +20,68 @@
text-align: left;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
/* GLightbox z-index 설정 */
.glightbox-container {
z-index: 9999 !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
min-height: 100px;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
.num {
font-family: Tahoma;
color: #b68556;
font-size: 17px;
}
.table th,
.table td {
vertical-align: top;
box-sizing: border-box;
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>홍보확인서 상세 내용</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="main-card mb-3 card">
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-2 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center w-100 justify-content-between card-header-tab">
<h4 class="mb-0 fw-bold text-dark">홍보확인서 상세 내용</h4>
<div class="d-flex align-items-center flex-nowrap gap-4 ms-auto" style="white-space:nowrap;">
<?php if (($data['receiver'] ?? '') != "API"): ?>
<span class="text-muted me-2">발신번호:</span>
<span class="fw-bold text-primary fs-6 me-4"><?= esc(str_replace('-', '', $data['caller_no'] ?? '')) ?></span>
<?php endif; ?>
<span class="text-muted me-2">팩스 순번:</span>
<span class="fw-bold text-primary fs-6 me-4"><?= $data['fax_sq'] ?></span>
<?php if (($data['receiver'] ?? '') != "API"): ?>
<div class="card-header">
<div class="d-flex align-items-center w-100">
<div class="ms-auto d-flex gap-1">
<span class="text-muted small me-2">
발신번호 : <?= esc(str_replace('-', '', $data['caller_no'] ?? '')) ?>
</span>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(90)">90˚</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(180)">180˚</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(270)">270˚</button>
</div>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<div class="card-body">
<!-- table 유지 + 반응형 -->
<div class="table-responsive">
@@ -92,13 +117,15 @@
?>
<?php if ($ext === 'pdf'): ?>
<a href="<?= esc($filePath . $fileName) ?>" class="embed"></a>
<a href="<?= esc($filePath . $fileName) ?>" target="_blank" class="btn btn-primary">PDF 보기</a>
<?php else: ?>
<a onclick="fn_preview('<?= esc($image_path . $fileName) ?>?<?= esc(($data['img_width'] ?? '') . ($data['img_height'] ?? '')) ?>')"
rel="lightbox">
<a href="<?= esc($image_path . $fileName) ?>?<?= esc(($data['img_width'] ?? '') . ($data['img_height'] ?? '')) ?>"
class="glightbox"
data-gallery="fax-image"
data-title="팩스 이미지">
<img id="fax_image"
src="<?= esc($image_path . $fileName) ?>?<?= esc(($data['img_width'] ?? '') . ($data['img_height'] ?? '')) ?>"
alt="fax" class="img-fluid" style="width: 100%;" />
alt="fax" class="img-fluid" style="width: 100%; cursor: pointer;" />
</a>
<?php endif; ?>
</td>
@@ -121,7 +148,7 @@
<div class="card-body p-2">
<table class="table table-sm table-bordered mb-2 tbl_basic2 align-middle">
<colgroup>
<col style="width: 110px;">
<col style="width: 120px;">
<col>
</colgroup>
<tbody>
@@ -652,7 +679,7 @@
<table
class="table table-sm table-bordered mb-2 tbl_basic2 align-middle">
<colgroup>
<col style="width: 140px;">
<col style="width: 120px;">
<col>
</colgroup>
<tbody>
@@ -940,10 +967,10 @@
<div class="table-scroll" style="height: 250px;overflow-y: scroll;">
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<tr>
<th width="90" style="text-align: center;">진행상태</th>
<th width="150" style="text-align: center;">진행상태</th>
<th width="150" style="text-align: center;">변경내용</th>
<th width="90" style="text-align: center;">처리자(ID)</th>
<th width="120" style="text-align: center;">처리일시</th>
<th width="150" style="text-align: center;">처리일시</th>
<th style="text-align: center;">세부내용</th>
</tr>
<?php if (!empty($history)) { ?>
@@ -973,29 +1000,25 @@
</div>
</div>
</div>
<?= $this->section('modals') ?>
<div class="modal" id="previewModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">미리보기</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0">
<img id="imgPreview" src="" alt="미리보기" width="100%" height="auto">
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('page_styles') ?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js"></script>
<script type="text/javascript">
$(function () {
// GLightbox 초기화
const lightbox = GLightbox({
touchNavigation: true,
loop: false,
autoplayVideos: true,
zoomable: true,
draggable: true
});
});
@@ -1776,20 +1799,6 @@
});
}
// 이미지 프리뷰
function fn_preview(src) {
const $img = $('#imgPreview');
// 이미지 표시
$img.attr('src', src).show();
$('#previewTitle').text('이미지 미리보기');
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
</script>
<?= $this->endSection() ?>

View File

@@ -1,76 +1,35 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>확인매물 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">홍보확인서 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호또는 발신팩스번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호 또는 발신팩스번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -292,10 +251,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -308,7 +273,38 @@
var table;
$(function () {
// 검색 조건 저장
function saveSearchForm() {
const data = $("#frm_srch_info").serializeArray();
localStorage.setItem("m703_search", JSON.stringify(data));
}
// 검색 조건 복원
function restoreSearchForm() {
const saved = localStorage.getItem("m703_search");
if (!saved) return;
const data = JSON.parse(saved);
data.forEach(function(item) {
$("[name='" + item.name + "']").val(item.value);
});
// 주요 select에 대해 change 이벤트 트리거
$("#srcSido, #srcGugun, #bonbu, #team").trigger("change");
}
$(function () {
// referrer에 '/m703'가 없으면 검색 조건 초기화
if (!document.referrer.includes('/m703')) {
localStorage.removeItem("m703_search");
}
restoreSearchForm();
// Bootstrap Tooltip 초기화 (빠른 표시)
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl, {
delay: { "show": 100, "hide": 100 }
})
})
$("#bonbu").on("change", function (e) {
@@ -536,6 +532,7 @@
});
$('#btnSearch').on('click', function () {
saveSearchForm();
table.ajax.reload()
});

View File

@@ -22,74 +22,6 @@ if (!empty($regist2)) {
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
table th {
vertical-align: middle;
line-height: 1.2;
}
.tbl_basic2 th {
padding: 0 10px;
height: 27px;
line-height: 27px;
vertical-align: middle;
border: solid 1px #d8d9de;
background-color: #eff0f4;
letter-spacing: -1px;
font-weight: normal;
color: #5a5f69;
text-align: left;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
.num {
color: #b68556;
font-size: 19px;
}
.table th,
.table td {
vertical-align: top;
box-sizing: border-box;
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>전화확인매물 상세 내용</div>
</div>
</div>
</div>
<form name="rcptFrm" id="rcptFrm" method="post" action="" enctype="multipart/form-data" onsubmit="return false;">
<input type="hidden" name="address_code" id="address_code" value="<?= $data['address_code'] ?>" />
@@ -102,35 +34,17 @@ if (!empty($regist2)) {
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-3 card">
<div class="card-header" style="width:100%; max-width:100%; min-width:600px; padding:0; border:0;">
<p class="left">
</p>
<table style="width:100%; min-width:600px; padding:0; border:0;" cellpadding="0" cellspacing="0"
border="0" width="100%">
<tbody>
<tr>
<td style="width: 50%;padding-left: 20px"><span class="tit">매물ID :</span> <span
class="num">
<?= $data['atcl_no'] ?>
</span>
</td>
<td style="width: 20%;"><span class="tit">CP ID :</span> <span class="num">
<?= $data['cpid'] ?>
</span></td>
<td style="width: 30%; text-align: right;padding-right: 20px"><span class="tit">현재 상태
:</span> <span class="num">
<?= $data['pre_stat'] ?>
</span></td>
</tr>
<tr>
<td height="15"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p></p>
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3">
<div class="flex-grow-1">
<h4 class="mb-0 fw-bold text-dark">전화확인매물 상세 내용</h4>
</div>
<div class="d-flex flex-wrap gap-3">
<div><span class="tit">매물ID:</span> <span class="num"><?= $data['atcl_no'] ?></span></div>
<div><span class="tit">CP ID:</span> <span class="num"><?= $data['cpid'] ?></span></div>
<div><span class="tit">현재 상태:</span> <span class="num"><?= $data['pre_stat'] ?></span></div>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-title">공인 중개사 정보</h5>
@@ -548,10 +462,10 @@ if (!empty($regist2)) {
</h5>
<table class="table table-bordered table-sm tbl_basic2 apt-info-table">
<colgroup>
<col width="15%" />
<col width="35%" />
<col width="15%" />
<col width="35%" />
<col style="width:120px">
<col>
<col style="width:120px">
<col>
</colgroup>
<tr>
<th>의뢰인(매도자) 전화번호</th>

View File

@@ -1,76 +1,35 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>전화확인매물 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">전화확인매물 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -265,10 +224,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.bootstrap5.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -277,11 +242,21 @@
const bonbuArr = <?= json_encode($bonbu, JSON_UNESCAPED_UNICODE); ?>;
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
});
// localStorage에서 검색 조건 복원
restoreFormData();
$("#bonbu").on("change", function (e) {
const value = e.target.value
@@ -511,7 +486,7 @@
{ data: null, render: fn_addr_render },
{ data: 'cpid' },
{ data: 'realtor_nm' },
{ data: null, width: "80px", fn_render_nm },
{ data: null, width: "80px", render: fn_render_nm },
{ data: null, render: fn_tm_render },
{ data: 'reg_charger' },
{ data: 'result_tm' },
@@ -534,6 +509,7 @@
});
$('#btnSearch').on('click', function () {
saveFormData(); // 검색 조건 저장
table.ajax.reload()
});
@@ -589,14 +565,6 @@
return str;
}
function fn_region_render(data, type, row) {
var str = "";
str = row.region_nm + " " + row.rm_no;
return str;
}
// 주소 render
function fn_addr_render(data, type, row) {
var str = "";
@@ -712,5 +680,29 @@
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
// localStorage에 검색 조건 저장
function saveFormData() {
const formData = $('#frm_srch_info').serializeArray();
const formObject = {};
formData.forEach(item => {
formObject[item.name] = item.value;
});
localStorage.setItem('m704_search_form', JSON.stringify(formObject));
}
// localStorage에서 검색 조건 복원
function restoreFormData() {
const savedData = localStorage.getItem('m704_search_form');
if (savedData) {
const formObject = JSON.parse(savedData);
Object.keys(formObject).forEach(key => {
const $element = $('#frm_srch_info').find(`[name="${key}"]`);
if ($element.length) {
$element.val(formObject[key]);
}
});
}
}
</script>
<?= $this->endSection() ?>

View File

@@ -57,6 +57,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
?>
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<link rel="stylesheet" href="/common/css/custom.css">
<style>
table th {
vertical-align: middle;
@@ -76,29 +77,64 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
text-align: left;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
/* GLightbox z-index 설정 */
.glightbox-container {
z-index: 9999 !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
min-height: 100px;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
.num {
font-family: Tahoma;
color: #b68556;
font-size: 17px;
}
.table th,
.table td {
vertical-align: top;
box-sizing: border-box;
}
.form-check-label {
margin-left: -2px;
/* 기본은 약 0.5rem 이상 */
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>등기부등본 확인매물 상세 내용</div>
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-2 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center w-100 justify-content-between card-header-tab">
<h4 class="mb-0 fw-bold text-dark">등기부등본 확인매물 상세 내용</h4>
<div class="d-flex align-items-center flex-nowrap gap-4 ms-auto" style="white-space:nowrap;">
<span class="text-muted me-2">매물번호:</span>
<span class="fw-bold text-primary fs-6 me-4"><?= $data['atcl_no'] ?></span>
<span class="text-muted me-2">CP ID:</span>
<span class="fw-bold text-primary fs-6 me-4"><?= $data['cpid'] ?></span>
<span class="text-muted me-2">현재 상태:</span>
<span class="fw-bold text-primary fs-6"><?= $data['pre_stat'] ?></span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="main-card mb-3 card">
<div class="card-body">
<form id="rcptFrm" name="rcptFrm" onsubmit="return false">
<input type="hidden" name="reg_chk_val" value="<?= $data['rgbk_confirm'] ?>" />
@@ -133,7 +169,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
} else {
foreach ($arrRegist as $row) {
$img_path = $row['file_path'] . $row['file_name'];
echo '<a href="' . $img_path . '" class="default_val" target="_blank" rel="lightbox[gallery1]">' .
echo '<a href="' . $img_path . '" class="glightbox" data-gallery="gallery1" data-title="등기부등본">' .
'<img id="photo-display2" src="' . $img_path . '" alt="Image" style="width:100%;max-width:945px;min-width:100%;border:0;" />' .
'</a>';
}
@@ -150,7 +186,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
echo '<img id="photo-display2" src="/img/photo.gif" alt="Image" style="width:100%;max-width:945px;min-width:100%;border:0;" />';
} else {
foreach ($arr_cert_register as $img_path) {
echo '<a href="' . $img_path . '" class="default_val" target="_blank" rel="lightbox[gallery1]">' .
echo '<a href="' . $img_path . '" class="glightbox" data-gallery="gallery1" data-title="등기부등본">' .
'<img id="photo-display2" src="' . $img_path . '" alt="Image" style="width:100%;max-width:945px;min-width:100%;border:0;" />' .
'</a>';
}
@@ -184,7 +220,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
<br>
<a href="<?= $regi_pdf_path ?>" class="default_val" target="_blank">등기부등본
보기</a>&nbsp;&nbsp;&nbsp;
<a href="<?= $reco_pdf_path ?>" class="default_val" target="_blank" rel="lightbox"
<a href="<?= $reco_pdf_path ?>" class="glightbox" data-gallery="hongbo" data-title="홍보확인서"
id="hongbo" onclick="chk_hongbo(event); return false;">홍보확인서 보기</a>
<?php
}
@@ -204,7 +240,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
<div class="card-body p-2">
<table class="table table-sm table-bordered mb-2 tbl_basic2 align-middle">
<colgroup>
<col style="width: 110px;">
<col style="width: 120px;">
<col>
</colgroup>
<tbody>
@@ -271,7 +307,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
<img id="reference" src="/img/zip.png"
alt="Image" /></a>
<?php } else { ?>
<a href="<?= $filePath ?>" rel="lightbox[gallery2]">
<a href="<?= $filePath ?>" class="glightbox" data-gallery="gallery2" data-title="참고파일">
<img id="reference" src="<?= $filePath ?>" alt="Image"
style="padding-right: 10px; height: 150px;" /></a>
<?php } ?>
@@ -294,8 +330,7 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
<?php } ?>
<?php } else { ?>
<?php foreach ($arr_reference as $row) { ?>
<a onclick="fn_preview('<?= esc($row) ?>')"
rel="lightbox[gallery2]">
<a href="<?= esc($row) ?>" class="glightbox" data-gallery="gallery2" data-title="참고파일">
<img id="reference" src="<?= $row ?>" alt="Image"
style="padding-right: 10px; height: 150px;" /></a>
<?php } ?>
@@ -1065,23 +1100,27 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
</div>
</div>
</div>
<div class="modal" id="previewModal" tabindex="-1">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">미리보기</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-0">
<img id="imgPreview" src="" alt="미리보기" width="100%" height="auto">
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('page_styles') ?>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/glightbox/dist/css/glightbox.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.jsdelivr.net/npm/glightbox/dist/js/glightbox.min.js"></script>
<script src="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone-min.js"></script>
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
$(function () {
// GLightbox 초기화
const lightbox = GLightbox({
touchNavigation: true,
loop: false,
autoplayVideos: true,
zoomable: true,
draggable: true
});
const reg_status = '<?= $data['reg_status'] ?>';
const filePdf = '<?= $file_pdf ?? '' ?>';
@@ -1792,20 +1831,6 @@ if (!empty($data['confirm_doc_img_url']) && $data['confirm_doc_img_url_save_yn']
});
}
// 이미지 프리뷰
function fn_preview(src) {
const $img = $('#imgPreview');
// 이미지 표시
$img.attr('src', src).show();
$('#previewTitle').text('이미지 미리보기');
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
</script>
<?= $this->endSection() ?>

View File

@@ -1,76 +1,35 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>등기부등본 확인매물현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">등기부등본 확인매물현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -102,7 +61,7 @@
<div class="d-flex gap-2">
<select name="charger_gbn" id="code_charger_gbn" class="form-select form-select-sm">
<option value="1">전화/서류담당자</option>
<option value="2" selected>등기부등본담당자</option>
<option value="2">등기부등본담당자</option>
</select>
<select name="assign_yn" id="assign_yn" class="form-select form-select-sm">
<option value="A">-전체-</option>
@@ -304,10 +263,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -316,10 +281,42 @@
const bonbuArr = <?= json_encode($bonbu, JSON_UNESCAPED_UNICODE); ?>;
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// 검색 조건 저장
function saveSearchForm() {
const data = $("#frm_srch_info").serializeArray();
localStorage.setItem("m705_search", JSON.stringify(data));
}
// 검색 조건 복원
function restoreSearchForm() {
const saved = localStorage.getItem("m705_search");
if (!saved) return;
const data = JSON.parse(saved);
data.forEach(function(item) {
$("[name='" + item.name + "']").val(item.value);
});
// 주요 select에 대해 change 이벤트 트리거
$("#srcSido, #srcGugun, #bonbu, #team").trigger("change");
}
$(function () {
// referrer에 '/m705'가 없으면 검색 조건 초기화
if (!document.referrer.includes('/m705')) {
localStorage.removeItem("m705_search");
}
restoreSearchForm();
// Bootstrap Tooltip 초기화 (빠른 표시)
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl, {
delay: { "show": 100, "hide": 100 }
})
})
$("#bonbu").on("change", function (e) {
@@ -573,6 +570,7 @@
});
$('#btnSearch').on('click', function () {
saveSearchForm();
table.ajax.reload()
});

View File

@@ -31,16 +31,23 @@ $usr_level = session('usr_level');
}
</style>
<div class="app-page-title">
<div class="page-title-wrapper">
<div class="page-title-heading">
<div>홍보확인서 상세 내용</div>
<div class="col-md-12 col-xl-12">
<div class="col-lg-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3">
<div class="flex-grow-1">
<h4 class="mb-0 fw-bold text-dark">홍보확인서 상세 내용</h4>
</div>
<div class="d-flex flex-wrap gap-3">
<div><span class="tit">매물ID:</span> <span class="num"><?= $data['atcl_no'] ?></span></div>
<div><span class="tit">CP ID:</span> <span class="num"><?= $article['cpid'] ?? '' ?></span></div>
<div><span class="tit">현재 상태:</span> <span class="num"><?= $article['current_stat'] ?? '' ?></span></div>
</div>
</div>
</div>
<div class="row">
<div class="col-12">
</div>
<div class="card-body">
<h5 class="card-title">팩스 이미지 및 기본 정보</h5>
<form action="" id="frmSave" name="frmSave" onsubmit="return false;">
<input type="hidden" name="work_type" id="work_type" value="<?= $data['work_type'] ?>" />
<input type="hidden" name="atcl_no" value="<?= $data['atcl_no'] ?>" />
@@ -48,16 +55,11 @@ $usr_level = session('usr_level');
<input type="hidden" name="fax_sq" id="fax_sq" value="<?= $data['fax_sq'] ?>" />
<input type="hidden" name="file_type" id="file_type" value="" />
</form>
<div class="main-card mb-3 card">
<?php if (($data['receiver'] ?? '') != "API"): ?>
<div class="card-header">
<div class="d-flex justify-content-start gap-1">
<div class="ms-auto d-flex gap-1">
<span class="ms-auto">
<div class="d-flex justify-content-end gap-1 mb-2">
<span>
발신번호 : <?= esc(str_replace('-', '', $data['caller_no'] ?? '')) ?>
</span>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(90)">90˚</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
@@ -65,10 +67,7 @@ $usr_level = session('usr_level');
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(270)">270˚</button>
</div>
</div>
</div>
<?php endif; ?>
<div class="card-body">
<!-- table 유지 + 반응형 -->
<div class="table-responsive">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0" style="min-width: 900px;">
@@ -132,7 +131,7 @@ $usr_level = session('usr_level');
<div class="card-body p-2">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0">
<colgroup>
<col style="width: 110px;">
<col style="width: 120px;">
<col>
</colgroup>
<tbody>

View File

@@ -1,6 +1,6 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<?= $this->section('page_styles') ?>
<style>
th {
font-size: 11px;
@@ -46,31 +46,38 @@
color: #fff !important;
}
</style>
<?= $this->endSection() ?>
<h1>홍보확인서 현황</h1>
<?= $this->section('content') ?>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">홍보확인서 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
<input type="hidden" name="todo" id="todo" value="inq" />
<input type="hidden" name="usr_id" value="" />
<!-- 안내 -->
<div class="alert alert-warning py-2 mb-3">
<small class="mb-0">
매물번호 또는 발신팩스번호를 입력하면 <b>다른 조건은 무시</b>됩니다.
</small>
</div>
<!-- 검색 폼 -->
<div class="row g-3">
<!-- 매물번호 -->
<div class="col-md-1">
<label class="form-label mb-1">매물번호</label>
<label class="form-label mb-1">
매물번호
<i class="pe-7s-info info-tooltip" data-bs-toggle="tooltip" data-bs-placement="top"
title="매물번호를 입력하면 다른 조건은 무시됩니다"></i>
</label>
<input type="text" name="atcl_no" class="form-control form-control-sm" placeholder="매물번호" maxlength="10"
data-bs-toggle="tooltip" data-bs-placement="top" title="매물번호를 입력하면 다른 조건은 무시됩니다"
onkeypress="atcl_no_enter(event)">
</div>
@@ -292,12 +299,12 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<?= $this->section('page_scripts') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
const date = new Date();
@@ -305,11 +312,21 @@
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codeArr = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
});
// localStorage에서 검색 조건 복원
restoreFormData();
$("#bonbu").on("change", function (e) {
const value = e.target.value
@@ -561,6 +578,7 @@
});
$('#btnSearch').on('click', function () {
saveFormData();
table.ajax.reload()
});
@@ -770,5 +788,29 @@
return str;
}
// localStorage에 검색 조건 저장
function saveFormData() {
const formData = $('#frm_srch_info').serializeArray();
const formObject = {};
formData.forEach(item => {
formObject[item.name] = item.value;
});
localStorage.setItem('m708_search_form', JSON.stringify(formObject));
}
// localStorage에서 검색 조건 복원
function restoreFormData() {
const savedData = localStorage.getItem('m708_search_form');
if (savedData) {
const formObject = JSON.parse(savedData);
Object.keys(formObject).forEach(key => {
const $element = $('#frm_srch_info').find(`[name="${key}"]`);
if ($element.length) {
$element.val(formObject[key]);
}
});
}
}
</script>
<?= $this->endSection() ?>

View File

@@ -50,20 +50,13 @@ $usr_level = session('usr_level');
</form>
<div class="main-card mb-3 card">
<?php if (($data['receiver'] ?? '') != "API"): ?>
<div class="card-header">
<div class="d-flex justify-content-start gap-1">
<div class="ms-auto d-flex gap-1">
<span class="ms-auto">
발신번호 : <?= esc(str_replace('-', '', $data['caller_no'] ?? '')) ?>
</span>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(90)">90˚</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(180)">180˚</button>
<button type="button" class="btn btn-sm btn-outline-secondary"
onclick="faximage_rotate(270)">270˚</button>
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3">
<div class="flex-grow-1">
<h4 class="mb-0 fw-bold text-dark">홍보확인서 상세 내용</h4>
</div>
<div class="d-flex flex-wrap gap-3">
<div><span class="tit">발신번호:</span> <span class="num"><?= esc(str_replace('-', '', $data['caller_no'] ?? '')) ?></span></div>
</div>
</div>
</div>
@@ -73,8 +66,8 @@ $usr_level = session('usr_level');
<div class="table-responsive">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0" style="min-width: 900px;">
<colgroup>
<col style="width: 60%;">
<col style="width: 40%;">
<col style="width:120px">
<col style="width:120px">
</colgroup>
<tbody>
@@ -120,7 +113,7 @@ $usr_level = session('usr_level');
<!-- 1) 요약/조회 + 액션 -->
<div class="main-card mb-3 card">
<div class="card-header">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex align-items-center w-100">
<span class="fw-semibold">기본 정보</span>
<div class="ms-auto">
@@ -132,7 +125,7 @@ $usr_level = session('usr_level');
<div class="card-body p-2">
<table class="table table-bordered table-sm tbl_basic2 align-middle mb-0">
<colgroup>
<col style="width: 110px;">
<col style="width:120px">
<col>
</colgroup>
<tbody>

View File

@@ -1,56 +1,17 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>모바일 추가 서류</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">모바일 추가 서류</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
@@ -292,10 +253,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.bootstrap5.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -305,11 +272,21 @@
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codeArr = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// localStorage에서 검색 조건 복원
restoreFormData();
$("#bonbu").on("change", function (e) {
const value = e.target.value
@@ -561,6 +538,7 @@
});
$('#btnSearch').on('click', function () {
saveFormData();
table.ajax.reload()
});
@@ -770,5 +748,29 @@
return str;
}
// localStorage에 검색 조건 저장
function saveFormData() {
const formData = $('#frm_srch_info').serializeArray();
const formObject = {};
formData.forEach(item => {
formObject[item.name] = item.value;
});
localStorage.setItem('m709_search_form', JSON.stringify(formObject));
}
// localStorage에서 검색 조건 복원
function restoreFormData() {
const savedData = localStorage.getItem('m709_search_form');
if (savedData) {
const formObject = JSON.parse(savedData);
Object.keys(formObject).forEach(key => {
const $element = $('#frm_srch_info').find(`[name="${key}"]`);
if ($element.length) {
$element.val(formObject[key]);
}
});
}
}
</script>
<?= $this->endSection() ?>

View File

@@ -1,35 +1,17 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#aptList tbody tr {
cursor: pointer;
}
.blockUI {
z-index: 1500 !important;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>모바일 자동검증</h1>
<div class="row">
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">모바일 자동검증</h4>
</div>
</div>
</div>
<div class="card-body">
<form class="row align-items-end" id="frm_srch_info" onsubmit="return false;">
@@ -88,9 +70,56 @@
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.bootstrap5.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript">
const codes = [];
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// localStorage에서 검색 조건 복원
restoreFormData();
});
// localStorage에 검색 조건 저장
function saveFormData() {
const formData = $('#frm_srch_info').serializeArray();
const formObject = {};
formData.forEach(item => {
formObject[item.name] = item.value;
});
localStorage.setItem('m711_search_form', JSON.stringify(formObject));
}
// localStorage에서 검색 조건 복원
function restoreFormData() {
const savedData = localStorage.getItem('m711_search_form');
if (savedData) {
const formObject = JSON.parse(savedData);
Object.keys(formObject).forEach(key => {
const $element = $('#frm_srch_info').find(`[name="${key}"]`);
if ($element.length) {
$element.val(formObject[key]);
}
});
}
}
</script>
<?= $this->endSection() ?>

View File

@@ -1,56 +1,17 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>신홍보확인서 현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">신홍보확인서 현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
@@ -288,10 +249,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.bootstrap5.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -300,11 +267,21 @@
const bonbuArr = <?= json_encode($bonbu, JSON_UNESCAPED_UNICODE); ?>;
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// localStorage에서 검색 조건 복원
restoreFormData();
$("#bonbu").on("change", function (e) {
const value = e.target.value

View File

@@ -1,56 +1,17 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
td {
text-align: center;
}
#resultList tbody tr {
cursor: pointer;
font-size: 12px;
}
.blockUI {
z-index: 1500 !important;
}
.ellipsis {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 180px;
}
.card-header {
display: flex !important;
align-items: center;
}
.card-header-tab {
justify-content: flex-start !important;
}
.table-scroll {
max-height: 300px;
overflow-y: scroll;
}
.swal2-cancel {
background-color: #ff0000 !important;
color: #fff !important;
}
</style>
<h1>모바일확인V2 매물현황</h1>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header bg-white border-bottom shadow-sm">
<div class="d-flex flex-wrap align-items-center gap-3 card-header-tab">
<div>
<h4 class="mb-0 fw-bold text-dark">모바일확인V2 매물현황</h4>
</div>
</div>
</div>
<div class="card-body">
<form id="frm_srch_info" method="get" onsubmit="return false;">
<input type="hidden" name="m" id="m" value="M801" />
@@ -263,10 +224,16 @@
</form>
</div>
</div>
</div>
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-body">
<div class="d-flex justify-content-end mb-3">
<button class="btn btn-sm btn-outline-success" id="excel-download">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
엑셀다운로드
</button>
</div>
<table id="resultList" class="table table-hover table-striped table-bordered">
<div class="card-header d-flex align-items-center">
<div class="d-flex align-items-center flex-wrap" style="gap: 8px; flex: 1">
@@ -306,10 +273,16 @@
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<?= $this->section('page_styles') ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.bootstrap5.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -318,11 +291,21 @@
const bonbuArr = <?= json_encode($bonbu, JSON_UNESCAPED_UNICODE); ?>;
const teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
const userArr = <?= json_encode($user, JSON_UNESCAPED_UNICODE); ?>;
const codes = <?= json_encode($codes, JSON_UNESCAPED_UNICODE); ?>;
var table;
$(function () {
// Bootstrap tooltip 초기화
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'))
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl)
});
// localStorage에서 검색 조건 복원
restoreFormData();
$("#bonbu").on("change", function (e) {
const value = e.target.value
@@ -574,6 +557,7 @@
});
$('#btnSearch').on('click', function () {
saveFormData(); // 검색 조건 저장
table.ajax.reload()
});
@@ -735,5 +719,29 @@
const modal = new bootstrap.Modal(document.getElementById('previewModal'));
modal.show();
}
// localStorage에 검색 조건 저장
function saveFormData() {
const formData = $('#frm_srch_info').serializeArray();
const formObject = {};
formData.forEach(item => {
formObject[item.name] = item.value;
});
localStorage.setItem('m713_search_form', JSON.stringify(formObject));
}
// localStorage에서 검색 조건 복원
function restoreFormData() {
const savedData = localStorage.getItem('m713_search_form');
if (savedData) {
const formObject = JSON.parse(savedData);
Object.keys(formObject).forEach(key => {
const $element = $('#frm_srch_info').find(`[name="${key}"]`);
if ($element.length) {
$element.val(formObject[key]);
}
});
}
}
</script>
<?= $this->endSection() ?>

8
check_watermark.sql Normal file
View File

@@ -0,0 +1,8 @@
-- watermark 테이블 데이터 확인
SELECT * FROM watermark;
-- 특정 cpid의 워터마크 확인 (cpid를 실제 값으로 변경)
SELECT * FROM watermark WHERE cpid = 'YOUR_CPID';
-- receipt 테이블에서 comp_sq 확인
SELECT rcpt_sq, rcpt_cpid, comp_sq FROM receipt LIMIT 10;

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
img/watermark/KAB_TYPE1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
img/watermark/KAB_TYPE2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

BIN
img/watermark/KAB_TYPE3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
img/watermark/LEE_TYPE1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
img/watermark/LEE_TYPE2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
img/watermark/LEE_TYPE3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Some files were not shown because too many files have changed in this diff Show More