Compare commits

..

69 Commits

Author SHA1 Message Date
f8c26acea8 워커 수정 2026-04-27 15:03:36 +09:00
b0ec75ae56 트랜젝션 실패시 처리 2026-04-08 20:13:25 +09:00
a87fed538b json_encode 에러 날때 exception 처리 2026-04-07 16:03:53 +09:00
cbf7e85cf8 헤더 2026-04-07 15:58:24 +09:00
6a72ccebd5 공통화 작업 및 워커 해더 2026-04-07 15:39:41 +09:00
cba387de9d // 1. 응답 헤더 설정 (JSON)
header('Content-Type: application/json; charset=utf-8');

제거
2026-03-27 11:52:38 +09:00
930e690126 수정 2026-03-26 21:06:31 +09:00
0ef2ba77c6 현장확인 매물검증 결과관리 - 매물 입력시 제외 2026-03-26 18:17:53 +09:00
c22b023310 로그 리스트 항목 생성 2026-03-26 11:36:21 +09:00
0b6ed3df73 worker service 매물 등록 및 redis 다운시 처리 2026-03-25 20:51:38 +09:00
a170fdc774 다시 수정 2026-03-25 15:59:05 +09:00
e5a80aff33 세션 패스 수정 2026-03-25 15:52:13 +09:00
7139e0c095 세션 처리 2026-03-25 13:14:42 +09:00
129e2b4e69 왜 안되지? 2026-03-24 19:31:40 +09:00
fd187bb84a jenkins 테스트 2026-03-24 19:29:39 +09:00
3fbc57bedc jenkins 테스트 2026-03-24 19:26:39 +09:00
81b85ae25d redis connect 수정 2026-03-24 19:11:19 +09:00
e2f49ba77e redis 연결 수정 2026-03-24 18:56:01 +09:00
728b394063 api 주소 변경 2026-03-20 16:32:51 +09:00
1f445512f7 처리가능 수량관리 수정 2026-03-20 13:35:55 +09:00
b553310dc1 테스트 파일 삭제 2026-03-20 11:32:46 +09:00
bb07396abf 로그 생성이 안되어 테스트 및 수정본 2026-03-20 09:33:30 +09:00
80cb9451d2 result 입력시 usr_sq dept_sq 를 region_codes 에서 가져오는 로직 넣기 2026-03-18 16:59:16 +09:00
9138fa9c16 redis 설정 변경 2026-03-18 14:33:17 +09:00
a6ae1bd377 로그 생성 수정 2026-03-11 17:25:45 +09:00
6bb9dceec9 오류 처리 2026-03-11 15:51:17 +09:00
32efe755e6 호출시 정보 저장 2026-03-11 09:55:11 +09:00
141f526f91 수정 2026-03-10 19:38:13 +09:00
9650707caf 수정 본 2026-03-10 18:57:09 +09:00
13dfb3e112 현장확인 화면 및 기능 수정 2026-03-05 21:00:40 +09:00
9d9df394c5 현장확인매물 상세 페이지 기능 수정 2026-03-05 18:17:31 +09:00
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
yangsh
6d87a209e0 링크이동 수정
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-02-09 14:32:54 +09:00
f6857ae959 링크이동 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/56
2026-02-09 11:00:52 +09:00
yangsh
a7dca8c5fa 링크이동 수정
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-02-09 11:00:15 +09:00
98d74658e9 사이드메뉴 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/55
2026-02-09 09:49:55 +09:00
yangsh
9a27018922 사이드메뉴 수정
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-02-09 09:49:08 +09:00
922c85962c 현장확인 수정
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/54
2026-02-06 10:39:16 +09:00
yangsh
8b621a065e 현장확인 수정
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-02-06 10:38:18 +09:00
53695a1dc3 Merge pull request 'feature/template' (#53) from feature/template into master
Reviewed-on: http://192.168.10.243:3000/owrainfo/confirms/pulls/53
2026-02-05 15:08:43 +09:00
yangsh
d92bbfef1a 713수정
Some checks failed
Close Pull Request / main (pull_request_target) Has been cancelled
2026-02-05 15:08:05 +09:00
yangsh
4a8178b185 상세수정 2026-02-05 14:09:49 +09:00
239 changed files with 18934 additions and 9646 deletions

2
.gitignore vendored
View File

@@ -175,4 +175,4 @@ _modules/*
# 6. 기타 개인 설정 파일 (선택적)
.github/copilot-instructions.md
.github/copilot-instructions.mdworker/fallback_queue/*.json

1
README
View File

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

360
SESSION_README.md Normal file
View File

@@ -0,0 +1,360 @@
# Session 관리 가이드
## 개요
본 애플리케이션은 **Redis**를 기본 세션 저장소로 사용하며, Redis 장애 시 **Database(MariaDB)**로 자동 폴백하는 이중화 구조를 가지고 있습니다.
## 아키텍처
### 세션 저장소
| 우선순위 | 핸들러 | 설명 | 성능 |
|---------|-------|------|------|
| 1순위 | **RedisHandler** | 메모리 기반 고속 세션 | ~0.03초 |
| 2순위 | **DatabaseHandler** | DB 기반 안정적 세션 | ~0.05초 (수동 전환 시) |
### 구성 요소
```
┌─────────────────────────────────────────┐
│ 사용자 로그인 요청 │
└──────────────┬──────────────────────────┘
┌─────────────────────────────────────────┐
│ Session.php 생성자 │
│ - Redis 연결 테스트 │
│ - SESSION_FORCE_DATABASE 확인 │
└──────────────┬──────────────────────────┘
┌──────┴──────┐
│ │
Redis 정상? Redis 장애?
│ │
▼ ▼
RedisHandler DatabaseHandler
(ci_sessions (ci_sessions
테이블) 테이블)
│ │
└──────┬──────┘
세션 데이터 저장/조회
```
## 설정 파일
### 1. Session.php (`src/app/Config/Session.php`)
```php
public string $driver = RedisHandler::class;
public function __construct()
{
// 환경변수로 강제 Database 모드 설정 가능
$forceDatabase = env('SESSION_FORCE_DATABASE', false);
if ($this->driver === RedisHandler::class && !$forceDatabase) {
try {
// Redis 연결 테스트 (타임아웃: 0.5초)
$testRedis = get_redis_connection('session');
if (!$testRedis) {
throw new \Exception('Redis connection failed');
}
// Redis 정상 - Redis 사용
$this->savePath = 'tcp://192.168.10.243:6379?database=0';
} catch (\Exception $e) {
// Redis 실패 - DatabaseHandler로 폴백
$this->driver = DatabaseHandler::class;
$this->savePath = 'ci_sessions';
}
} else {
// Database 모드
$this->savePath = 'ci_sessions';
}
}
```
### 2. 환경 설정 (`.env`)
```bash
# Redis 세션 설정
SESSION_REDIS_HOST = 192.168.10.243
SESSION_REDIS_PORT = 6379
SESSION_REDIS_DATABASE = 0
#SESSION_REDIS_PASSWORD =
# 세션 강제 Database 모드 (Redis 장애 시 true로 변경)
SESSION_FORCE_DATABASE = false
```
### 3. Redis Helper (`src/app/Helpers/redis_helper.php`)
```php
function get_redis_connection(string $type = 'worker')
{
$redis = new \Redis();
// 타임아웃 0.5초로 빠른 실패 감지
$timeout = 0.5;
$success = $redis->connect($host, $port, $timeout);
return $success ? $redis : false;
}
```
## 데이터베이스 테이블
### ci_sessions 테이블 구조
```sql
CREATE TABLE `ci_sessions` (
`session_id` VARCHAR(40) NOT NULL DEFAULT '0',
`ip_address` VARCHAR(16) NOT NULL DEFAULT '0',
`user_agent` VARCHAR(120) NOT NULL,
`last_activity` INT UNSIGNED NOT NULL DEFAULT 0,
`user_data` VARCHAR(4000) NOT NULL,
PRIMARY KEY (`session_id`)
) ENGINE = MEMORY;
CREATE INDEX `last_activity_idx`
ON `ci_sessions` (`last_activity` ASC);
```
**주요 특징:**
- **ENGINE = MEMORY**: 메모리 기반 테이블로 매우 빠른 읽기/쓰기 성능
- **장점**: Redis와 비슷한 속도 (디스크 I/O 없음)
- **단점**: 서버 재시작 시 세션 데이터 소실 (일반적으로 문제없음 - 세션은 휘발성 데이터)
- **용량**: VARCHAR(4000)으로 충분한 세션 데이터 저장 가능
## 운영 가이드
### 1. Redis 장애 발생 시
#### 자동 폴백 (기본 동작)
- Redis 연결 실패 시 자동으로 DatabaseHandler로 전환
- **단점**: 매 요청마다 Redis 연결 시도 → 타임아웃 대기 (약 0.5초 추가)
- 사용자는 약간 느린 응답 시간을 경험
#### 수동 전환 (권장)
Redis 장애 감지 즉시 다음 조치:
```bash
# 1. .env 파일 수정
vi /path/to/src/.env
# SESSION_FORCE_DATABASE를 true로 변경
SESSION_FORCE_DATABASE = true
# 2. PHP-FPM 재시작 (선택사항, 다음 요청부터 자동 적용)
docker exec projects-admin_confirms kill -USR2 1
```
**장점**: Redis 연결 시도 없이 즉시 Database 사용 → 빠른 응답 (0.05초)
### 2. Redis 복구 후
```bash
# 1. .env 파일 원복
SESSION_FORCE_DATABASE = false
# 2. PHP-FPM 재시작
docker exec projects-admin_confirms kill -USR2 1
```
### 3. 모니터링
#### 로그 확인
```bash
# 세션 관련 로그 확인
docker exec projects-admin_confirms tail -f /var/www/html/writable/logs/log-$(date +%Y-%m-%d).log | grep -i session
# Redis 폴백 경고 확인
docker exec projects-admin_confirms grep "Redis unavailable" /var/www/html/writable/logs/log-$(date +%Y-%m-%d).log
```
#### 예상 로그 메시지
**Redis 정상:**
```
DEBUG - Session: Class initialized using 'CodeIgniter\Session\Handlers\RedisHandler' driver.
```
**Redis 장애 (자동 폴백):**
```
WARNING - Session: Redis unavailable (Redis connection failed), falling back to DatabaseHandler
DEBUG - Session: Class initialized using 'CodeIgniter\Session\Handlers\DatabaseHandler' driver.
```
**Database 강제 모드:**
```
INFO - Session: Forced to use DatabaseHandler (SESSION_FORCE_DATABASE=true)
DEBUG - Session: Class initialized using 'CodeIgniter\Session\Handlers\DatabaseHandler' driver.
```
### 4. 성능 모니터링
```bash
# 로그인 응답 시간 측정
for i in {1..5}; do
curl -X POST http://localtest2-admin.confirms.co.kr/login/chkLogin \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "user_id=test&user_pw=test" \
-o /dev/null -s -w " Time: %{time_total}s\n"
done
```
**기대 성능:**
- Redis 정상: 0.03 ~ 0.05초
- Database (수동 전환): 0.05 ~ 0.08초
- 자동 폴백 (Redis 다운): 0.5 ~ 1.0초
## 사용자 알림
### 프론트엔드 경고 표시
Redis 장애 시 로그인 페이지에 자동으로 경고 배너가 표시됩니다:
```javascript
// login.php의 JavaScript
function checkSystemStatus(responseData) {
if (responseData.system && responseData.system.redis_fallback) {
// 경고 메시지: "세션 서버(Redis) 장애로 임시 모드로 운영 중입니다."
showRedisWarning(responseData.system.warning_message);
}
}
```
**API 응답 예시:**
```json
{
"code": "0",
"msg": "success",
"system": {
"redis_fallback": true,
"warning_message": "세션 서버(Redis) 장애로 임시 모드로 운영 중입니다. 시스템 관리자에게 문의하세요."
}
}
```
## 트러블슈팅
### 문제: 로그인이 느림 (2~3초)
**원인**: Redis 다운 상태에서 자동 폴백 모드 사용 중
**해결**:
```bash
# SESSION_FORCE_DATABASE=true로 수동 전환
echo "SESSION_FORCE_DATABASE = true" >> /path/to/src/.env
```
### 문제: 세션이 유지되지 않음
**원인**: ci_sessions 테이블이 없거나 권한 문제
**해결**:
```sql
-- 테이블 존재 확인
SHOW TABLES LIKE 'ci_sessions';
-- 권한 확인
SHOW GRANTS FOR 'confirms'@'%';
-- 테이블이 없는 경우 생성
CREATE TABLE `ci_sessions` (
`session_id` VARCHAR(40) NOT NULL DEFAULT '0',
`ip_address` VARCHAR(16) NOT NULL DEFAULT '0',
`user_agent` VARCHAR(120) NOT NULL,
`last_activity` INT UNSIGNED NOT NULL DEFAULT 0,
`user_data` VARCHAR(4000) NOT NULL,
PRIMARY KEY (`session_id`)
) ENGINE = MEMORY;
CREATE INDEX `last_activity_idx`
ON `ci_sessions` (`last_activity` ASC);
```
### 문제: 서버 재시작 후 모든 세션이 사라짐
**원인**: ci_sessions가 MEMORY 엔진을 사용 (정상 동작)
**설명**:
- MEMORY 엔진은 서버 재시작 시 데이터가 삭제됩니다
- 세션은 일시적 데이터이므로 일반적으로 문제가 되지 않습니다
- 사용자는 재로그인하면 됩니다
**영구 저장이 필요한 경우**:
```sql
-- InnoDB로 변경 (성능은 약간 느려짐)
ALTER TABLE ci_sessions ENGINE=InnoDB;
```
### 문제: Redis 연결 타임아웃이 너무 김
**원인**: redis_helper.php의 타임아웃 설정
**해결**:
```php
// src/app/Helpers/redis_helper.php
$timeout = 0.5; // 0.1 ~ 1.0 사이 값으로 조정
$redis->connect($host, $port, $timeout);
```
## 관련 파일
| 파일 | 역할 |
|------|------|
| `src/app/Config/Session.php` | 세션 설정 및 폴백 로직 |
| `src/app/Helpers/redis_helper.php` | Redis 연결 헬퍼 함수 |
| `src/app/Controllers/Login.php` | 로그인 및 시스템 상태 체크 |
| `src/app/Views/pages/login.php` | 프론트엔드 경고 표시 |
| `src/.env` | 환경 설정 (Redis 연결 정보, 강제 모드) |
## Worker 및 API (참고)
### Worker (NaverWorker.php)
- Redis 큐 사용 (DB 9)
- Redis 장애 시 파일 기반 폴백 (`worker/fallback_queue/*.json`)
### API (api_receiver.php, KisoController.php)
- Redis 큐 사용 (DB 9)
- Redis 장애 시 파일 기반 폴백 (`worker/fallback_queue/*.json`)
## 추가 개선 사항
### 고려 중인 기능
1. **Redis Sentinel 도입** (고가용성)
- 자동 장애 조치
- 마스터/슬레이브 구조
2. **APM 연동**
- New Relic, DataDog 등
- 실시간 성능 모니터링
3. **헬스체크 엔드포인트**
```php
// GET /health/session
{
"status": "ok",
"driver": "RedisHandler",
"redis_available": true,
"response_time_ms": 12
}
```
## 문의
세션 관련 문제 발생 시:
1. 로그 확인 (`/writable/logs/`)
2. Redis 서버 상태 확인
3. ci_sessions 테이블 상태 확인
4. 필요 시 수동 전환 수행
---
**Last Updated**: 2026-03-25
**Version**: 1.0.0

209
app/Commands/NaverRetry.php Normal file
View File

@@ -0,0 +1,209 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
use App\Models\Entities\NaverWorkerLogModel;
class NaverRetry extends BaseCommand
{
protected $group = 'Workers';
protected $name = 'naver:retry';
protected $description = '실패한 Naver Worker 작업을 재처리합니다.';
protected $usage = 'naver:retry [log_id] [options]';
protected $arguments = [
'log_id' => '재처리할 특정 로그 ID (선택사항, 없으면 모든 실패 건 재처리)'
];
protected $options = [
'--limit' => '재처리할 최대 개수 (기본: 10)',
'--dry-run' => '실제 실행 없이 목록만 확인',
'--force' => '재시도 횟수 제한 무시 (3회 이상 실패한 건도 재처리)'
];
public function run(array $params)
{
helper(['log']);
$logId = $params[0] ?? null;
$limit = CLI::getOption('limit') ?? 10;
$isDryRun = CLI::getOption('dry-run') !== null;
$isForce = CLI::getOption('force') !== null;
$logModel = model(NaverWorkerLogModel::class);
$naverService = new \App\Services\NaverService();
// 1. 특정 ID 재처리
if ($logId) {
$this->retryOne($logModel, $naverService, $logId, $isDryRun, $isForce);
return;
}
// 2. 실패한 모든 작업 재처리
$this->retryFailed($logModel, $naverService, $limit, $isDryRun, $isForce);
}
/**
* 특정 로그 ID 재처리
*/
protected function retryOne($logModel, $naverService, $logId, $isDryRun, $isForce)
{
$log = $logModel->find($logId);
if (!$log) {
CLI::error("❌ Log ID {$logId} not found");
return;
}
CLI::write(CLI::color("📋 Log ID: {$logId}", 'cyan'));
CLI::write(" Status: {$log['status']}");
CLI::write(" Retry Count: " . ($log['retry_cnt'] ?? 0));
CLI::write(" Error: {$log['error_msg']}");
CLI::write(" Created: {$log['created_at']}");
// 재시도 횟수 체크
if (!$isForce && ($log['retry_cnt'] ?? 0) >= 3) {
CLI::write(CLI::color('⚠️ 이미 3회 이상 재시도했습니다. --force 옵션으로 강제 실행 가능', 'yellow'));
return;
}
// 재시도 불가능한 오류 체크
if (!$isForce && $this->isNonRetryableError($log['error_msg'])) {
CLI::write(CLI::color('⚠️ 재시도 불가능한 오류입니다. 데이터를 먼저 수정해주세요.', 'yellow'));
CLI::write(CLI::color(' (--force 옵션으로 강제 실행 가능)', 'yellow'));
return;
}
if ($isDryRun) {
CLI::write(CLI::color('🔍 DRY RUN - 재처리하지 않음', 'yellow'));
return;
}
$this->processLog($logModel, $naverService, $log);
}
/**
* 재시도 불가능한 오류인지 확인
*/
protected function isNonRetryableError($errorMsg)
{
if (!$errorMsg) return false;
// 데이터 수정이 필요한 오류 패턴
$nonRetryablePatterns = [
'foreign key constraint',
'Duplicate entry',
'빈 페이로드',
'usr_sq.*users 테이블에 없음', // 이미 폴백 적용된 건은 재시도 가능
];
foreach ($nonRetryablePatterns as $pattern) {
if (stripos($errorMsg, $pattern) !== false) {
return true;
}
}
return false;
}
/**
* 실패한 모든 작업 재처리
*/
protected function retryFailed($logModel, $naverService, $limit, $isDryRun, $isForce)
{
$query = $logModel->where('status', 'FAIL');
// force가 아닌 경우 재시도 횟수 3회 미만만 조회
if (!$isForce) {
$query->groupStart()
->where('retry_cnt IS NULL')
->orWhere('retry_cnt <', 3)
->groupEnd();
}
$failedLogs = $query->orderBy('created_at', 'ASC')->findAll($limit);
if (empty($failedLogs)) {
CLI::write(CLI::color('✅ 재처리할 실패 작업이 없습니다.', 'green'));
return;
}
CLI::write(CLI::color("📋 실패한 작업 {count}건 발견", 'cyan')
->replace('{count}', count($failedLogs)));
if ($isDryRun) {
foreach ($failedLogs as $log) {
CLI::write(" - ID: {$log['seq']} | Atcl: {$log['atcl_no']} | Error: {$log['error_msg']}");
}
CLI::write(CLI::color('🔍 DRY RUN - 재처리하지 않음', 'yellow'));
return;
}
// 실제 재처리
$successCount = 0;
$failCount = 0;
foreach ($failedLogs as $log) {
CLI::write(CLI::color("\n🔄 Retrying Log ID: {$log['seq']}", 'yellow'));
$result = $this->processLog($logModel, $naverService, $log);
if ($result) {
$successCount++;
} else {
$failCount++;
}
// 과부하 방지
sleep(1);
}
CLI::write(CLI::color("\n✅ 재처리 완료: 성공 {$successCount}건, 실패 {$failCount}", 'green'));
}
/**
* 로그 데이터 재처리
*/
protected function processLog($logModel, $naverService, $log)
{
try {
// 상태를 RETRY로 변경
$logModel->update($log['seq'], ['status' => 'RETRY']);
// JSON 파싱
$responseJson = json_decode($log['raw_payload'], true);
$payload = $responseJson['request_data'] ?? [];
if (empty($payload)) {
throw new \Exception("빈 페이로드 데이터");
}
CLI::write(" Article: {$payload['articleNumber']}");
// 재처리
$insertId = $naverService->processArticle($payload);
// 성공 시 로그 업데이트
$logModel->update($log['seq'], [
'atcl_no' => $payload['articleNumber'] ?? null,
'status' => 'SUCCESS',
'target_db_id' => $insertId,
'error_msg' => null
]);
CLI::write(CLI::color(" ✅ Success! DB ID: {$insertId}", 'green'));
return true;
} catch (\Exception $e) {
// 실패 시 로그 업데이트
$logModel->update($log['seq'], [
'status' => 'FAIL',
'error_msg' => $e->getMessage()
]);
CLI::error(" ❌ Failed: " . $e->getMessage());
return false;
}
}
}

View File

@@ -17,57 +17,125 @@ class NaverWorker extends BaseCommand
// DB 객체를 담을 변수 선언
protected $db;
protected $redisHost;
protected $redisPort;
protected $redisDatabase;
public function run(array $params)
{
helper('log'); // 여기서 로드 완료!
helper(['log', 'redis']); // redis helper 추가
$this->db = \Config\Database::connect();
// 워커 시작 시점에 선제적으로 연결 상태를 보정
try {
$this->db->initialize();
} catch (\Throwable $e) {
CLI::error('Database connection init failed: ' . $e->getMessage());
}
$logModel = model(NaverWorkerLogModel::class);
$naverService = new \App\Services\NaverService(); // 서비스 생성
$redis = new \Redis();
try {
$redis->connect('redis', 6379);
$redis->select(9);
CLI::write(CLI::color('🟢 Naver Worker running...', 'green'));
} catch (\Exception $e) {
CLI::error("Redis 연결 불가: " . $e->getMessage());
return;
// Redis 연결 (실패해도 계속 진행 - 파일 모드로 동작 가능)
$redis = get_redis_connection('worker');
$config = get_redis_config('worker');
if ($redis) {
CLI::write(CLI::color('🟢 Naver Worker running... (Redis: ' . $config['host'] . ':' . $config['port'] . ' DB:' . $config['database'] . ')', 'green'));
} else {
CLI::write(CLI::color('⚠️ Naver Worker running in FILE-ONLY mode (Redis unavailable)', 'yellow'));
}
while (true) {
// 1. DB 연결 상태 체크 (더 견고하게)
// Redis 또는 폴백 파일에서 데이터 읽기
$rawData = null;
$source = 'redis'; // 데이터 소스 추적
// 1. Redis에서 데이터 읽기 시도 (Redis가 있을 경우만)
if ($redis) {
$maxRetries = 2;
$retryCount = 0;
while ($retryCount < $maxRetries) {
try {
if ($this->db->connID === false || !@$this->db->connID->ping()) {
$this->db->reconnect();
CLI::write(CLI::color('🔄 Database reconnected.', 'yellow'));
$result = $redis->brPop(['naver:raw_queue'], 5); // 5초 타임아웃
if ($result) {
$rawData = $result[1];
$source = 'redis';
}
} catch (\Throwable $e) {
$this->db->reconnect();
break; // 성공하면 루프 탈출
} catch (\Exception $e) {
$retryCount++;
CLI::write(CLI::color("⚠️ Redis error (attempt {$retryCount}/{$maxRetries}): " . $e->getMessage(), 'yellow'));
if ($retryCount >= $maxRetries) {
CLI::write(CLI::color("⚠️ Redis unavailable, switching to file mode", 'yellow'));
$redis = null; // Redis를 비활성화
break;
}
$result = $redis->brPop(['naver:raw_queue'], 30);
// Redis 재연결 시도
try {
CLI::write(CLI::color('🔄 Reconnecting to Redis...', 'yellow'));
$redis->close();
$redis = get_redis_connection('worker');
if ($redis) {
CLI::write(CLI::color('✅ Redis reconnected', 'green'));
}
} catch (\Exception $reconnectError) {
CLI::error("Redis reconnection error: " . $reconnectError->getMessage());
}
}
}
}
if (!$result) {
// 데이터가 없어서 타임아웃 난 경우.
// 굳이 sleep 안 해도 바로 다음 brPop이 다시 30초 대기를 시작함.
// 2. Redis에서 데이터 없으면 폴백 파일 확인
if (!$rawData) {
$rawData = $this->readFromFallbackFile();
if ($rawData) {
$source = 'file';
}
}
// 3. 데이터 없으면 다음 루프
if (!$rawData) {
continue;
}
if ($result) {
$rawData = $result[1];
// [1] 꺼내자마자 DB에 원문 저장 (2차 임시 저장)
// 4. 데이터 소스 로깅
CLI::write(CLI::color("📥 Data received from: " . strtoupper($source), 'cyan'));
// [1] 꺼내자마자 DB에 원문 저장 (2차 임시 저장) - 실패 시 재시도
try {
$logId = $logModel->insert([
'raw_payload' => $rawData,
'status' => 'INIT'
]);
} catch (\Throwable $e) {
// MySQL 연결 계열 에러 시 재연결 후 재시도
if ($this->isMySqlConnectionError($e)) {
CLI::write(CLI::color('⚠️ MySQL gone away, reconnecting...', 'yellow'));
$this->db->close();
$this->db = \Config\Database::connect();
$this->db->initialize();
$logModel = model(NaverWorkerLogModel::class);
// 재시도
$logId = $logModel->insert([
'raw_payload' => $rawData,
'status' => 'INIT'
]);
} else {
throw $e; // 다른 에러면 그대로 throw
}
}
try {
$responseJson = json_decode($result[1], true);
$responseJson = json_decode($rawData, true);
$payload = $responseJson['request_data'] ?? [];
if (empty($payload)) {
@@ -77,23 +145,48 @@ class NaverWorker extends BaseCommand
// 서비스의 함수 하나로 모든 처리 완료
$insertId = $naverService->processArticle($payload);
// [3] 성공 시 로그 업데이트
$logModel->update($logId, [
// [3] 성공 시 로그 업데이트 (재연결 처리 포함)
$this->safeUpdateLog($logModel, $logId, [
'atcl_no' => $payload['articleNumber'] ?? null,
'status' => 'SUCCESS',
'target_db_id' => $insertId
]);
CLI::write("✅ Success! DB ID: $insertId", 'cyan');
CLI::write("✅ Success! DB ID: $insertId | Source: $source", 'cyan');
} catch (\Exception $e) {
CLI::error("❌ Task Failed: " . $e->getMessage());
// 실패 로그는 여기서 남김
// 1. DB 상태를 FAIL로 업데이트 (필수)
$logModel->update($logId, ['status' => 'FAIL', 'error_msg' => $e->getMessage()]);
// 2. Redis 실패 큐에 백업 (선택 - 나중에 모아서 다시 던질 때 편함)
// payload에서 매물번호 추출 시도
$atclNo = null;
try {
if (!empty($rawData)) {
$responseJson = json_decode($rawData, true);
$payload = $responseJson['request_data'] ?? [];
$atclNo = $payload['articleNumber'] ?? null;
}
} catch (\Exception $parseEx) {
// JSON 파싱 실패는 무시
}
// 실패 로그는 여기서 남김
// 1. DB 상태를 FAIL로 업데이트 (필수) (재연결 처리 포함)
$this->safeUpdateLog($logModel, $logId, [
'atcl_no' => $atclNo,
'status' => 'FAIL',
'error_msg' => $e->getMessage()
]);
// 2. Redis 실패 큐에 백업 (선택 - Redis가 있을 경우만)
if ($redis) {
try {
$redis->lPush('naver:failed_queue', $rawData);
} catch (\Exception $redisEx) {
// Redis 실패 시에도 에러 처리하지 않음 (이미 DB에 FAIL 로그 남김)
CLI::write(CLI::color('⚠️ Failed to push to failed_queue: ' . $redisEx->getMessage(), 'yellow'));
}
}
helper('log');
write_custom_log("FAILED_DATA | Error: " . $e->getMessage(), 'ERROR', 'failed');
@@ -101,6 +194,103 @@ class NaverWorker extends BaseCommand
sleep(1);
}
}
}
/**
* MySQL 연결 계열 에러 발생 시 재연결 후 재시도하는 안전한 update
*/
protected function safeUpdateLog($logModel, $logId, $data)
{
try {
return $logModel->update($logId, $data);
} catch (\Throwable $e) {
if ($this->isMySqlConnectionError($e)) {
CLI::write(CLI::color('⚠️ MySQL gone away on update, reconnecting...', 'yellow'));
$this->db->close();
$this->db = \Config\Database::connect();
$this->db->initialize();
$logModel = model(\App\Models\Entities\NaverWorkerLogModel::class);
// 재시도
return $logModel->update($logId, $data);
} else {
throw $e;
}
}
}
/**
* MySQL 연결 끊김 계열 에러 여부 판별
*/
protected function isMySqlConnectionError(\Throwable $e): bool
{
$message = strtolower($e->getMessage());
return str_contains($message, 'mysql server has gone away')
|| str_contains($message, 'lost connection to mysql server')
|| str_contains($message, 'server has gone away');
}
/**
* 폴백 파일에서 데이터 읽기 (Redis 장애 시 파일에서 직접 처리)
*
* @return string|null JSON 데이터 또는 null
*/
protected function readFromFallbackFile()
{
$fallbackDir = ROOTPATH . 'worker/fallback_queue';
// 폴백 디렉토리가 없으면 null 반환
if (!is_dir($fallbackDir)) {
return null;
}
// 폴백 파일 목록 가져오기 (오래된 순서대로)
$files = glob($fallbackDir . '/*.json');
if (empty($files)) {
return null;
}
sort($files); // 파일명(타임스탬프) 기준 정렬
// 가장 오래된 파일 하나 처리
$filePath = $files[0];
try {
// 파일 락을 사용하여 읽기 (동시 접근 방지)
$fp = fopen($filePath, 'r');
if (!$fp) {
CLI::write(CLI::color("⚠️ Failed to open fallback file: " . basename($filePath), 'yellow'));
return null;
}
// 배타적 락 획득 시도
if (!flock($fp, LOCK_EX | LOCK_NB)) {
// 락 획득 실패 (다른 프로세스가 처리 중)
fclose($fp);
return null;
}
// 파일 내용 읽기
$content = stream_get_contents($fp);
// 파일 삭제 (처리 완료로 간주)
flock($fp, LOCK_UN);
fclose($fp);
unlink($filePath);
CLI::write(CLI::color("📂 Processing fallback file: " . basename($filePath), 'green'));
return $content;
} catch (\Exception $e) {
CLI::write(CLI::color("❌ Error reading fallback file " . basename($filePath) . ": " . $e->getMessage(), 'red'));
if (isset($fp) && is_resource($fp)) {
flock($fp, LOCK_UN);
fclose($fp);
}
return null;
}
}

32
app/Commands/TestLog.php Normal file
View File

@@ -0,0 +1,32 @@
<?php
namespace App\Commands;
use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;
class TestLog extends BaseCommand
{
protected $group = 'Test';
protected $name = 'test:log';
protected $description = 'Test log_message function';
public function run(array $params)
{
CLI::write('Testing log_message()...', 'yellow');
log_message('error', '===== TEST LOG MESSAGE FROM CLI ===== ' . date('Y-m-d H:i:s'));
log_message('debug', 'Debug level test');
log_message('info', 'Info level test');
$logFile = WRITEPATH . 'logs/log-' . date('Y-m-d') . '.log';
CLI::write('Log file: ' . $logFile);
CLI::write('Exists: ' . (file_exists($logFile) ? 'YES' : 'NO'));
if (file_exists($logFile)) {
CLI::write('Last 10 lines:');
CLI::write(shell_exec('tail -10 ' . escapeshellarg($logFile)));
}
}
}

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

@@ -159,13 +159,13 @@ class Cache extends BaseConfig
{
parent::__construct();
// Redis 설정에 .env 값을 할당 (이전 논의된 Docker 호스트 이름 'redis' 사용)
// Redis 설정에 환경 변수 값을 할당 (두 가지 환경 변수 형식 지원)
$this->redis = [
'host' => env('redis.default.host', '127.0.0.1'),
'password' => (env('redis.default.password') === '' || env('redis.default.password') === null) ? null : env('redis.default.password'),
'port' => (int)env('redis.default.port', 6379),
'timeout' => (int)env('redis.default.timeout', 0),
'database' => (int)env('redis.default.database', 0)
'host' => env('REDIS_HOST', env('redis.default.host', '127.0.0.1')),
'password' => env('REDIS_PASSWORD', env('redis.default.password')) ?: null,
'port' => (int)(env('REDIS_PORT', env('redis.default.port', 6379))),
'timeout' => (int)(env('REDIS_TIMEOUT', env('redis.default.timeout', 0))),
'database' => (int)(env('REDIS_DATABASE', env('redis.default.database', 0)))
];
// 필요하다면, 이 생성자에서 $handler나 $backupHandler 같은 다른 설정도

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

@@ -39,7 +39,7 @@ class Logger extends BaseConfig
*
* @var int|list<int>
*/
public $threshold = (ENVIRONMENT === 'production') ? 4 : 9;
public $threshold = 9; // Always log everything for debugging
/**
* --------------------------------------------------------------------------

View File

@@ -28,6 +28,8 @@ $routes->group('common', ['namespace' => 'App\Controllers\Common'], function ($r
$routes->post('common/changeUserPass', 'Common::changeUserPass'); // 비밀번호변경
$routes->get('getComplexList', 'Common::getComplexList'); // 단지목록조회
$routes->get('getPyeongInfo', 'Common::getPyeongInfo'); // 평형정보조회
});
@@ -67,17 +69,25 @@ $routes->group('', ['namespace' => 'App\Controllers\Article'], static function (
$routes->get('excel', 'Receipt::excel');
$routes->post('saveTel', 'Receipt::saveTel'); // 연락가능전화 저장
$routes->post('resDbYn', 'Receipt::resDbYn'); // 거주여부 저장
$routes->post('resGround', 'Receipt::resGround'); // 평면도요청 저장
$routes->post('assignRegist', 'Receipt::assignRegist'); // 예약확정 저장
$routes->post('requestMovie', 'Receipt::requestMovie'); // 동영상 촬영여부저장
$routes->post('requestMessage', 'Receipt::requestMessage'); // 중개사메모 저장
$routes->post('rsrvcancel', 'Receipt::rsrvcancel'); // 예약취소
$routes->post('chgStatus', 'Receipt::chgStatus'); // 상태변경
$routes->post('sendSms', 'Receipt::sendSms'); // 문자발송
$routes->post('saveRecInfo', 'Receipt::saveRecInfo'); // 거주인정보저장
$routes->get('getRecInfo', 'Receipt::getRecInfo'); // 거주인정보조회
$routes->get('getHistory', 'Receipt::getHistory'); // 정보변경이력조회
$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'); // 촬영위치 저장
$routes->post('modifyPriceInfo', 'Receipt::modifyPriceInfo'); // 가격정보 수정
});
/**
@@ -414,7 +424,8 @@ $routes->group('', ['namespace' => 'App\Controllers\V2'], static function ($rout
$routes->get('m713a/excel', 'M713::excel');
$routes->post('m713a/rotateImage', 'M713::rotateImage'); // 이미지 회전
$routes->post('m713a/saveCorpOwn', 'M713::saveCorpOwn'); // 법인매물저장
$routes->post('m713a/saveRegi', 'M713::saveRegi'); // 매물저장
$routes->post('m713a/saveModify', 'M713::saveModify');
$routes->post('m713a/saveRegi', 'M713::saveRegi'); // 등기부등본 저장
$routes->post('m713a/nextRegi', 'M713::nextRegi'); // 다음매물
});
@@ -658,6 +669,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');
});
/**
@@ -684,3 +701,12 @@ $routes->post('/login/chkLogin', 'Login::chkLogin');
if (is_file($filepath = APPPATH . 'Config/Routes/Api.php')) {
require $filepath;
}
/**
* Worker 관리
*/
$routes->group('manage/worker', ['namespace' => 'App\Controllers\Manage'], function ($routes) {
$routes->get('failed', 'WorkerLogController::failedList');
$routes->post('retry', 'WorkerLogController::retrySelected');
$routes->get('detail/(:num)', 'WorkerLogController::detail/$1');
});

View File

@@ -6,5 +6,5 @@ use CodeIgniter\Router\RouteCollection;
/** @var RouteCollection $routes */
$routes->group('kiso', function(RouteCollection $routes) {
$routes->match(['get', 'post'], 'api/vrfcReq', 'KisoController::vrfcReq');
$routes->match(['GET', 'POST'], 'api/vrfcReq', 'KisoController::vrfcReq');
});

View File

@@ -4,7 +4,7 @@ namespace Config;
use CodeIgniter\Config\BaseConfig;
use CodeIgniter\Session\Handlers\BaseHandler;
use CodeIgniter\Session\Handlers\FileHandler;
use CodeIgniter\Session\Handlers\DatabaseHandler;
use CodeIgniter\Session\Handlers\RedisHandler;
class Session extends BaseConfig
@@ -15,14 +15,11 @@ class Session extends BaseConfig
* --------------------------------------------------------------------------
*
* The session storage driver to use:
* - `CodeIgniter\Session\Handlers\FileHandler`
* - `CodeIgniter\Session\Handlers\DatabaseHandler`
* - `CodeIgniter\Session\Handlers\MemcachedHandler`
* - `CodeIgniter\Session\Handlers\RedisHandler`
*
* @var class-string<BaseHandler>
*/
// public string $driver = FileHandler::class;
public string $driver = RedisHandler::class;
/**
@@ -51,16 +48,61 @@ class Session extends BaseConfig
*
* The location to save sessions to and is driver dependent.
*
* For the 'files' driver, it's a path to a writable directory.
* WARNING: Only absolute paths are supported!
*
* For the 'database' driver, it's a table name.
* Please read up the manual for the format with other session drivers.
* For Redis: tcp://host:port?database=n&password=xxx
*
* IMPORTANT: You are REQUIRED to set a valid save path!
*/
// public string $savePath = WRITEPATH . 'session';
public string $savePath = 'tcp://192.168.10.243:6379?database=0';
public string $savePath;
public function __construct()
{
parent::__construct();
// 환경변수로 강제로 Database 모드 설정 가능 (Redis 장애 시 수동 전환)
$forceDatabase = env('SESSION_FORCE_DATABASE', false);
// Redis 설정: Redis 연결 실패 시 Database로 폴백
if ($this->driver === RedisHandler::class && !$forceDatabase) {
helper('redis');
try {
// Redis 연결 테스트
$testRedis = get_redis_connection('session');
if (!$testRedis) {
throw new \Exception('Redis connection failed');
}
// Redis 정상 - Redis 설정 사용
$config = get_redis_config('session');
$this->savePath = sprintf(
'tcp://%s:%s?database=%s',
$config['host'],
$config['port'],
$config['database']
);
if (!empty($config['password'])) {
$this->savePath .= '&password=' . $config['password'];
}
} catch (\Exception $e) {
// Redis 실패 - DatabaseHandler로 폴백
log_message('warning', 'Session: Redis unavailable (' . $e->getMessage() . '), falling back to DatabaseHandler');
$this->driver = DatabaseHandler::class;
$this->savePath = 'ci_sessions'; // 테이블 이름
}
} else {
// Database 강제 모드 또는 기본 Database 설정
if ($forceDatabase && $this->driver === RedisHandler::class) {
log_message('info', 'Session: Forced to use DatabaseHandler (SESSION_FORCE_DATABASE=true)');
$this->driver = DatabaseHandler::class;
}
$this->savePath = 'ci_sessions';
}
}
/**
* --------------------------------------------------------------------------

View File

@@ -109,42 +109,100 @@ class Processible extends BaseController
// 지역별 수량 저장
public function saveArea()
{
try {
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):
$this->model->saveArea($row);
endforeach;
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} else {
if (empty($rows)) {
log_message('info', '[Processible::saveArea] 저장가능한 데이터가 없습니다.');
return $this->response->setJSON([
'code' => '9',
'msg' => '저장가능한 데이터가 없습니다.'
]);
}
// API 형식으로 변환 및 DB 저장
$syncSlotData = [];
foreach ($rows as $row) {
// DB 저장 (API 실패와 무관하게 저장됨)
$this->model->saveArea($row);
// 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] DB 저장 완료 | Count: ' . count($rows));
// 네이버 API 슬롯 동기화 시도
log_message('info', '[Processible::saveArea] 슬롯 동기화 시작 | Count: ' . count($syncSlotData));
$naverClient = new \App\Libraries\NaverApiClient();
$apiResponse = $naverClient->syncSiteSlot($syncSlotData);
// API 응답 에러 체크
$hasError = false;
$errorMessage = '';
if ($apiResponse === null) {
$hasError = true;
$errorMessage = 'API 응답 없음 (null)';
} elseif (!empty($apiResponse['error'])) {
$hasError = true;
$errorType = $apiResponse['error_type'] ?? 'UNKNOWN';
$httpCode = $apiResponse['http_code'] ?? 'N/A';
$errorMessage = "API Error: {$errorType} (HTTP {$httpCode})";
} elseif (isset($apiResponse['http_code']) && $apiResponse['http_code'] >= 400) {
$hasError = true;
$errorMessage = "HTTP Error: {$apiResponse['http_code']}";
}
// API 에러 발생 시 (DB는 이미 저장됨)
if ($hasError) {
log_message('error', "[Processible::saveArea] {$errorMessage} | Response: " . json_encode($apiResponse, JSON_UNESCAPED_UNICODE));
return $this->response->setJSON([
'code' => '1',
'msg' => 'DB 저장은 완료되었으나 네이버 슬롯 동기화에 실패했습니다. 관리자에게 문의하세요.',
'error' => $errorMessage,
'dbSaved' => true,
'syncData' => $syncSlotData,
'apiResponse' => $apiResponse
]);
}
// 성공
log_message('info', '[Processible::saveArea] Naver API 슬롯 동기화 성공 | Response: ' . json_encode($apiResponse, JSON_UNESCAPED_UNICODE));
return $this->response->setJSON([
'code' => '0',
'msg' => 'success',
'dbSaved' => true,
'syncData' => $syncSlotData,
'apiResponse' => $apiResponse
]);
} catch (\Exception $e) {
log_message('error', '[Processible::saveArea] 예외 발생: ' . $e->getMessage());
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
'msg' => '처리 중 오류가 발생했습니다: ' . $e->getMessage(),
]);
}
}
// 기본 수량 저장
public function saveCount()
{
try {
@@ -152,18 +210,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 {

File diff suppressed because it is too large Load Diff

View File

@@ -4,16 +4,19 @@ namespace App\Controllers\Common;
use App\Controllers\BaseController;
use App\Models\common\CommonModel;
use App\Models\manage\UserModel;
use App\Libraries\NaverApiClient;
class Common extends BaseController
{
private $model;
private $userModel;
private $naverApiClient;
public function __construct()
{
$this->model = new CommonModel();
$this->userModel = new UserModel();
$this->naverApiClient = new NaverApiClient();
}
public function getVrfcCode()
@@ -118,4 +121,54 @@ class Common extends BaseController
]);
}
}
// 단지 조회
public function getComplexList()
{
$legalDivisionNumber = $this->request->getGet("legalDivisionNumber");
$realEstateType = $this->request->getGet("realEstateType") ?? null;
try {
$complexList = $this->naverApiClient->getComplexList($legalDivisionNumber , $realEstateType);
return $this->response->setJSON($complexList);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
/**
* 평형 조회
*
* complexNumber : 단지 번호
* realEstateType : 매물 종류 (APT, OFFICETEL, VILLA 등)
*/
public function getPyeongInfo()
{
$complexNumber = $this->request->getGet("complexNumber");
$realEstateType = $this->request->getGet("realEstateType");
try {
if ( $realEstateType == 'A01' || $realEstateType == 'A02' || $realEstateType == 'A03' ) {
$pyeongInfo = $this->naverApiClient->getPyeongTypeList($complexNumber);
} else if ( $realEstateType == 'A05' || $realEstateType == 'A06' ) {
$pyeongInfo = $this->naverApiClient->getVillaPyeongTypeList($complexNumber);
} else {
return $this->response->setJSON([
'code' => '9',
'msg' => '지원하지 않는 매물 종류입니다.',
]);
}
return $this->response->setJSON($pyeongInfo);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
}

View File

@@ -13,6 +13,23 @@ class KisoController extends BaseController
/** @var ResponseInterface */
protected $response;
/**
* 네이버 검증 요청 API
*
* Required Parameters:
* - articleNumber: 기사 번호
* - requestType: 요청 타입 (verify, check, validate)
* - requestDatetime: 요청 일시 (YYYY-MM-DD HH:MM:SS)
*
* Error Codes:
* - E001: 필수 파라미터 누락
* - E002: requestType 값 오류
* - E003: requestDatetime 형식 오류
* - E005: HTTP 메소드 오류
* - E999: Redis 연결 오류
*
* @return ResponseInterface
*/
public function vrfcReq()
{
// 1. 요청 방식에 따라 데이터 파싱
@@ -25,56 +42,79 @@ class KisoController extends BaseController
} else {
// 지원하지 않는 메소드 처리 (예: PUT, DELETE 등)
return $this->response->setStatusCode(Response::HTTP_METHOD_NOT_ALLOWED)
->setJSON(['resultCode' => 'E005', 'resultMessage' => 'Method not allowed. Use GET or POST.']);
->setJSON(['code' => 'E005', 'message' => 'Method not allowed. Use GET or POST.']);
}
// 2. 필수 항목 검증
$requiredKeys = ['articleNumber', 'requestType', 'requestDatetime'];
foreach ($requiredKeys as $key) {
// 파싱된 데이터($data) 내에 키가 없거나 값이 비어있는지 확인
if (empty($data[$key])) {
// isset()과 trim()을 사용하여 '0' 값도 허용
if (!isset($data[$key]) || trim((string)$data[$key]) === '') {
return $this->response->setStatusCode(Response::HTTP_BAD_REQUEST)
->setJSON([
'resultCode' => 'E001',
'resultMessage' => "Missing required parameter: {$key}"
'code' => 'E001',
'message' => "Missing required parameter: {$key}"
]);
}
}
// 3. Redis 연결 및 예외 처리
// 3. Redis 연결 및 직접 푸시
try {
$redis = new \Redis();
// Docker 환경이므로 host를 'redis'로 설정
$success = $redis->connect('redis', 6379);
// 3. requestType 값 검증
$validRequestTypes = ['verify', 'check', 'validate']; // 허용되는 requestType 값
if (!in_array($data['requestType'], $validRequestTypes, true)) {
return $this->response->setStatusCode(Response::HTTP_BAD_REQUEST)
->setJSON([
'code' => 'E002',
'message' => "Invalid requestType. Allowed values: " . implode(', ', $validRequestTypes)
]);
}
if (!$success) {
// 4. requestDatetime 날짜 형식 검증 (Y-m-d H:i:s 형식)
$datetime = \DateTime::createFromFormat('Y-m-d H:i:s', $data['requestDatetime']);
if (!$datetime || $datetime->format('Y-m-d H:i:s') !== $data['requestDatetime']) {
return $this->response->setStatusCode(Response::HTTP_BAD_REQUEST)
->setJSON([
'code' => 'E003',
'message' => "Invalid requestDatetime format. Use: YYYY-MM-DD HH:MM:SS"
]);
}
// 5. Redis 연결 및 큐 저장
helper('redis');
try {
$redis = get_redis_connection('worker');
if (!$redis) {
throw new \Exception('Redis connection failed');
}
$redis->select(10); // 10번 DB 선택
// 데이터 준비
$data['retry_count'] = 0;
$data['received_at'] = date('Y-m-d H:i:s');
// 리스트에 데이터 삽입 (이 명령어가 실행되어야 monitor에 LPUSH가 뜹니다)
$redis->lPush('naver:queue', json_encode($data));
// 리스트에 데이터 삽입
$pushResult = $redis->lPush('naver:queue', json_encode($data));
if (!$pushResult) {
throw new \Exception('Failed to push data to Redis queue');
}
// 성공 로그 기록
log_message('info', "Request queued successfully - Article: {$data['articleNumber']}, Type: {$data['requestType']}");
} catch (\Exception $e) {
log_message('error', 'Redis Push Error: ' . $e->getMessage());
return $this->response->setStatusCode(500)->setJSON([
'resultCode' => 'E999',
'resultMessage' => 'Redis Connection Error'
'code' => 'E999',
'message' => 'Redis Connection Error'
]);
}
// 4. 성공 응답
return $this->response->setStatusCode(Response::HTTP_ACCEPTED) // 202 Accepted
// 6. 성공 응답
return $this->response->setStatusCode(Response::HTTP_OK) // 200 OK
->setJSON([
'resultCode' => 'S000',
'resultMessage' => 'Request successfully queued for processing',
'articleNumber' => $data['articleNumber']
'code' => 'success',
'message' => ''
]);
}
}

View File

@@ -0,0 +1,27 @@
<?php
namespace App\Controllers;
class LogTest extends BaseController
{
public function index()
{
log_message('error', '===== WEB LOG TEST ===== ' . date('Y-m-d H:i:s'));
log_message('info', 'Info from web');
log_message('debug', 'Debug from web');
$logFile = WRITEPATH . 'logs/log-' . date('Y-m-d') . '.log';
echo "ENVIRONMENT: " . ENVIRONMENT . "<br>";
echo "Log file: " . $logFile . "<br>";
echo "Exists: " . (file_exists($logFile) ? 'YES' : 'NO') . "<br>";
echo "Writable: " . (is_writable(dirname($logFile)) ? 'YES' : 'NO') . "<br>";
if (file_exists($logFile)) {
echo "<h3>Last 20 lines:</h3>";
echo "<pre>";
echo htmlspecialchars(shell_exec('tail -20 ' . escapeshellarg($logFile)));
echo "</pre>";
}
}
}

View File

@@ -3,6 +3,7 @@ namespace App\Controllers;
use App\Controllers\BaseController;
use App\Models\common\LoginModel;
use CodeIgniter\Session\Handlers\DatabaseHandler;
class Login extends BaseController
{
@@ -13,6 +14,37 @@ class Login extends BaseController
$this->loginModel = new LoginModel();
}
/**
* Redis 폴백 상태 체크 (세션이 DatabaseHandler로 동작 중인지)
*/
private function getSystemStatus(): array
{
$status = [
'redis_fallback' => false,
'warning_message' => ''
];
// Session 설정에서 현재 드라이버 확인
$sessionConfig = config('Session');
if ($sessionConfig->driver === DatabaseHandler::class) {
$status['redis_fallback'] = true;
$status['warning_message'] = '세션 서버(Redis) 장애로 임시 모드로 운영 중입니다. 시스템 관리자에게 문의하세요.';
}
return $status;
}
/**
* JSON 응답에 시스템 상태 추가
*/
private function jsonResponse(array $data): \CodeIgniter\HTTP\ResponseInterface
{
$systemStatus = $this->getSystemStatus();
$data['system'] = $systemStatus;
return $this->response->setJSON($data);
}
public function index(): string
{
$user_id = get_cookie('save_id');
@@ -59,7 +91,7 @@ class Login extends BaseController
];
if (!$this->validate($rules)) {
return $this->response->setJSON([
return $this->jsonResponse([
'code' => '1',
'errors' => $this->validator->getErrors()
]);
@@ -82,7 +114,7 @@ class Login extends BaseController
$this->loginModel->insertUserLog($logs);
return $this->response->setJSON([
return $this->jsonResponse([
'code' => '1',
'msg' => '존재하지 않는 아이디입니다.'
]);
@@ -96,7 +128,7 @@ class Login extends BaseController
$this->loginModel->insertUserLog($logs);
return $this->response->setJSON(body: [
return $this->jsonResponse([
'code' => '1',
'msg' => '잘못된 비밀번호 입니다.'
]);
@@ -135,7 +167,7 @@ class Login extends BaseController
$this->session->set($newdata);
return $this->response->setJSON([
return $this->jsonResponse([
'code' => '0',
'msg' => 'success'
]);
@@ -148,7 +180,17 @@ class Login extends BaseController
log_message('error', '[LOGIN ERROR] ' . $e->getMessage());
log_message('error', $e->getTraceAsString());
return $this->response->setJSON([
// 세션 관련 에러인지 확인
$errorMessage = $e->getMessage();
if (stripos($errorMessage, 'session') !== false ||
stripos($errorMessage, 'redis') !== false) {
return $this->jsonResponse([
'code' => '8',
'msg' => '세션 서비스 오류입니다. 시스템 관리자에게 문의해주세요.'
]);
}
return $this->jsonResponse([
'code' => '9',
'msg' => '서버 내부 오류가 발생했습니다. 잠시 후 다시 시도해주세요.'
]);

View File

@@ -0,0 +1,222 @@
<?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) {
$logs[] = $this->parseLogLine($line);
}
return $logs;
}
/**
* 로그 한 줄 파싱
*/
private function parseLogLine($line)
{
// 로그 포맷: [2025-12-22 10:30:45] [INFO] [NaverWorker::run:95] 메시지
if (preg_match('/\[(.+?)\]\s*\[(.+?)\]\s*(?:\[(.+?)\]\s*)?(.+)/', $line, $matches)) {
return [
'timestamp' => $matches[1],
'level' => $matches[2],
'location' => $matches[3] ?? '',
'message' => $matches[4]
];
}
// 파싱 실패한 경우 원본 그대로
return [
'timestamp' => date('Y-m-d H:i:s'),
'level' => 'UNKNOWN',
'location' => '',
'message' => $line
];
}
/**
* 로그 파일이 존재하는 날짜 목록 가져오기
*/
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) {
$newLogs[] = $this->parseLogLine($line);
}
}
}
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

@@ -0,0 +1,366 @@
<?php
namespace App\Controllers\Manage;
use App\Controllers\BaseController;
use App\Models\Entities\NaverWorkerLogModel;
class WorkerLogController extends BaseController
{
protected $logModel;
public function __construct()
{
$this->logModel = new NaverWorkerLogModel();
}
/**
* 실패 로그 목록 (오류 유형별 분석)
*/
public function failedList()
{
$db = \Config\Database::connect();
// 1. 전체 통계
$stats = [
'total_fail' => $this->logModel->where('status', 'FAIL')->countAllResults(false),
'retry_available' => $this->logModel
->where('status', 'FAIL')
->groupStart()
->where('retry_cnt IS NULL')
->orWhere('retry_cnt <', 3)
->groupEnd()
->countAllResults(false),
'retry_exhausted' => $this->logModel
->where('status', 'FAIL')
->where('retry_cnt >=', 3)
->countAllResults(false),
];
// 2. 오류 유형별 분류
$errorTypes = $this->classifyErrors();
// 3. 최근 실패 목록
$recentFails = $this->logModel
->select('seq, atcl_no, status, error_msg, retry_cnt, created_at')
->where('status', 'FAIL')
->orderBy('created_at', 'DESC')
->findAll(50);
// 각 오류에 대한 해결 가이드 추가
foreach ($recentFails as &$log) {
$log['error_type'] = $this->detectErrorType($log['error_msg']);
$log['solution'] = $this->getSolution($log['error_type']);
$log['can_retry'] = $this->canRetry($log);
}
$data = [
'stats' => $stats,
'errorTypes' => $errorTypes,
'logs' => $recentFails
];
return view('manage/worker_log/failed_list', array_merge($this->data, $data));
}
/**
* 오류 유형 분류
*/
protected function classifyErrors()
{
$db = \Config\Database::connect();
$errorPatterns = [
'foreign_key' => [
'pattern' => 'foreign key constraint',
'label' => 'FK 제약조건 위반',
'severity' => 'high',
'count' => 0
],
'duplicate' => [
'pattern' => 'Duplicate entry',
'label' => '중복 데이터',
'severity' => 'medium',
'count' => 0
],
'missing_user' => [
'pattern' => 'usr_sq.*users 테이블에 없음',
'label' => '담당자 정보 없음',
'severity' => 'medium',
'count' => 0
],
'empty_payload' => [
'pattern' => '빈 페이로드',
'label' => '빈 데이터',
'severity' => 'low',
'count' => 0
],
'api_error' => [
'pattern' => 'API.*FAIL|HTTP.*40[0-9]|HTTP.*50[0-9]',
'label' => 'API 통신 오류',
'severity' => 'medium',
'count' => 0
],
'unknown' => [
'pattern' => '',
'label' => '기타 오류',
'severity' => 'low',
'count' => 0
]
];
$failedLogs = $this->logModel
->select('error_msg')
->where('status', 'FAIL')
->findAll();
foreach ($failedLogs as $log) {
$classified = false;
foreach ($errorPatterns as $key => &$pattern) {
if ($key === 'unknown') continue;
if ($pattern['pattern'] && preg_match('/' . $pattern['pattern'] . '/i', $log['error_msg'])) {
$pattern['count']++;
$classified = true;
break;
}
}
if (!$classified) {
$errorPatterns['unknown']['count']++;
}
}
return $errorPatterns;
}
/**
* 오류 유형 감지
*/
protected function detectErrorType($errorMsg)
{
if (!$errorMsg) return 'unknown';
if (stripos($errorMsg, 'foreign key constraint') !== false) {
return 'foreign_key';
}
if (stripos($errorMsg, 'Duplicate entry') !== false) {
return 'duplicate';
}
if (stripos($errorMsg, 'usr_sq') !== false && stripos($errorMsg, 'users 테이블') !== false) {
return 'missing_user';
}
if (stripos($errorMsg, '빈 페이로드') !== false) {
return 'empty_payload';
}
if (preg_match('/API.*FAIL|HTTP.*40[0-9]|HTTP.*50[0-9]/i', $errorMsg)) {
return 'api_error';
}
return 'unknown';
}
/**
* 오류 유형별 해결 방법
*/
protected function getSolution($errorType)
{
$solutions = [
'foreign_key' => [
'title' => 'DB 데이터 수정 필요',
'steps' => [
'1. 참조하는 테이블의 데이터가 존재하는지 확인',
'2. region 테이블의 orphaned usr_sq 값 수정',
'3. TypeSParameterMapper의 폴백 로직 확인'
],
'auto_retry' => false
],
'duplicate' => [
'title' => '중복 데이터 처리',
'steps' => [
'1. 기존 데이터 확인 (atcl_no로 검색)',
'2. 중복 원인 파악 (동일 요청 2회 수신?)',
'3. 필요시 기존 데이터 삭제 후 재처리'
],
'auto_retry' => false
],
'missing_user' => [
'title' => '담당자 정보 수정됨 - 재처리 가능',
'steps' => [
'✅ TypeSParameterMapper가 자동 폴백 적용됨',
'✅ 바로 재처리 가능 (usr_sq=1로 처리됨)'
],
'auto_retry' => true
],
'empty_payload' => [
'title' => '잘못된 요청 데이터',
'steps' => [
'1. raw_payload 확인',
'2. 네이버 API 응답 확인',
'3. 재처리 불가 - 데이터 삭제 권장'
],
'auto_retry' => false
],
'api_error' => [
'title' => 'API 통신 오류',
'steps' => [
'1. 일시적 오류인지 확인 (네트워크, 타임아웃)',
'2. 네이버 API 서버 상태 확인',
'3. 일시적 오류면 재처리 가능'
],
'auto_retry' => true
],
'unknown' => [
'title' => '원인 미상',
'steps' => [
'1. error_msg 상세 확인',
'2. 로그 파일 확인',
'3. 개발팀 검토 필요'
],
'auto_retry' => false
]
];
return $solutions[$errorType] ?? $solutions['unknown'];
}
/**
* 재시도 가능 여부
*/
protected function canRetry($log)
{
// 재시도 횟수 체크
if (($log['retry_cnt'] ?? 0) >= 3) {
return false;
}
// 오류 유형별 재시도 가능 여부
$errorType = $this->detectErrorType($log['error_msg']);
$solution = $this->getSolution($errorType);
return $solution['auto_retry'] ?? false;
}
/**
* 선택한 로그 재처리 (AJAX)
*/
public function retrySelected()
{
$logIds = $this->request->getPost('log_ids');
if (empty($logIds) || !is_array($logIds)) {
return $this->response->setJSON([
'success' => false,
'message' => '재처리할 로그를 선택해주세요.'
]);
}
$naverService = new \App\Services\NaverService();
$results = [
'success' => 0,
'fail' => 0,
'details' => []
];
foreach ($logIds as $logId) {
$log = $this->logModel->find($logId);
if (!$log) {
$results['details'][] = [
'id' => $logId,
'status' => 'error',
'message' => '로그를 찾을 수 없습니다.'
];
continue;
}
// 재시도 가능 여부 체크
if (!$this->canRetry($log)) {
$results['details'][] = [
'id' => $logId,
'atcl_no' => $log['atcl_no'],
'status' => 'skip',
'message' => '재시도 불가능 (횟수 초과 또는 수정 필요)'
];
continue;
}
try {
// 재처리
$this->logModel->update($logId, ['status' => 'RETRY']);
$responseJson = json_decode($log['raw_payload'], true);
$payload = $responseJson['request_data'] ?? [];
if (empty($payload)) {
throw new \Exception("빈 페이로드 데이터");
}
$insertId = $naverService->processArticle($payload);
$this->logModel->update($logId, [
'atcl_no' => $payload['articleNumber'] ?? null,
'status' => 'SUCCESS',
'target_db_id' => $insertId,
'error_msg' => null,
'retry_cnt' => ($log['retry_cnt'] ?? 0) + 1
]);
$results['success']++;
$results['details'][] = [
'id' => $logId,
'atcl_no' => $log['atcl_no'],
'status' => 'success',
'message' => "성공 (DB ID: {$insertId})"
];
} catch (\Exception $e) {
$this->logModel->update($logId, [
'status' => 'FAIL',
'error_msg' => $e->getMessage(),
'retry_cnt' => ($log['retry_cnt'] ?? 0) + 1
]);
$results['fail']++;
$results['details'][] = [
'id' => $logId,
'atcl_no' => $log['atcl_no'],
'status' => 'fail',
'message' => $e->getMessage()
];
}
}
return $this->response->setJSON([
'success' => true,
'results' => $results
]);
}
/**
* 특정 로그 상세 (AJAX)
*/
public function detail($id)
{
$log = $this->logModel->find($id);
if (!$log) {
return $this->response->setJSON([
'success' => false,
'message' => '로그를 찾을 수 없습니다.'
]);
}
// raw_payload JSON 파싱
$log['parsed_payload'] = json_decode($log['raw_payload'], true);
$log['error_type'] = $this->detectErrorType($log['error_msg']);
$log['solution'] = $this->getSolution($log['error_type']);
$log['can_retry'] = $this->canRetry($log);
return $this->response->setJSON([
'success' => true,
'log' => $log
]);
}
}

View File

@@ -31,6 +31,7 @@ class Assign extends BaseController
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
$draw = (int) $this->request->getGet('draw') ?: 1;
$data = [
'bonbu' => $this->request->getGet('bonbu'),
@@ -42,12 +43,18 @@ class Assign extends BaseController
'srchTxt' => $this->request->getGet('srchTxt'),
];
$totalCount = $this->assignModel->getTotalCount($data);
$datas = $this->assignModel->getUserList($start, $end, $data);
// 첫 번째 행에서 total_count 추출 (없으면 0)
$totalCount = !empty($datas) ? (int)$datas[0]['total_count'] : 0;
// 각 행에서 total_count 컬럼 제거
foreach ($datas as &$row) {
unset($row['total_count']);
}
return $this->response->setJSON(body: [
'draw' => $draw,
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,

View File

@@ -0,0 +1,163 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Models\common\CodeModel;
/**
* BaseV2Controller
* V2 모듈 공통 로직: lists / getResultList / excel
*
* 하위 클래스에서 구현해야 하는 메서드:
* - createModel() : 모듈 전용 Model 인스턴스 반환
* - getCodeKeys() : lists()에서 로드할 코드 카테고리 배열 반환
* - getViewName() : lists()에서 렌더링할 뷰 경로 반환
* - getSearchKeys() : getResultList/excel에서 수집할 GET 파라미터 키 배열 반환
*/
abstract class BaseV2Controller extends BaseController
{
protected $model;
protected $codeModel;
public function __construct()
{
$this->codeModel = new CodeModel();
$this->model = $this->createModel();
}
abstract protected function createModel();
abstract protected function getCodeKeys(): array;
abstract protected function getViewName(): string;
abstract protected function getSearchKeys(): array;
public function lists(): string
{
$codes = $this->codeModel->getCodeLists($this->getCodeKeys());
$sido = $this->model->getAreaList();
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['codes'] = $codes;
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
return view($this->getViewName(), $this->data);
}
public function getResultList()
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
$data = $this->buildSearchData();
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON([
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
public function excel()
{
try {
$data = $this->buildSearchData();
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(['data' => $datas]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
/**
* getSearchKeys()에 정의된 키만 GET에서 수집해서 배열로 반환
*/
protected function buildSearchData(): array
{
$data = [];
foreach ($this->getSearchKeys() as $key) {
$rawValue = $this->request->getGet($key);
$data[$key] = $this->normalizeSearchValue($key, $rawValue);
}
return $data;
}
/**
* 공통 파라미터 정규화
* - null/공백은 빈 문자열로 통일
* - 문자열은 trim 처리
* - 날짜 키(date 포함)는 형식 검증 실패 시 빈 문자열로 처리
*/
protected function normalizeSearchValue(string $key, $value)
{
if (is_array($value)) {
return array_map(static function ($item) {
if ($item === null) {
return '';
}
if (is_string($item)) {
$item = trim($item);
return $item === '' ? '' : $item;
}
return $item;
}, $value);
}
if ($value === null) {
return '';
}
if (is_string($value)) {
$value = trim($value);
if ($value === '') {
return '';
}
}
if ($this->isDateKey($key) && !$this->isValidDateValue((string) $value)) {
return '';
}
return $value;
}
/**
* 날짜 성격 파라미터 판별
* 예: receipt_sdate, receipt_edate, complete_sdate, stat_complete_date 등
*/
protected function isDateKey(string $key): bool
{
return strpos($key, 'date') !== false;
}
/**
* 허용 날짜 형식 검증
* - YYYY-MM-DD
* - YYYYMMDD
*/
protected function isValidDateValue(string $value): bool
{
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) === 1) {
[$year, $month, $day] = explode('-', $value);
return checkdate((int) $month, (int) $day, (int) $year);
}
if (preg_match('/^\d{8}$/', $value) === 1) {
$year = substr($value, 0, 4);
$month = substr($value, 4, 2);
$day = substr($value, 6, 2);
return checkdate((int) $month, (int) $day, (int) $year);
}
return false;
}
}

View File

@@ -1,130 +1,60 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\FormValidation;
use App\Libraries\MyUpload;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M701Model;
use App\Models\v2\M710Model;
use Exception;
use function PHPUnit\Framework\throwException;
use App\Models\v2\M701Model;
class M701 extends BaseController
class M701 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M701Model();
$this->codeModel = new CodeModel();
return new M701Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m701/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m701/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'reference_file_url_yn',
'corp_own',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id = null)
{
$id = (int) $id;
@@ -1700,5 +1630,3 @@ class M701 extends BaseController
}
}
}

View File

@@ -1,123 +1,58 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\MyUpload;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M702Model;
use App\Models\v2\M710Model;
use Exception;
use App\Models\v2\M702Model;
class M702 extends BaseController
class M702 extends BaseV2Controller
{
private $model;
private $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M702Model();
$this->codeModel = new CodeModel();
return new M702Model();
}
public function lists()
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['codes'] = $codes;
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
return view("pages/v2/m702/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m702/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'corp_own' => $this->request->getGet('corp_own'), // 법인
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'corp_own',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'corp_own' => $this->request->getGet('corp_own'), // 법인
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 배정변경
public function updateAssign()
{
try {

View File

@@ -1,131 +1,62 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M703Model;
use App\Models\v2\M710Model;
use App\Models\v2\M703Model;
class M703 extends BaseController
class M703 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M703Model();
$this->codeModel = new CodeModel();
return new M703Model();
}
public function lists()
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'FAX_CORP']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m703/lists", $this->data);
return ['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'FAX_CORP'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m703/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'chk_rec' => $this->request->getGet('chk_rec'), // 동의서 유무
'fax_corp' => $this->request->getGet('fax_corp'), // 팩스업체
protected function getSearchKeys(): array
{
return [
'atcl_no',
'chk_atcl_no',
'caller_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'target_yn',
'rcpt_cpid',
'chk_rec',
'fax_corp',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'chk_rec' => $this->request->getGet('chk_rec'), // 동의서 유무
'fax_corp' => $this->request->getGet('fax_corp'), // 팩스업체
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id)
{
$naver = new NaverApiClient();
$id = (string) $id;
if ($id === '') {
@@ -162,11 +93,11 @@ class M703 extends BaseController
$apt_rlet_type_cd = ['A01', 'A02', 'A03', 'A04', 'B01', 'B02', 'B03'];
$villa_rlet_type_cd = ['A05', 'A06'];
if (in_array($article['rlet_type_cd'], $apt_rlet_type_cd)) { // apt 단지
// $detail_hscp = $this->call_kiso_api->aptDetail($article['hscp_no']);
$detail_hscp = $naver->aptDetail($article['hscp_no']);
}
if (in_array($article['rlet_type_cd'], $villa_rlet_type_cd)) { // villa 단지
// $detail_hscp = $this->call_kiso_api->villaDetail($article['hscp_no']);
$detail_hscp = $naver->villaDetail($article['hscp_no']);
}
$this->data['hscp_info'] = $hscp_info;

View File

@@ -1,128 +1,60 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\MyUpload;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M704Model;
use App\Models\v2\M710Model;
use Exception;
use App\Models\v2\M704Model;
class M704 extends BaseController
class M704 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M704Model();
$this->codeModel = new CodeModel();
return new M704Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'TEL_FAIL_CAUSE', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m704/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'TEL_FAIL_CAUSE', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m704/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'stat_complete_date' => $this->request->getGet('stat_complete_date'), // 진행상태별시간유형
'complete_sdate' => $this->request->getGet('complete_sdate'), // 진행상태별시간1
'complete_edate' => $this->request->getGet('complete_edate'), // 진행상태별시간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'stat_complete_date',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'reference_file_url_yn',
'corp_own',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'stat_complete_date' => $this->request->getGet('stat_complete_date'), // 진행상태별시간유형
'complete_sdate' => $this->request->getGet('complete_sdate'), // 진행상태별시간1
'complete_edate' => $this->request->getGet('complete_edate'), // 진행상태별시간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id)
{
$naver = new NaverApiClient();

View File

@@ -1,86 +1,60 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\Common;
use App\Libraries\MyUpload;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M705Model;
use App\Models\v2\M710Model;
use App\Models\v2\M705Model;
class M705 extends BaseController
class M705 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M705Model();
$this->codeModel = new CodeModel();
return new M705Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'TEL_FAIL_CAUSE', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m705/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'TEL_FAIL_CAUSE', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m705/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'chk_spc_yn' => $this->request->getGet('chk_spc_yn'), // 면적여부
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'chk_spc_yn',
'reference_file_url_yn',
'corp_own',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 배정확인
public function getNotAssign()
{
try {

View File

@@ -1,117 +1,54 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M706Model;
use App\Models\v2\M710Model;
use Exception;
use App\Models\v2\M706Model;
class M706 extends BaseController
class M706 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M706Model();
$this->codeModel = new CodeModel();
return new M706Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m706/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m706/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'rcpt_cpid',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id)
{
$naver = new NaverApiClient();

View File

@@ -1,125 +1,59 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\Common;
use App\Libraries\NaverApiClient;
use App\Models\common\CodeModel;
use App\Models\results\M415Model;
use App\Models\v2\M708Model;
use App\Models\v2\M710Model;
use Exception;
use App\Models\v2\M708Model;
class M708 extends BaseController
class M708 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M708Model();
$this->codeModel = new CodeModel();
return new M708Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m708/lists", $this->data);
return ['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m708/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'rcpt_v2' => $this->request->getGet('rcpt_v2'), // 검증방식
protected function getSearchKeys(): array
{
return [
'atcl_no',
'chk_atcl_no',
'caller_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'target_yn',
'rcpt_cpid',
'rlet_type_cd',
'rcpt_v2',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'rcpt_v2' => $this->request->getGet('rcpt_v2'), // 검증방식
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id)
{
$id = (string) $id;

View File

@@ -1,120 +1,55 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\Common;
use App\Models\common\CodeModel;
use App\Models\v2\M709Model;
class M709 extends BaseController
class M709 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M709Model();
$this->codeModel = new CodeModel();
return new M709Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m709/lists", $this->data);
return ['CP_ID', 'STEP_VERIFICATION', 'RECEIPT_STATUS3', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m709/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'rcpt_v2' => $this->request->getGet('rcpt_v2'), // 검증방식
protected function getSearchKeys(): array
{
return [
'atcl_no',
'chk_atcl_no',
'caller_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'target_yn',
'rcpt_cpid',
'rlet_type_cd',
'rcpt_v2',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'chk_atcl_no' => $this->request->getGet('chk_atcl_no'), // 매물번호입력
'caller_no' => $this->request->getGet('caller_no'), // 발신팩스번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'target_yn' => $this->request->getGet('target_yn'), // 홍보확인서여부
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'rcpt_v2' => $this->request->getGet('rcpt_v2'), // 검증방식
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id)
{
$id = (string) $id;

View File

@@ -18,6 +18,7 @@ class M710 extends BaseController
public function lists(): string
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();

View File

@@ -1,129 +1,63 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\Common;
use App\Libraries\MyUpload;
use App\Models\common\CodeModel;
use App\Libraries\NaverApiClient;
use App\Models\results\M415Model;
use App\Models\v2\M712Model;
class M712 extends BaseController
class M712 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M712Model();
$this->codeModel = new CodeModel();
return new M712Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m712/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m712/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'ownerTypeCode' => $this->request->getGet('ownerTypeCode'), // 소유자 구분
'document_not_received_yn' => $this->request->getGet('document_not_received_yn'), // 서류미수취
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'reference_file_url_yn',
'ownerTypeCode',
'document_not_received_yn',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'ownerTypeCode' => $this->request->getGet('ownerTypeCode'), // 소유자 구분
'document_not_received_yn' => $this->request->getGet('document_not_received_yn'), // 서류미수취
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id): string
{
$naver = new NaverApiClient();
$id = (string) $id;
if ($id === '') {
@@ -139,12 +73,37 @@ class M712 extends BaseController
$regist = $this->model->getRecordInfo($id, '2'); //등기부등본
$display = $this->model->getDisplay('M705_detail');
$hscp_info = [];
if (!empty($data['hscp_no'])) {
$apt_rlet_type_cd = ['A01', 'A02', 'A03', 'A04', 'B01', 'B02', 'B03'];
$villa_rlet_type_cd = ['A05', 'A06'];
if (in_array($data['rlet_type_cd'], $apt_rlet_type_cd)) { // apt 단지
$detail_hscp = $naver->aptDetail($data['hscp_no']);
}
if (in_array($data['rlet_type_cd'], $villa_rlet_type_cd)) { // villa 단지
$detail_hscp = $naver->villaDetail($data['hscp_no']);
}
// print_r($data);
// print_r($detail_hscp);
// exit;
if (!empty($detail_hscp) && isset($detail_hscp['result'])) {
$hscp_info = $detail_hscp['result'];
}
}
$this->data['codes'] = $codes;
$this->data['data'] = $data;
$this->data['memo'] = $memo;
$this->data['record'] = $record;
$this->data['regist'] = $regist;
$this->data['display'] = $display;
$this->data['hscp_info'] = $hscp_info;
return view("pages/v2/m712/detail", $this->data);
}
@@ -294,14 +253,384 @@ class M712 extends BaseController
// 정보저장
public function saveRegi()
{
/*
1.0.1 POST 데이터 받기.
1.1.1 1차 검증인지 2차검증인지 확인.
1.1.2 1차, 2차 검증이면 v2_confirm.type에 넣을 값을 알맞게 셋팅.
1.2.1 v2_confirms에 데이터가 있는지 확인.
1.3.1 데이터가 있음 : success 여부 판단 후 updateConfirm 실행 success값만 UPDATE. (수정변경이력 저장)
1.4.1 데이터가 없음 : success 여부 판단 후 insertConfirm 실행 v2_confirms INSERT. (수정변경이력 저장)
1.4.2 상태변경 하기 : 등기부등본 확인중 상태로 변경. (수정변경이력 저장)
1.5.1 이미지파일 서버에 UPLOAD (수정변경이력 저장)
1.6.1 기존파일 탐색.
1.7.1 기존파일 있음 : 기존파일 use_yn 'N'으로 UPDATE 후 v2_files INSERT.
1.8.1 기존파일 없음 : v2_files INSERT.
1.9.1 매물주소, 의뢰인 정보 v2_check_list INSERT. (수정변경이력 저장)
1.10.1 API 전송.
1.11.1 API 전송결과 : SUCCESS 이면 상태값 변경 : 등기부등본 확인완료 상태. (수정변경이력 저장)
1.12.1 서류 확인내용 v2_article_info_etc document_cert_method 저장
*/
$naver = new NaverApiClient();
// $model710 = new M710Model();
$model415 = new M415Model();
$v2DailyModel = new V2StDailyModel();
try {
$usr_id = session('usr_id');
$toDay = date('Y-m-d H:i:s');
$atcl_vrtc_way = 'R'; //검증구분
$atcl_vr_sq = $this->request->getPost('rcpt_key');
// $atcl_no = $this->request->getPost('atcl_no');
$reg_conf_yn_1 = $this->request->getPost('reg_conf_yn_1'); //확인내용
$reg_conf_yn_2 = $this->request->getPost('reg_conf_yn_2'); //매물주소
$reg_conf_yn_3 = $this->request->getPost('reg_conf_yn_3'); //의뢰인정보
$reg_conf_yn_info_2 = $this->request->getPost('reg_conf_yn_info_2'); //매물주소
$reg_conf_yn_info_3 = $this->request->getPost('reg_conf_yn_info_3'); //의뢰인정보
$memo = $this->request->getPost('memo'); //메모
$owner_verifiable = $this->request->getPost('owner_verifiable'); //실소유주 확인여부
$noimg_chk_chk = $this->request->getPost('noimg_chk_chk'); // 등기부등본이미지 파일없음.
$img_chk_chk = $this->request->getPost('img_chk_chk'); // 등기소, 리얼탑 열람, 리얼탑 기열람, 열람
$atcl_vrtc_type = $this->request->getPost('atcl_vrtc_type'); // 검증구분
$vrfc_type_sub = $this->request->getPost('vrfc_type_sub'); // 하위검증구분
$arr_uncnfrm_status = $this->request->getPost('arr_uncnfrm_status'); // 등기부등본 미확인여부 상세
$ownerTypeCode = $this->request->getPost('ownerTypeCode'); // 소유자명 확인 일치 , 불일치
$document_cert_method = $this->request->getPost('document_cert_method'); // 서류 내용 확인
if ($owner_verifiable == "1") {
$owner_verifiable = true;
} else {
$owner_verifiable = false;
}
//상태가 이미 등기부등본확인중 이상이면 저장하지 않는다.
$resStat = $this->model->chkStat($atcl_vr_sq);
$v2_vrfc_req = $v2DailyModel->get_v2_vrfc_req($atcl_vr_sq);
$rlet_type_cd = $model415->get_rlet_type_cd($atcl_vr_sq);
if ((int) $resStat['stat_cd'] >= 60 || (int) $resStat['stat_cd'] == 19) {
throw new \Exception('이미 저장된 데이터입니다.');
} else {
$resultCnt = $this->model->chkRegiTryCnt($atcl_vr_sq); //1차검증인지 2차검증인지 확인 쿼리 : v2_vrfc_req.type_cnt
if ($resultCnt['reg_try_cnt'] == 0) { // 1차 검증일 때
log_message('debug', '712 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 0 ');
$try_cnt = '1';
} else if ($resultCnt['reg_try_cnt'] == 1) { // 2차 검증일 때
log_message('debug', '712 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 1 ');
$try_cnt = '2';
} else {
log_message('debug', '712 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 예외처리 ');
$try_cnt = '2';
//$try_cnt = intval($try_cnt) + 1;
}
$result = $this->model->chkConfirm($atcl_vr_sq, $atcl_vrtc_way);
if ($result == 0) { //v2_confirm 존재하지 않는다면
if ($reg_conf_yn_2 == '10000' && $reg_conf_yn_3 == '10000') { //success 여부 판단
$chk_type = '1';
//$chk_delay = '0'; //지연여부
//$chk_zombie = '0'; //좀비매물
} else {
// 2015.06.29 추가
// 불일치가 날 경우에 10분 이내에 다시 불일치 처리 불가능(같은 매물을 두사람이 중복처리할 가능성 사전 방지)
// 1. 현재 매물의 마지막으로 업데이트 된 시간을 가져옴.
// 2. 현재 시간과 비교하여 10분 이내면 경고창을 띄어줌.
$chk_type = '0';
//$chk_delay = '1'; //지연여부
//$chk_zombie = '0'; //좀비매물
$result_tm = $this->model->getUpdateFailTime($atcl_vr_sq);
$update_tm = $result_tm['insert_tm'];
$ten_ago = date("Y-m-d H:i:s", mktime(date("H"), date("i") - 1, date("s"), date("m"), date("d"), date("Y")));
if ($update_tm > $ten_ago) {
// 수정한 시간이 현재시간10분전 보다 클 경우 수정불가능
throw new \Exception('이미 불일치 처리 된 매물입니다.');
}
}
$this->model->insertConfirm($atcl_vr_sq, $atcl_vrtc_way, $chk_type, $try_cnt);
} else {
if ($reg_conf_yn_2 == '10000' && $reg_conf_yn_3 == '10000') { //success 여부 판단
$chk_type = '1';
//$chk_delay = '0'; //지연여부
//$chk_zombie = '0'; //좀비매물
} else {
// 2015.06.29 추가
// 불일치가 날 경우에 10분 이내에 다시 불일치 처리 불가능(같은 매물을 두사람이 중복처리할 가능성 사전 방지)
// 1. 현재 매물의 마지막으로 업데이트 된 시간을 가져옴.
// 2. 현재 시간과 비교하여 10분 이내면 경고창을 띄어줌.
$chk_type = '0';
//$chk_delay = '1'; //지연여부
//$chk_zombie = '0'; //좀비매물
$result_tm = $this->model->getUpdateFailTime($atcl_vr_sq);
$update_tm = $result_tm['insert_tm'];
$ten_ago = date("Y-m-d H:i:s", mktime(date("H"), date("i") - 1, date("s"), date("m"), date("d"), date("Y")));
if ($update_tm > $ten_ago) {
throw new \Exception('이미 불일치 처리 된 매물입니다.');
}
}
$this->model->updateConfirm($atcl_vr_sq, $atcl_vrtc_way, $chk_type);
}
$this->model->InsResChar($atcl_vr_sq); //담당자 업데이트
// 모바일v1,v2고 등기부등본 미확인여부 상세 저장
if ($vrfc_type_sub == 'M1' || $vrfc_type_sub == 'O1') {
$this->model->add_cert_uncnfrm_status($atcl_vr_sq, $arr_uncnfrm_status);
if (strpos($arr_uncnfrm_status, '20020') !== false) { //등기부등본 미확인여부 상세에 20020(파일 오첨부)있고
if ($vrfc_type_sub == 'M1') { // 모바일v1일땐 코드 20020,코멘트x
$reg_conf_yn_2 = '20020';
$reg_conf_yn_info_2 = '';
} else { // 모바일v2일땐 일반 불일치코드,코멘트=파일 오첨부
$reg_conf_yn_info_2 = '파일 오첨부';
}
}
}
//v2_check_list 확인여부 INSERT
$this->model->insertChkList($atcl_vr_sq, $atcl_vrtc_way, '21', $reg_conf_yn_2, $reg_conf_yn_info_2);
//v2_check_list 매물주소 INSERT
$this->model->insertChkList($atcl_vr_sq, $atcl_vrtc_way, '22', $reg_conf_yn_3, $reg_conf_yn_info_3);
//memo 저장
$this->model->saveMemo([$memo, $atcl_vr_sq]);
// document_cert_method
$this->model->updatedocument_cert_method($atcl_vr_sq, $document_cert_method);
//실소유주 확인 저장
$this->model->update_owner_verifiable($atcl_vr_sq, $owner_verifiable);
$sendData = $this->model->getDatacertAPI($atcl_vr_sq, 'R');
log_message('debug', '712 saveRegi => ' . $sendData['atclNo'] . ' ::: ' . json_encode($sendData) . PHP_EOL);
$d_yn = $this->model->get_send_yn('D');
if ($d_yn['stop_yn'] == 'N') { //전송금지
//1.해당매물정보를v2_stop_api_save_info에다 넣음
$this->model->insert_v2_stop_api_save_info($sendData['atclNo'], $atcl_vr_sq, 'D', '');
//2.아무렇지않게 행동한다
$send_result['result'] = 'success';
} else {
//API 호출
$send_result = $naver->certification_712($sendData['atclNo'], $try_cnt, $sendData['success'], $sendData['checkList'], $sendData['charger'], $sendData['date'], $sendData['modifyInfo'], $sendData['ownerVerifiable']);
}
if ($send_result['result'] == 'success') {
if ($chk_type == '1') {
//상태변경 TABLE INSERT : 등기부등본 확인완료 상태로 변경
$this->model->chgStat($atcl_vr_sq, '45', $toDay);
$chgVrfc45 = $this->model->chgStatVrfc($atcl_vr_sq, '45'); //v2_vrfc_req INSERT
$statFaxUp45 = $this->model->chgStatFax($atcl_vr_sq, '45'); //fax_imgs
//상태변경 TABLE INSERT : 검증완료 상태로 변경
$this->model->chgStat($atcl_vr_sq, '60', $toDay);
$chgVrfc60 = $this->model->chgStatVrfc($atcl_vr_sq, '60'); //v2_vrfc_req INSERT
$statFaxUp60 = $this->model->chgStatFax($atcl_vr_sq, '60'); //fax_imgs
// ★ 검증완료
//0.불일치 이력이 있는지 확인
$cnt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
if (empty($cnt)) {
if ($atcl_vrtc_type == 'M' || $atcl_vrtc_type == 'N') { //모바일은 등기가 첨 시작이니까 insert해줘야함
if (!($atcl_vrtc_type == 'M' && in_array($rlet_type_cd['rlet_type_cd'], array('B01', 'B02', 'B03')))) {//만약 분양권들이면 넘어가고 아니면 체크
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인완료 시간
$cert_comple_dt = $model415->get_cert_confTimeForHistory($atcl_vr_sq);
//3.검증완료시간
$finishTime = $model415->get_60_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
}
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인완료 시간
$cert_comple_dt = $model415->get_cert_confTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$model415->update_v2_time_required_Conf_Done($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm']);
}
}
if ($noimg_chk_chk == 'Y') {
$this->model->chgStat($atcl_vr_sq, '70', $toDay);
$this->model->updateStat($atcl_vr_sq, 'Y'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0103', '1', 'add'); // 등기부등본이미지 없음 저장
}
if ($img_chk_chk == 'O') {
$this->model->chgStat($atcl_vr_sq, '76', $toDay);
$this->model->updateStat($atcl_vr_sq, 'O'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0105', '1', 'add'); // (열람)간소화확인으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'T') {
$this->model->chgStat($atcl_vr_sq, '80', $toDay);
$this->model->updateStat($atcl_vr_sq, 'T'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0111', '1', 'add'); // 등기소로 일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'R') {
$this->model->chgStat($atcl_vr_sq, '86', $toDay);
$this->model->updateStat($atcl_vr_sq, 'R'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0107', '1', 'add'); // 리얼탑 열람 일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'G') {
$this->model->chgStat($atcl_vr_sq, '87', $toDay);
$this->model->updateStat($atcl_vr_sq, 'G'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0108', '1', 'add'); // 리얼탑 기열람 일치으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
}
} else {
if ($atcl_vrtc_type == 'M') {
//상태변경 TABLE INSERT : 등기부등본 확인 불일치 상태로 변경
$this->model->chgStat($atcl_vr_sq, '49', $toDay);
$chgVrfc49 = $this->model->chgStatVrfc($atcl_vr_sq, '49'); //v2_vrfc_req INSERT
$statFaxUp49 = $this->model->chgStatFax($atcl_vr_sq, '49'); //fax_imgs
//v2_vrfc_req try_cnt 값을 1로 update
$this->model->chgRegiTryCnt($atcl_vr_sq, '2');
//상태변경 TABLE INSERT : 검증실패 상태로 변경
$this->model->chgStat($atcl_vr_sq, '69', $toDay);
$chgVrfc69 = $this->model->chgStatVrfc($atcl_vr_sq, '69'); //v2_vrfc_req INSERT
$statFaxUp69 = $this->model->chgStatFax($atcl_vr_sq, '69'); //fax_imgs
// ★모바일이고 검증실패
if (!in_array($rlet_type_cd['rlet_type_cd'], array('B01', 'B02', 'B03'))) {//만약 분양권들이면 넘어가고 아니면 체크
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
}
} else {
//상태변경 TABLE INSERT : 등기부등본 확인 불일치 상태로 변경
$this->model->chgStat($atcl_vr_sq, '49', $toDay);
$chgVrfc49 = $this->model->chgStatVrfc($atcl_vr_sq, '49'); //v2_vrfc_req INSERT
$statFaxUp49 = $this->model->chgStatFax($atcl_vr_sq, '49'); //fax_imgs
//등기부등본 확인중 상태로 변경.
$this->model->saveChangedHistory($atcl_vr_sq, '30', 'C9', $usr_id, '상태변경 : 49 => 30'); //검증결과 변동사항 HISTORY
$chgVrfc40 = $this->model->chgStatVrfc($atcl_vr_sq, '30'); //v2_vrfc_req INSERT
$statFaxUp40 = $this->model->chgStatFax($atcl_vr_sq, '30'); //fax_imgs
if ($try_cnt == '1') {
//v2_vrfc_req try_cnt 값을 1로 update
$this->model->chgRegiTryCnt($atcl_vr_sq, '1');
if ($atcl_vrtc_type == 'T') {
//검증구분이 전화매물일 경우 사전에 일치로 처리된 값을 초기화 시켜준다.
$reset_query = $this->model->resetTelConf($atcl_vr_sq);
}
// ★1차실패
if ($atcl_vrtc_type == 'N') {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$sf = 'F';
$model415->update_v2_time_required_Conf($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $sf);
}
} else if ($try_cnt == '2') {
//v2_vrfc_req try_cnt 값을 2로 update
$this->model->chgRegiTryCnt($atcl_vr_sq, '2');
//상태변경 TABLE INSERT : 검증실패 상태로 변경.
$this->model->chgStat($atcl_vr_sq, '69', $toDay);
$chgVrfc69 = $this->model->chgStatVrfc($atcl_vr_sq, '69'); //v2_vrfc_req INSERT
$statFaxUp69 = $this->model->chgStatFax($atcl_vr_sq, '69'); //fax_imgs
// ★모바일 이외 검증실패
if ($atcl_vrtc_type == 'N') {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$model415->update_v2_time_required_Conf_Done($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm']);
}
}
}
if ($noimg_chk_chk == 'Y') {
$this->model->chgStat($atcl_vr_sq, '70', $toDay);
$this->model->updateStat($atcl_vr_sq, 'Y'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0103', '1', 'add'); // 등기부등본이미지 없음 저장
}
if ($img_chk_chk == 'O') {
$this->model->chgStat($atcl_vr_sq, '77', $toDay);
$this->model->updateStat($atcl_vr_sq, 'O'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0105', '1', 'add'); // (열람)간소화확인으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'T') {
$this->model->chgStat($atcl_vr_sq, '85', $toDay);
$this->model->updateStat($atcl_vr_sq, 'T'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0112', '1', 'add'); // 등기소 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'R') {
$this->model->chgStat($atcl_vr_sq, '88', $toDay);
$this->model->updateStat($atcl_vr_sq, 'R'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0109', '1', 'add'); // 리얼탑 열람 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'G') {
$this->model->chgStat($atcl_vr_sq, '89', $toDay);
$this->model->updateStat($atcl_vr_sq, 'G'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0110', '1', 'add'); // 리얼탑 기열람 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
}
}
} else {
if (isset($send_result['error'])) {
$error_message = $send_result['error']['code'] . "\\n" . $send_result['error']['message'];
// API 호출 에러 발생시 해당 내용들을 DB에 저장해준다.
$err_time = date("Y-m-d H:i:s");
$this->model->saveApiErr($atcl_vr_sq, $send_result['error']['code'], $send_result['error']['message'], $err_time, $v2_vrfc_req['atcl_no']);
throw new \Exception($error_message);
} else {
throw new \Exception('네이버 전송 중 오류가 발생되었습니다. 다시 시도하세요.');
}
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success',
]);
}
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',

View File

@@ -1,126 +1,62 @@
<?php
namespace App\Controllers\V2;
use App\Controllers\BaseController;
use App\Controllers\V2\BaseV2Controller;
use App\Libraries\MyUpload;
use App\Models\common\CodeModel;
use App\Libraries\NaverApiClient;
use App\Models\results\M415Model;
use App\Models\v2\M710Model;
use App\Models\v2\M713Model;
class M713 extends BaseController
class M713 extends BaseV2Controller
{
private $model, $codeModel;
public function __construct()
protected function createModel()
{
$this->model = new M713Model();
$this->codeModel = new CodeModel();
return new M713Model();
}
public function lists(): string
protected function getCodeKeys(): array
{
$codes = $this->codeModel->getCodeLists(['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE']); // 코드조회
$sido = $this->model->getAreaList(); // 지역조회
$bonbu = $this->model->getBonbuList();
$team = $this->model->getTeamList();
$user = $this->model->getUserList();
$this->data['sido'] = $sido;
$this->data['bonbu'] = $bonbu;
$this->data['team'] = $team;
$this->data['user'] = $user;
$this->data['codes'] = $codes;
return view("pages/v2/m713/lists", $this->data);
return ['STEP_VERIFICATION', 'VRFCREQ_WAY', 'CP_ID', 'ARTICLE_TYPE'];
}
public function getResultList()
protected function getViewName(): string
{
$start = (int) $this->request->getGet('start') ?: 0;
$end = (int) $this->request->getGet('length') ?: 10;
return 'pages/v2/m713/lists';
}
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'chk_spc_yn' => $this->request->getGet('chk_spc_yn'), // 면적확인
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인소유
protected function getSearchKeys(): array
{
return [
'atcl_no',
'stat_cd',
'realtor_nm',
'charger_gbn',
'assign_yn',
'receipt_sdate',
'receipt_edate',
'complete_sdate',
'complete_edate',
'srcSido',
'srcGugun',
'srcDong',
'bonbu',
'team',
'damdang',
'vrfcreq_way',
'vrfc_type_sub',
'rcpt_cpid',
'rlet_type_cd',
'chk_spc_yn',
'reference_file_url_yn',
'corp_own',
];
$totalCount = $this->model->getTotalCount($data);
$datas = $this->model->getResultList($start, $end, $data);
return $this->response->setJSON(body: [
'recordsTotal' => $totalCount,
'recordsFiltered' => $totalCount,
'data' => $datas,
]);
}
// 엑셀 다운로드
public function excel()
{
try {
$data = [
'atcl_no' => $this->request->getGet('atcl_no'), // 매물번호
'stat_cd' => $this->request->getGet('stat_cd'), // 현재상태
'realtor_nm' => $this->request->getGet('realtor_nm'), // 중개소
'charger_gbn' => $this->request->getGet('charger_gbn'), // 배정여부
'assign_yn' => $this->request->getGet('assign_yn'), // 배정여부2
'receipt_sdate' => $this->request->getGet('receipt_sdate'), // 접수기간1
'receipt_edate' => $this->request->getGet('receipt_edate'), // 접수기간2
'complete_sdate' => $this->request->getGet('complete_sdate'), // 완료기간1
'complete_edate' => $this->request->getGet('complete_edate'), // 완료기간2
'srcSido' => $this->request->getGet('srcSido'), // 시도
'srcGugun' => $this->request->getGet('srcGugun'), // 시군구
'srcDong' => $this->request->getGet('srcDong'), // 읍면동
'bonbu' => $this->request->getGet('bonbu'), // 본부
'team' => $this->request->getGet('team'), // 팀
'damdang' => $this->request->getGet('damdang'), // 담당
'vrfcreq_way' => $this->request->getGet('vrfcreq_way'), // 검증방식1
'vrfc_type_sub' => $this->request->getGet('vrfc_type_sub'), // 검증방식2
'rcpt_cpid' => $this->request->getGet('rcpt_cpid'), // 매체사
'rlet_type_cd' => $this->request->getGet('rlet_type_cd'), // 매물종류
'chk_spc_yn' => $this->request->getGet('chk_spc_yn'), // 면적확인
'reference_file_url_yn' => $this->request->getGet('reference_file_url_yn'), // 참고용
'corp_own' => $this->request->getGet('corp_own'), // 법인소유
];
$datas = $this->model->getExcelList($data);
return $this->response->setJSON(body: [
'data' => $datas,
]);
} catch (\Exception $e) {
$e->getPrevious()->getTraceAsString();
}
}
// 상세화면
public function detail($id): string
{
$naver = new NaverApiClient();
$id = (string) $id;
if ($id === '') {
@@ -138,6 +74,30 @@ class M713 extends BaseController
$sido = $this->model->getAreaList(); // 지역조회
$hscp_info = [];
if (!empty($data['hscp_no'])) {
$apt_rlet_type_cd = ['A01', 'A02', 'A03', 'A04', 'B01', 'B02', 'B03'];
$villa_rlet_type_cd = ['A05', 'A06'];
if (in_array($data['rlet_type_cd'], $apt_rlet_type_cd)) { // apt 단지
$detail_hscp = $naver->aptDetail($data['hscp_no']);
}
if (in_array($data['rlet_type_cd'], $villa_rlet_type_cd)) { // villa 단지
$detail_hscp = $naver->villaDetail($data['hscp_no']);
}
// print_r($data);
// print_r($detail_hscp);
// exit;
if (!empty($detail_hscp) && isset($detail_hscp['result'])) {
$hscp_info = $detail_hscp['result'];
}
}
$this->data['codes'] = $codes;
$this->data['data'] = $data;
$this->data['memo'] = $memo;
@@ -145,6 +105,7 @@ class M713 extends BaseController
$this->data['regist'] = $regist;
$this->data['display'] = $display;
$this->data['sido'] = $sido;
$this->data['hscp_info'] = $hscp_info;
return view("pages/v2/m713/detail", $this->data);
}
@@ -293,6 +254,414 @@ class M713 extends BaseController
}
public function saveModify()
{
try {
$vr_sq = $this->request->getPost('vr_sq');
$owner_birth = $this->request->getPost('owner_birth');
$address2 = $this->request->getPost('address2');
$address2a = $this->request->getPost('address2a');
$address2b = $this->request->getPost('address2b');
$address3 = $this->request->getPost('address3');
$address4 = $this->request->getPost('address4');
$address_code = $this->request->getPost('dong');
$hscp_no = $this->request->getPost('hscp_no');
$hscp_nm = $this->request->getPost('hscp_nm');
$owner_birth = trim($owner_birth);
$this->model->modify_info($vr_sq, $owner_birth, $address2, $address2a, $address2b, $address3, $address4, $address_code, $hscp_no, $hscp_nm);
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 등기부등본 저장
public function saveRegi()
{
/*
1.0.1 POST 데이터 받기.
1.1.1 1차 검증인지 2차검증인지 확인.
1.1.2 1차, 2차 검증이면 v2_confirm.type에 넣을 값을 알맞게 셋팅.
1.2.1 v2_confirms에 데이터가 있는지 확인.
1.3.1 데이터가 있음 : success 여부 판단 후 updateConfirm 실행 success값만 UPDATE. (수정변경이력 저장)
1.4.1 데이터가 없음 : success 여부 판단 후 insertConfirm 실행 v2_confirms INSERT. (수정변경이력 저장)
1.4.2 상태변경 하기 : 등기부등본 확인중 상태로 변경. (수정변경이력 저장)
1.5.1 이미지파일 서버에 UPLOAD (수정변경이력 저장)
1.6.1 기존파일 탐색.
1.7.1 기존파일 있음 : 기존파일 use_yn 'N'으로 UPDATE 후 v2_files INSERT.
1.8.1 기존파일 없음 : v2_files INSERT.
1.9.1 매물주소, 의뢰인 정보 v2_check_list INSERT. (수정변경이력 저장)
1.10.1 API 전송.
1.11.1 API 전송결과 : SUCCESS 이면 상태값 변경 : 등기부등본 확인완료 상태. (수정변경이력 저장)
*/
$naver = new NaverApiClient();
$model710 = new M710Model();
$model415 = new M415Model();
$v2DailyModel = new V2StDailyModel();
try {
$usr_id = session('usr_id');
$toDay = date('Y-m-d H:i:s');
$atcl_vrtc_way = 'R'; //검증구분
$atcl_vr_sq = $this->request->getPost('rcpt_key');
// $atcl_no = $this->request->getPost('atcl_no');
$reg_conf_yn_1 = $this->request->getPost('reg_conf_yn_1'); //확인내용
$reg_conf_yn_2 = $this->request->getPost('reg_conf_yn_2'); //매물주소
$reg_conf_yn_3 = $this->request->getPost('reg_conf_yn_3'); //의뢰인정보
$reg_conf_yn_info_2 = $this->request->getPost('reg_conf_yn_info_2'); //매물주소
$reg_conf_yn_info_3 = $this->request->getPost('reg_conf_yn_info_3'); //의뢰인정보
$memo = $this->request->getPost('memo'); //메모
$owner_verifiable = $this->request->getPost('owner_verifiable'); //실소유주 확인여부
$noimg_chk_chk = $this->request->getPost('noimg_chk_chk'); // 등기부등본이미지 파일없음.
$img_chk_chk = $this->request->getPost('img_chk_chk'); // 등기소, 리얼탑 열람, 리얼탑 기열람, 열람
$atcl_vrtc_type = $this->request->getPost('atcl_vrtc_type'); // 검증구분
$vrfc_type_sub = $this->request->getPost('vrfc_type_sub'); // 하위검증구분
$arr_uncnfrm_status = $this->request->getPost('arr_uncnfrm_status'); // 등기부등본 미확인여부 상세
//상태가 이미 등기부등본확인중 이상이면 저장하지 않는다.
$resStat = $this->model->chkStat($atcl_vr_sq);
$v2_vrfc_req = $v2DailyModel->get_v2_vrfc_req($atcl_vr_sq);
$rlet_type_cd = $model415->get_rlet_type_cd($atcl_vr_sq);
if ((int) $resStat['stat_cd'] >= 60 || (int) $resStat['stat_cd'] == 19) {
throw new \Exception('이미 저장된 데이터입니다.');
} else {
$resultCnt = $this->model->chkRegiTryCnt($atcl_vr_sq); //1차검증인지 2차검증인지 확인 쿼리 : v2_vrfc_req.type_cnt
if ($resultCnt['reg_try_cnt'] == 0) { // 1차 검증일 때
log_message('debug', '713 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 0 ');
$try_cnt = '1';
} else if ($resultCnt['reg_try_cnt'] == 1) { // 2차 검증일 때
log_message('debug', '713 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 1 ');
$try_cnt = '2';
} else {
log_message('debug', '713 page >> 매물번호 : ' . $atcl_vr_sq . ' 등기부등본 불일치 횟수 : 예외처리 ');
$try_cnt = '2';
//$try_cnt = intval($try_cnt) + 1;
}
$result = $this->model->chkConfirm($atcl_vr_sq, $atcl_vrtc_way);
if ($result == 0) { //v2_confirm 존재하지 않는다면
if ($reg_conf_yn_2 == '10000' && $reg_conf_yn_3 == '10000') { //success 여부 판단
$chk_type = '1';
//$chk_delay = '0'; //지연여부
//$chk_zombie = '0'; //좀비매물
} else {
// 2015.06.29 추가
// 불일치가 날 경우에 10분 이내에 다시 불일치 처리 불가능(같은 매물을 두사람이 중복처리할 가능성 사전 방지)
// 1. 현재 매물의 마지막으로 업데이트 된 시간을 가져옴.
// 2. 현재 시간과 비교하여 10분 이내면 경고창을 띄어줌.
$chk_type = '0';
//$chk_delay = '1'; //지연여부
//$chk_zombie = '0'; //좀비매물
$result_tm = $this->model->getUpdateFailTime($atcl_vr_sq);
$update_tm = $result_tm['insert_tm'];
$ten_ago = date("Y-m-d H:i:s", mktime(date("H"), date("i") - 1, date("s"), date("m"), date("d"), date("Y")));
if ($update_tm > $ten_ago) {
// 수정한 시간이 현재시간10분전 보다 클 경우 수정불가능
throw new \Exception('이미 불일치 처리 된 매물입니다.');
}
}
$this->model->insertConfirm($atcl_vr_sq, $atcl_vrtc_way, $chk_type, $try_cnt);
} else {
if ($reg_conf_yn_2 == '10000' && $reg_conf_yn_3 == '10000') { //success 여부 판단
$chk_type = '1';
//$chk_delay = '0'; //지연여부
//$chk_zombie = '0'; //좀비매물
} else {
// 2015.06.29 추가
// 불일치가 날 경우에 10분 이내에 다시 불일치 처리 불가능(같은 매물을 두사람이 중복처리할 가능성 사전 방지)
// 1. 현재 매물의 마지막으로 업데이트 된 시간을 가져옴.
// 2. 현재 시간과 비교하여 10분 이내면 경고창을 띄어줌.
$chk_type = '0';
//$chk_delay = '1'; //지연여부
//$chk_zombie = '0'; //좀비매물
$result_tm = $this->model->getUpdateFailTime($atcl_vr_sq);
$update_tm = $result_tm['insert_tm'];
$ten_ago = date("Y-m-d H:i:s", mktime(date("H"), date("i") - 1, date("s"), date("m"), date("d"), date("Y")));
if ($update_tm > $ten_ago) {
// 수정한 시간이 현재시간10분전 보다 클 경우 수정불가능
throw new \Exception('이미 불일치 처리 된 매물입니다.');
}
}
$this->model->updateConfirm($atcl_vr_sq, $atcl_vrtc_way, $chk_type);
}
$this->model->InsResChar($atcl_vr_sq); //담당자 업데이트
// 모바일v1,v2고 등기부등본 미확인여부 상세 저장
if ($vrfc_type_sub == 'M1' || $vrfc_type_sub == 'O1') {
$this->model->add_cert_uncnfrm_status($atcl_vr_sq, $arr_uncnfrm_status);
if (strpos($arr_uncnfrm_status, '20020') !== false) { //등기부등본 미확인여부 상세에 20020(파일 오첨부)있고
if ($vrfc_type_sub == 'M1') { // 모바일v1일땐 코드 20020,코멘트x
$reg_conf_yn_2 = '20020';
$reg_conf_yn_info_2 = '';
} else { // 모바일v2일땐 일반 불일치코드,코멘트=파일 오첨부
$reg_conf_yn_info_2 = '파일 오첨부';
}
}
}
//v2_check_list 확인여부 INSERT
$this->model->insertChkList($atcl_vr_sq, $atcl_vrtc_way, '21', $reg_conf_yn_2, $reg_conf_yn_info_2);
//v2_check_list 매물주소 INSERT
$this->model->insertChkList($atcl_vr_sq, $atcl_vrtc_way, '22', $reg_conf_yn_3, $reg_conf_yn_info_3);
//memo 저장
$this->model->saveMemo([$memo, $atcl_vr_sq]);
//실소유주 확인 저장
$this->model->update_owner_verifiable($atcl_vr_sq, $owner_verifiable);
$sendData = $this->model->getDatacertAPI($atcl_vr_sq, 'R');
//이미지 파일 없음 && 홍보확인서 V2일 경우
log_message('debug', '713 noimage_chk_chk sendData_return1 => ' . $sendData['atclNo'] . ' ::: ' . json_encode($sendData) . PHP_EOL);
if ($noimg_chk_chk == "Y" && $sendData['vrfcType'] == "D2") {
// $sendData['ownerVerifiable'] = false;
}
$d_yn = $model710->get_send_yn('O');
if ($d_yn['stop_yn'] == 'N') { //전송금지
//1.해당매물정보를v2_stop_api_save_info에다 넣음
$model710->insert_v2_stop_api_save_info($sendData['atclNo'], $atcl_vr_sq, 'O', '');
//2.아무렇지않게 행동한다
$send_result['result'] = 'success';
} else {
//API 호출
$send_result = $naver->certification($sendData['atclNo'], $try_cnt, $sendData['success'], $sendData['checkList'], $sendData['charger'], $sendData['date'], $sendData['modifyInfo'], $sendData['ownerVerifiable']);
}
if ($send_result['result'] == 'success') {
if ($chk_type == '1') {
//상태변경 TABLE INSERT : 등기부등본 확인완료 상태로 변경
$this->model->chgStat($atcl_vr_sq, '45', $toDay);
$chgVrfc45 = $this->model->chgStatVrfc($atcl_vr_sq, '45'); //v2_vrfc_req INSERT
$statFaxUp45 = $this->model->chgStatFax($atcl_vr_sq, '45'); //fax_imgs
//상태변경 TABLE INSERT : 검증완료 상태로 변경
$this->model->chgStat($atcl_vr_sq, '60', $toDay);
$chgVrfc60 = $this->model->chgStatVrfc($atcl_vr_sq, '60'); //v2_vrfc_req INSERT
$statFaxUp60 = $this->model->chgStatFax($atcl_vr_sq, '60'); //fax_imgs
// ★ 검증완료
//0.불일치 이력이 있는지 확인
$cnt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
if (empty($cnt)) { //검증완료일땐 불일치가없어야 통계포함된다
if ($atcl_vrtc_type == 'M' || $atcl_vrtc_type == 'O') { //모바일은 등기가 첨 시작이니까 insert해줘야함
if (!($atcl_vrtc_type == 'M' && in_array($rlet_type_cd['rlet_type_cd'], array('B01', 'B02', 'B03')))) {//만약 분양권들이면 넘어가고 아니면 체크
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인완료 시간
$cert_comple_dt = $model415->get_cert_confTimeForHistory($atcl_vr_sq);
//3.검증완료시간
$finishTime = $model415->get_60_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
}
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인완료 시간
$cert_comple_dt = $model415->get_cert_confTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$model415->update_v2_time_required_Conf_Done($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm']);
}
}
if ($noimg_chk_chk == 'Y') {
$this->model->chgStat($atcl_vr_sq, '70', $toDay);
$this->model->updateStat($atcl_vr_sq, 'Y'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0103', '1', 'add'); // 등기부등본이미지 없음 저장
}
if ($img_chk_chk == 'O') {
$this->model->chgStat($atcl_vr_sq, '76', $toDay);
$this->model->updateStat($atcl_vr_sq, 'O'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0105', '1', 'add'); // (열람)간소화확인으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'T') {
$this->model->chgStat($atcl_vr_sq, '80', $toDay);
$this->model->updateStat($atcl_vr_sq, 'T'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0111', '1', 'add'); // 등기소로 일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'R') {
$this->model->chgStat($atcl_vr_sq, '86', $toDay);
$this->model->updateStat($atcl_vr_sq, 'R'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0107', '1', 'add'); // 리얼탑 열람 일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
} else if ($img_chk_chk == 'G') {
$this->model->chgStat($atcl_vr_sq, '87', $toDay);
$this->model->updateStat($atcl_vr_sq, 'G'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0108', '1', 'add'); // 리얼탑 기열람 일치으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0101', '1', 'add'); // 일치로 저장
}
} else {
if ($atcl_vrtc_type == 'M') {
//상태변경 TABLE INSERT : 등기부등본 확인 불일치 상태로 변경
$result_query7 = $this->model->chgStat($atcl_vr_sq, '49', $toDay);
$chgVrfc49 = $this->model->chgStatVrfc($atcl_vr_sq, '49'); //v2_vrfc_req INSERT
$statFaxUp49 = $this->model->chgStatFax($atcl_vr_sq, '49'); //fax_imgs
//v2_vrfc_req try_cnt 값을 1로 update
$res_try = $this->model->chgRegiTryCnt($atcl_vr_sq, '2');
//상태변경 TABLE INSERT : 검증실패 상태로 변경.
$result_query9 = $this->model->chgStat($atcl_vr_sq, '69', $toDay);
$chgVrfc69 = $this->model->chgStatVrfc($atcl_vr_sq, '69'); //v2_vrfc_req INSERT
$statFaxUp69 = $this->model->chgStatFax($atcl_vr_sq, '69'); //fax_imgs
// ★모바일이고 검증실패
if (!in_array($rlet_type_cd['rlet_type_cd'], array('B01', 'B02', 'B03'))) {//만약 분양권들이면 넘어가고 아니면 체크
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
}
} else {
//상태변경 TABLE INSERT : 등기부등본 확인 불일치 상태로 변경
$result_query7 = $this->model->chgStat($atcl_vr_sq, '49', $toDay);
$chgVrfc49 = $this->model->chgStatVrfc($atcl_vr_sq, '49'); //v2_vrfc_req INSERT
$statFaxUp49 = $this->model->chgStatFax($atcl_vr_sq, '49'); //fax_imgs
//등기부등본 확인중 상태로 변경.
$this->model->saveChangedHistory($atcl_vr_sq, '30', 'C9', $usr_id, '상태변경 : 49 => 30'); //검증결과 변동사항 HISTORY
$chgVrfc40 = $this->model->chgStatVrfc($atcl_vr_sq, '30'); //v2_vrfc_req INSERT
$statFaxUp40 = $this->model->chgStatFax($atcl_vr_sq, '30'); //fax_imgs
if ($try_cnt == '1') {
//v2_vrfc_req try_cnt 값을 1로 update
$this->model->chgRegiTryCnt($atcl_vr_sq, '1');
if ($atcl_vrtc_type == 'T') {
//검증구분이 전화매물일 경우 사전에 일치로 처리된 값을 초기화 시켜준다.
$reset_query = $this->model->resetTelConf($atcl_vr_sq);
}
// ★1차실패
if ($atcl_vrtc_type == 'O') {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$sf = 'F';
$model415->update_v2_time_required_Conf($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $sf);
}
} else if ($try_cnt == '2') {
//v2_vrfc_req try_cnt 값을 2로 update
$this->model->chgRegiTryCnt($atcl_vr_sq, '2');
//상태변경 TABLE INSERT : 검증실패 상태로 변경.
$result_query9 = $this->model->chgStat($atcl_vr_sq, '69', $toDay);
$chgVrfc69 = $this->model->chgStatVrfc($atcl_vr_sq, '69'); //v2_vrfc_req INSERT
$statFaxUp69 = $this->model->chgStatFax($atcl_vr_sq, '69'); //fax_imgs
// ★모바일 이외 검증실패
if ($atcl_vrtc_type == 'O') {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_M_timeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.검증실패시간
$finishTime = $model415->get_69_ForHistory($atcl_vr_sq);
//4.해당 정보를 테이블에 넣는다
$model415->insert_v2_time_required_M($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm'], $finishTime['insert_tm']);
} else {
//1.등기부등본 확인중 시간
$tel_doc_conf_dt = $model415->get_cert_ing_TimeForHistory($atcl_vr_sq);
//2.등기부등본 확인실패 시간
$cert_comple_dt = $model415->get_cert_failTimeForHistory($atcl_vr_sq);
//3.해당 정보를 테이블에 넣는다
$model415->update_v2_time_required_Conf_Done($v2_vrfc_req['atcl_no'], $v2_vrfc_req['cpid'], $atcl_vrtc_type, $tel_doc_conf_dt['insert_tm'], $cert_comple_dt['insert_tm']);
}
}
}
if ($noimg_chk_chk == 'Y') {
$this->model->chgStat($atcl_vr_sq, '70', $toDay);
$this->model->updateStat($atcl_vr_sq, 'Y'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0103', '1', 'add'); // 등기부등본이미지 없음 저장
}
if ($img_chk_chk == 'O') {
$this->model->chgStat($atcl_vr_sq, '77', $toDay);
$this->model->updateStat($atcl_vr_sq, 'O'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0105', '1', 'add'); // (열람)간소화확인으로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'T') {
$this->model->chgStat($atcl_vr_sq, '85', $toDay);
$this->model->updateStat($atcl_vr_sq, 'T'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0112', '1', 'add'); // 등기소 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'R') {
$this->model->chgStat($atcl_vr_sq, '88', $toDay);
$this->model->updateStat($atcl_vr_sq, 'R'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0109', '1', 'add'); // 리얼탑 열람 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
} else if ($img_chk_chk == 'G') {
$this->model->chgStat($atcl_vr_sq, '89', $toDay);
$this->model->updateStat($atcl_vr_sq, 'G'); // reg_status를 업데이트해준다.
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0110', '1', 'add'); // 리얼탑 기열람 불일치로 저장
$v2DailyModel->set_v2_st_daily(NULL, $v2_vrfc_req['cpid'], 'R0102', '1', 'add'); // 불일치로 저장
}
}
} else {
if (isset($send_result['error'])) {
$error_message = $send_result['error']['code'] . "\\n" . $send_result['error']['message'];
// API 호출 에러 발생시 해당 내용들을 DB에 저장해준다.
$err_time = date("Y-m-d H:i:s");
$this->model->saveApiErr($atcl_vr_sq, $send_result['error']['code'], $send_result['error']['message'], $err_time, $v2_vrfc_req['atcl_no']);
throw new \Exception($error_message);
} else {
throw new \Exception('네이버 전송 중 오류가 발생되었습니다. 다시 시도하세요.');
}
}
return $this->response->setJSON([
'code' => '0',
'msg' => 'success'
]);
}
} catch (\Exception $e) {
return $this->response->setJSON([
'code' => '9',
'msg' => $e->getMessage(),
]);
}
}
// 다음매물확인
public function nextRegi()
{

View File

@@ -13,11 +13,32 @@ class AuthCheck implements FilterInterface
$session = session();
log_message('debug', 'URI PATH: ' . service('uri')->getPath());
try {
// 세션 읽기 시도
$loggedIn = $session->get('logged_in');
// 로그인 체크
if (!$session->get('logged_in')) {
if (!$loggedIn) {
// 로그인 안 되어 있으면 로그인 페이지로
return redirect()->to('/login');
}
} catch (\Exception $e) {
// 세션 오류 (Redis 다운 등) - 모든 예외 catch
log_message('error', '[SESSION ERROR in AuthCheck] ' . $e->getMessage());
// AJAX 요청인 경우 JSON 응답
if ($request->isAJAX()) {
return service('response')
->setStatusCode(503)
->setJSON([
'code' => '8',
'msg' => '세션 서비스 오류입니다. 페이지를 새로고침 해주세요. (Redis)'
]);
}
// 일반 요청인 경우 로그인 페이지로 리다이렉트 (에러 메시지 포함)
return redirect()->to('/login')->with('error', '세션 서비스 오류입니다. 시스템 관리자에게 문의해주세요.');
}
}
public function after(RequestInterface $request, ResponseInterface $response, $arguments = null)

View File

@@ -7,40 +7,33 @@ if (!function_exists('limitHscpMarketPriceInfo')) {
* @param string $ptp_no 평형코드
* @param string $atcl_amt 가격
*/
function limitHscpMarketPriceInfo($CI, $trade_type, $hscp_no, $ptp_no, $atcl_amt)
function limitHscpMarketPriceInfo($trade_type, $hscp_no, $ptp_no, $atcl_amt)
{
$return = array();
if (!empty($hscp_no) && !empty($ptp_no)) {
$hscpMarketPriceInfo = $CI->call_kiso_api->hscpMarketPriceInfo($hscp_no, $ptp_no);
$naver = new \App\Libraries\NaverApiClient();
$hscpMarketPriceInfo = $naver->getComplexPriceByUnitType((int)$hscp_no, (int)$ptp_no);
if (isset($hscpMarketPriceInfo['error'])) { //결과값 확인
if ($hscpMarketPriceInfo['error']['code'] == 'VC027') {
$return = array();
} else {
$return = $hscpMarketPriceInfo['error'];
}
if (isset($hscpMarketPriceInfo['error']) && $hscpMarketPriceInfo['error']) { //결과값 확인
log_message('error', '네이버 시세 API 호출 실패: ' . json_encode($hscpMarketPriceInfo));
return array();
} else {
$limitH = 0;
$limitL = 0;
$sise = array();
$sise = $hscpMarketPriceInfo['data'];
// 상한가, 하한가 체크 ( 상한가 * 2, 하한가 * 0.7) 이내의 범위에 가격이 있어야 함.
if ($trade_type == 'A1') {
// 매매
if (isset($hscpMarketPriceInfo['result']['deal_uplmt_prc'])) {
$limitH = $hscpMarketPriceInfo['result']['deal_uplmt_prc'];
}
if (isset($hscpMarketPriceInfo['result']['deal_lwlmt_prc'])) {
$limitL = $hscpMarketPriceInfo['result']['deal_lwlmt_prc'];
}
$limitH = $sise['dealCeilingPrice'] ?? 0;
$limitL = $sise['dealFloorPrice'] ?? 0;
} elseif ($trade_type == 'B1') {
// 전세
if (isset($hscpMarketPriceInfo['result']['lease_uplmt_prc'])) {
$limitH = $hscpMarketPriceInfo['result']['lease_uplmt_prc'];
}
if (isset($hscpMarketPriceInfo['result']['lease_lwlmt_prc'])) {
$limitL = $hscpMarketPriceInfo['result']['lease_lwlmt_prc'];
}
$limitH = $sise['leaseCeilingPrice'] ?? 0;
$limitL = $sise['leaseFloorPrice'] ?? 0;
}
if (!empty($limitH)) {
@@ -316,3 +309,146 @@ function getOwnerTypeCodeNo($code)
break;
}
}
/**
* 무엇이 변경되었는지 확인한다.
* $table(DB의 원래 데이터), data (변경된 내용) ==> array
*/
function what_is_changed($table, $data){
$return = '';
if (empty($table) || empty($data)){
log_message('warning', 'what_is_changed 함수에 빈 데이터 전달 | table: ' . json_encode($table) . ', data: ' . json_encode($data));
return $return;
}
foreach ( $data as $key => $value ) {
if (!array_key_exists($key, $table)) {
$table[$key] = '';
}
if (strcmp(trim((string) $table[$key]), trim((string) $value)) != 0){
switch ( $key ) {
case 'trade_type': // 거래구분
$return .= ', 거래구분 : ';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_product_info2': // 매매, 전세, 월세보증금
$return .= ', 거래가 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_product_info3': // 월세
$return .= ', 월세 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_dtl_addr': // 상세주소
$return .= ', 상세주소 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_li_addr': //리 주소
$return .= ', 리 주소 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_jibun_addr': //지번 주소
$return .= ', 지번 주소 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_etc_addr': //기타 주소
$return .= ', 기타 주소 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_ref_addr': // 상세주소
$return .= ', 기타주소2 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_ho': // 기타주소
$return .= ', 기타주소 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_hscp_no': // 단지
$return .= ', 단지번호 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_ptp_no': // 평형
$return .= ', 평형 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'rcpt_floor': // 층
$return .= ', 층 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'exp_spc_yn': // 층
$return .= ', 면적확인여부 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'excls_spc1': // 층
$return .= ', 전용면적 첫번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'excls_spc2': // 층
$return .= ', 전용면적 두번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'room_cnt': // 층
$return .= ', 방개수 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'sply_spc': // 층
$return .= ', 공급면적 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'share_spc': // 층
$return .= ', 공용면적 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'tot_spc': // 층
$return .= ', 연면적 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'tot_spc1': // 층
$return .= ', 연면적 첫번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'tot_spc2': // 층
$return .= ', 연면적 두번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'grnd_spc1': // 층
$return .= ', 대지면적 첫번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'grnd_spc2': // 층
$return .= ', 대지면적 두번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'grnd_spc3': // 층
$return .= ', 대지면적 세번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'grnd_spc4': // 층
$return .= ', 대지면적 네번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'grnd_spc5': // 층
$return .= ', 대지면적 다섯번째 값 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'spc_stat': // 층
$return .= ', 면적구분 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
case 'request_msg': // 층
$return .= ', 메모변경 :';
$return .= $table[$key] . ' => ' . $value . "\n";
break;
// case 'rcpt_x': // 좌표 x 12x.xxxxx (경도: longitude)
// $return .= '거래구분 :';
// break;
// case 'rcpt_y': // 좌표 y 3x.xxxx (위도: latitude)
// $return .= '거래구분 :';
// break;
}
}
}
return trim(substr($return, 1));
}

View File

@@ -6,7 +6,7 @@ if (! function_exists('write_custom_log')) {
*/
function write_custom_log($message, $level = 'INFO', $type = 'service')
{
$logDir = WRITEPATH . 'logs/worker';
$logDir = WRITEPATH . 'logs';
if (!is_dir($logDir)) {
@mkdir($logDir, 0777, true);
}
@@ -31,8 +31,8 @@ if (! function_exists('write_custom_log')) {
}
// ----------------------------
$suffix = ($type === 'failed') ? '_failed' : '';
$logFile = $logDir . '/' . date('Y-m-d') . $suffix . '.log';
$suffix = ($type === 'failed') ? '-failed' : '';
$logFile = $logDir . '/log-' . date('Y-m-d') . $suffix . '.log';
$timestamp = date('Y-m-d H:i:s');
$singleLine = str_replace(["\r", "\n", "\t"], " ", $message);

View File

@@ -0,0 +1,35 @@
<?php
if (!function_exists('write_query_log')) {
/**
* SQL 쿼리 로그를 writable/logs/sql-query-{date}.log에 기록
*
* @param string $message 로그 메시지
* @param string $sql SQL 쿼리 (선택)
*/
function write_query_log(string $message, string $sql = '')
{
$logDir = WRITEPATH . 'logs';
$logFile = $logDir . '/sql-query-' . date('Y-m-d') . '.log';
$timestamp = date('Y-m-d H:i:s');
$logMessage = "[{$timestamp}] {$message}";
if (!empty($sql)) {
$logMessage .= "\nSQL: {$sql}";
}
$logMessage .= "\n" . str_repeat('-', 80) . "\n";
// 로그 디렉토리 확인 및 생성
if (!is_dir($logDir)) {
mkdir($logDir, 0755, true);
}
// 파일에 쓰기
file_put_contents($logFile, $logMessage, FILE_APPEND | LOCK_EX);
// log_message도 호출 (작동하면 좋고, 안되도 파일에는 기록됨)
log_message('error', $message);
}
}

View File

@@ -0,0 +1,82 @@
<?php
if (!function_exists('get_redis_connection')) {
/**
* Redis 연결을 반환하는 헬퍼 함수
* .env 환경변수에서 설정을 읽어 Redis에 연결합니다.
*
* @param string $type 'worker' 또는 'session' (기본값: 'worker')
* @return Redis|false Redis 객체 또는 연결 실패 시 false
* @throws RedisException
*/
function get_redis_connection(string $type = 'worker')
{
$redis = new \Redis();
try {
// 타입에 따라 다른 환경변수 사용
if ($type === 'session') {
$host = env('SESSION_REDIS_HOST', '127.0.0.1');
$port = env('SESSION_REDIS_PORT', '6379');
$database = env('SESSION_REDIS_DATABASE', '0');
$password = env('SESSION_REDIS_PASSWORD', '');
} else {
// worker, default
$host = env('REDIS_HOST', '127.0.0.1');
$port = env('REDIS_PORT', '6379');
$database = env('REDIS_DATABASE', '9');
$password = env('REDIS_PASSWORD', '');
}
// Redis 연결 (타임아웃: 0.5초)
$timeout = 0.5;
$success = $redis->connect($host, (int)$port, $timeout);
if (!$success) {
log_message('error', "Redis connection failed: {$host}:{$port}");
return false;
}
// 비밀번호 인증 (있는 경우)
if (!empty($password)) {
$redis->auth($password);
}
// 데이터베이스 선택
$redis->select((int)$database);
return $redis;
} catch (\RedisException $e) {
log_message('error', "Redis connection error: " . $e->getMessage());
return false;
}
}
}
if (!function_exists('get_redis_config')) {
/**
* Redis 설정 정보를 배열로 반환
*
* @param string $type 'worker' 또는 'session'
* @return array Redis 설정 배열
*/
function get_redis_config(string $type = 'worker'): array
{
if ($type === 'session') {
return [
'host' => env('SESSION_REDIS_HOST', '127.0.0.1'),
'port' => env('SESSION_REDIS_PORT', '6379'),
'database' => env('SESSION_REDIS_DATABASE', '0'),
'password' => env('SESSION_REDIS_PASSWORD', ''),
];
}
return [
'host' => env('REDIS_HOST', '127.0.0.1'),
'port' => env('REDIS_PORT', '6379'),
'database' => env('REDIS_DATABASE', '9'),
'password' => env('REDIS_PASSWORD', ''),
];
}
}

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

@@ -3,6 +3,8 @@
namespace App\Libraries;
use App\Models\common\CommonModel;
use App\Models\v2\M712Model;
use CodeIgniter\Model;
class NaverApiClient
{
@@ -39,13 +41,36 @@ class NaverApiClient
* object $space 면적정보[비공동] (supplySpace,exclusiveSpace,totalSpace,groundSpace,buildingSpace)
* object $facilities 비공동시설정보 (roomCount)
*/
/** 현장확인 수정시 */
public function updateArticleInfo(string $articleNumber, array $updateData, string $charger = 'admin'): ?array
{
$this->charger = $charger;
$url = "{$this->baseUrl}/kiso/center/verification-site/{$articleNumber}?charger={$this->charger}";
log_message('info', "[updateArticleInfo] 호출됨 - URL: {$url}, 데이터: " . json_encode($updateData, JSON_UNESCAPED_UNICODE));
$result = $this->request('PUT', $url, $updateData);
log_message('info', "[updateArticleInfo] 결과 - " . ($result === null ? 'NULL' : json_encode($result, JSON_UNESCAPED_UNICODE)));
return $result;
}
/** 일반매물 수정시 */
public function v2updateArticleInfo(string $articleNumber, array $updateData, string $charger = 'admin'): ?array
{
$this->charger = $charger;
$url = "{$this->baseUrl}/kiso/center/verification-article/{$articleNumber}?charger={$this->charger}";
return $this->request('PUT', $url, $updateData);
log_message('info', "[v2updateArticleInfo] 호출됨 - URL: {$url}, 데이터: " . json_encode($updateData, JSON_UNESCAPED_UNICODE));
$result = $this->request('PUT', $url, $updateData);
log_message('info', "[v2updateArticleInfo] 결과 - " . ($result === null ? 'NULL' : json_encode($result, JSON_UNESCAPED_UNICODE)));
return $result;
}
/**
* [POST] 4.매물검증 결과관리
* API:POST /kiso/center/verification-article/{매물번호}/report?charger={담당자명}
@@ -106,9 +131,132 @@ class NaverApiClient
$this->charger = $charger;
$url = "{$this->baseUrl}/kiso/center/verification-article/price/{$articleNumber}?charger={$this->charger}";
return $this->request('POST', $url, $priceData);
return $this->request('PATCH', $url, $priceData);
}
/**
* 현장확인 슬롯 동기화
* 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/verification-site/slots";
return $this->request('POST', $url, $syncData);
}
/**
* 현장확인 매물검증 결과 관리
* API: POST /kiso/center/verification-site/{매물번호}/report?charger={담당자명}
* @param string $type 현장확인 S11: 예약, S21: 방문, S31: 검수
* @param string $code 결과코드 10000: 성공, 20000: 실패, 30000: 지연, 20121: 방문전취소, 20122:방문후취소, 20123:촬영후취소
* @param string $message 내용
* @param string $reserveDate 예약 년월일 2005-07-31
*/
public function verificationSiteReport(string $articleNumber, array $reportData, string $charger = 'admin'): ?array
{
$this->charger = $charger;
$url = "{$this->baseUrl}/kiso/center/verification-site/{$articleNumber}/report?charger={$this->charger}";
return $this->request('POST', $url, $reportData);
}
/**
* 특정 단지/평형 시세조회()
* @param Long hscpNo 단지번호
* @param int ptpNo 평형번호
* API: GET /confirms/hscpMarketPriceInfo.nhn?hscpNo={단지번호}&ptpNo={평형번호}
*/
// public function hscpMarketPriceInfo($hscpNo, $ptpNo){
// $url = '/confirms/hscpMarketPriceInfo.nhn';
// $url = $this->commonModel->getCompanyInfo(3);
// $url = $url['api_server'] . $url;
// $data = [
// 'hscpNo' => $hscpNo,
// 'ptpNo' => $ptpNo
// ];
// return $this->request('GET', $url, $data);
// }
public function getComplexPriceByUnitType(int $hscpNo, int $ptpNo): ?array
{
$url = $this->baseUrl . "/kiso/marketprice/complex/{$hscpNo}/pyeong-type/{$ptpNo}";
return $this->request('GET', $url);
}
/**
* 법정동 기준 단지 목록 조회
* API: GET /kiso/complex/legal-division/{법정동코드}
* legalDivisionNumber : 법정동 코드
*/
public function getComplexList($legalDivisionNumber, $realEstateType = null)
{
$url = $this->baseUrl . "/kiso/complex/legal-division/{$legalDivisionNumber}";
if ($realEstateType !== null) {
$url .= "?realEstateType={$realEstateType}";
}
return $this->request('GET', $url);
}
/**
* 단지평형목록 조회(아파트/오피스텔)
*/
public function getPyeongTypeList($complexNumber){
$url = $this->baseUrl . "/kiso/complex/{$complexNumber}/pyeongs";
return $this->request('GET', $url);
}
/**
* 빌라 단지 평형 목록 조회
*/
public function getVillaPyeongTypeList($complexNumber){
$url = $this->baseUrl . "/kiso/complex/villa/{$complexNumber}/pyeongs";
return $this->request('GET', $url);
}
/**
* 단지 상세 조회
*/
public function getComplexDetail($complexNumber){
$url = $this->baseUrl . "/kiso/complex/{$complexNumber}";
return $this->request('GET', $url);
}
/**
* 빌라 단지 상세 조회
*/
public function getVillaComplexDetail($complexNumber){
$url = $this->baseUrl . "/kiso/complex/villa/{$complexNumber}";
return $this->request('GET', $url);
}
/**
* 빌라 단지 동호수 조회
*/
public function getVillaBuildingList($complexNumber){
$url = $this->baseUrl . "/kiso/complex/villa/{$complexNumber}/buildings";
return $this->request('GET', $url);
}
/**
* 현장확인 동기화 결과 전송
* API: GET /site/submitSyncResult.nhn?reserveNoList={예약번호리스트}
* @param string reserveNoList 예약번호 리스트 (쉼표로 구분된 문자열, 예: "12345,67890,54321")
*/
public function submitSyncResult(string $reserveNoList): ?array
{
$url = "{$this->baseUrl}/site/submitSyncResult.nhn";
@@ -122,7 +270,7 @@ class NaverApiClient
*/
public function aptDetail($hscpNo)
{
$url = $this->commonModel->getCompanyInfo(2);
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/confirms/APTDetail?hscpNo={$hscpNo}";
return $this->request('GET', $url);
}
@@ -134,7 +282,7 @@ class NaverApiClient
public function villaDetail($hscpNo)
{
$url = $this->commonModel->getCompanyInfo(2);
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/confirms/villa/{$hscpNo}";
return $this->request('GET', $url);
}
@@ -322,15 +470,127 @@ class NaverApiClient
return $this->request('POST', $url, $postData);
}
/**
* 등기부 등본 확인 결과
* 712 OwnerVerifiable 전송 오류 우회 테스트
*/
public function certification_712($atclNo, $type, $success, $checkList, $charger, $date, $modifyInfo, $ownerVerifiable)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/confirms/certification";
$model712 = new M712Model();
$data = $model712->getOwnerVerifiable($atclNo);
$ov = $data['OwnerVerifiable_change'];
if (isset($ov)) {
if ($ov > 0) {
$ownerVerifiable = true;
} else {
$ownerVerifiable = false;
}
} else {
$ownerVerifiable = null;
}
$postData = [
"atclNo" => $atclNo,
"type" => $type,
"success" => $success,
"checkList" => $checkList,
"charger" => $charger,
"date" => $date,
"modifyInfo" => $modifyInfo,
"ownerVerifiable" => $ownerVerifiable
];
log_message('debug', '712 certification_712 => ' . $atclNo . ' ::: ' . json_encode($postData) . PHP_EOL);
return $this->request('POST', $url, $postData);
}
/**
* 현장확인 거주인 여부 변경
*/
public function residentsExistence($reserveNumber, $isResidentsExist)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/residents/existence";
$postData = [
'reserveNumber' => $reserveNumber,
'isResidentsExist' => $isResidentsExist
];
return $this->request('POST', $url, $postData);
}
/**
* 예약확인 완료
*/
public function reserveSuccess($reserveNo, $modyfyYn, $agency, $team, $staff, $staffTel, $reserveYmd, $apm)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/site/reserveSuccess.nhn";
$getData = ['reserveNo' => $reserveNo, 'modyfyYn' => $modyfyYn, 'agency' => $agency, 'team' => $team, 'staff' => $staff, 'staffTel' => $staffTel, 'reserveYmd' => $reserveYmd, 'apm' => $apm];
return $this->request('POST', $url, $getData);
}
/**
* 예약확인 실패
*/
public function reserveFail($reserveNo, $errorCode, $etcTxt)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/site/reserveFail.nhn";
$getData = ['reserveNo' => $reserveNo, 'errorCode' => $errorCode, 'errorDesc' => $etcTxt];
return $this->request('POST', $url, $getData);
}
/**
* 촬영 실패
*/
public function shootFail($reserveNo, $errorCode, $etcTxt)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/site/shootFail.nhn";
$getData = ['reserveNo' => $reserveNo, 'errorCode' => $errorCode, 'errorDesc' => $etcTxt];
return $this->request('POST', $url, $getData);
}
/**
* 현장확인2 및 썸네일 검수 실패
*/
public function inspectFail($reserveNumber, $failDescription)
{
$url = $this->commonModel->getCompanyInfo(3);
$url = $url['api_server'] . "/site/vr/inspect/fail";
$postData = [
'reserveNumber' => $reserveNumber,
'failDescription' => $failDescription
];
return $this->request('POST', $url, $postData);
}
/**
* 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);
@@ -363,7 +623,7 @@ class NaverApiClient
'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9'
]);
}
} elseif ( $method === 'PATCH') {
} elseif ($method === 'PATCH') {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
if ($data) {
$payload = json_encode($data);
@@ -378,14 +638,34 @@ 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 [
'error' => true,
'error_type' => 'CURL_ERROR',
'curl_errno' => $curlErrno,
'curl_error' => $curlError,
'url' => $url
];
}
// 결과 로그 기록 (성공/실패 모두 기록하여 추적 가능하게 함)
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;
return [
'error' => true,
'error_type' => 'HTTP_ERROR',
'http_code' => $httpCode,
'response' => $response,
'url' => $url
];
}
return json_decode($response, true);

View File

@@ -0,0 +1,47 @@
<?php
namespace App\Models\Entities;
use CodeIgniter\Model;
class ChangedHistoryModel extends Model
{
protected $table = 'changed_history';
protected $primaryKey = 'seq';
protected $useAutoIncrement = true;
protected $returnType = 'array';
protected $protectFields = true;
protected $allowedFields = [
'rcpt_sq',
'rcpt_stat',
'changed_type',
'changed_id',
'changed_tm',
'remark',
];
/**
* 정보변경 이력 1건 저장
*/
public function addHistory(
int $rcptSq,
?string $rcptStat,
?string $changedType,
?string $changedId,
?string $remark,
?string $changedTm = null
): bool {
$data = [
'rcpt_sq' => $rcptSq,
'rcpt_stat' => $rcptStat,
'changed_type' => $changedType,
'changed_id' => $changedId,
'changed_tm' => $changedTm ?? date('Y-m-d H:i:s'),
'remark' => $remark,
];
return $this->insert($data) !== false;
}
}

View File

@@ -13,7 +13,10 @@ class ReceiptModel extends Model
protected $allowedFields = [
'comp_sq', 'rcpt_rating', 'rcpt_key', 'rcpt_atclno', 'rcpt_type',
'rcpt_product', 'rcpt_product_nm', 'rcpt_product_info1', 'rcpt_product_info2',
'rcpt_product_info3', 'rcpt_office', 'rcpt_agent', 'rcpt_sido', 'rcpt_hscp_nm',
'rcpt_product_info3', 'rcpt_product_info4', 'rcpt_product_info5', 'rcpt_product_info6',
'trade_type', 'rcpt_ptp_no', 'rcpt_hscp_no',
'dealAmount', 'warrantyAmount', 'leaseAmount', 'preSaleAmount', 'premiumAmount', 'preSaleOptionAmount',
'rcpt_office', 'rcpt_agent', 'rcpt_sido', 'rcpt_hscp_nm',
'rcpt_dtl_addr', 'rcpt_etc_addr', 'rcpt_floor', 'rcpt_floor2', 'rcpt_tm',
'rcpt_stat', 'rcpt_x', 'rcpt_y', 'agent_nm', 'agent_head_tel', 'rsrv_date',
'insert_tm', 'rcpt_cpid', 'room_cnt', 'isSiteVRVerification'
@@ -104,4 +107,5 @@ class ReceiptModel extends Model
'total' => $totalCount
];
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace App\Models\Entities;
use CodeIgniter\Model;
class RegionModel extends Model
{
protected $table = 'region_codes';
protected $primaryKey = 'region_cd';
protected $returnType = 'array';
protected $useSoftDeletes = false;
protected $useTimestamps = false;
protected $allowedFields = [
'region_cd', 'region_nm', 'use_yn', 'dept_sq', 'usr_sq'
];
/**
* 지역 코드로 담당자 정보 조회
*
* @param string $regionCd 지역 코드 (sectorNumber)
* @return array|null ['dept_sq' => 26, 'usr_sq' => 1] 또는 null
*/
public function getChargeByRegionCd($regionCd)
{
if (empty($regionCd)) {
return null;
}
return $this->select('dept_sq, usr_sq')
->where('region_cd', $regionCd)
->where('use_yn', 'Y')
->first();
}
}

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

@@ -115,6 +115,22 @@ class DeptModel extends Model
return $query->getResultArray();
}
/**
* 부서검색(상세)
*/
public function getDeptDetail($dept_sq)
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE dept_sq = ?";
$data = array($dept_sq);
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
return $row;
}
// 조직별통계
public function getDeptStatistics($data)
{

View File

@@ -212,75 +212,88 @@ class ProcessibleModel extends Model
// 지역별 수량 저장
public function saveArea($data)
{
$this->db->transStart();
$usr_sq = session('usr_sq');
$now = date('Y-m-d H:i:s');
$sql = "INSERT INTO service_count
(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)
";
$datas = [
$data['sc_date'],
$data['region_cd'],
$data['am_cnt'],
$data['pm_cnt'],
((int) $data['am_cnt'] + (int) $data['pm_cnt']),
$usr_sq,
$usr_sq
$insertData = [
'sc_date' => $data['sc_date'],
'region_cd' => $data['region_cd'],
'am_cnt' => $data['am_cnt'],
'pm_cnt' => $data['pm_cnt'],
'day_cnt' => (int)$data['am_cnt'] + (int)$data['pm_cnt'],
'insert_usr' => $usr_sq,
'insert_tm' => $now,
'update_usr' => $usr_sq,
'update_tm' => $now
];
if ($this->db->query($sql, $datas) === false) {
return [
'success' => false,
'msg' => '저장실패',
];
}
$this->db->transComplete();
// CI4 Query Builder upsert (INSERT ... ON DUPLICATE KEY UPDATE)
$result = $this->db->table('service_count')->upsert($insertData);
return [
'success' => true,
'success' => $result !== false,
'msg' => $result !== false ? '성공' : '저장실패'
];
}
public function saveCount($data)
{
$this->db->transStart();
$usr_sq = session('usr_sq');
$now = date('Y-m-d H:i:s');
$sql = "INSERT INTO service_count
(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)
";
$datas = [
'0000-00-00',
$data['region_cd'],
$data['am_cnt'],
$data['pm_cnt'],
((int) $data['am_cnt'] + (int) $data['pm_cnt']),
$usr_sq,
$usr_sq
$insertData = [
'sc_date' => '0000-00-00',
'region_cd' => $data['region_cd'],
'am_cnt' => $data['am_cnt'],
'pm_cnt' => $data['pm_cnt'],
'day_cnt' => (int)$data['am_cnt'] + (int)$data['pm_cnt'],
'insert_usr' => $usr_sq,
'insert_tm' => $now,
'update_usr' => $usr_sq,
'update_tm' => $now
];
if ($this->db->query($sql, $datas) === false) {
// CI4 Query Builder upsert
$result = $this->db->table('service_count')->upsert($insertData);
// 실행된 쿼리 로그 출력
$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();
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();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -8,64 +8,85 @@ class CodeModel extends Model
/**
* 코드목록 읽어오기(Y만)
*/
public function getCodeList($category)
{
$sql = "SELECT category, category_nm, cd, cd_nm FROM codes" .
" WHERE category = ?" .
" AND use_yn = 'Y'" .
" ORDER BY view_odr";
$data = [$category];
$query = $this->db->query($sql, $data);
return $query->getResultArray();
}
public function getCodeLists($data): array
public function getCodeList(string $category): array
{
return $this->db->table('codes')
->select('category, category_nm, cd, cd_nm')
->whereIn('category', $data)
->where('category', $category)
->where('use_yn', 'Y')
->orderBy('view_odr')
->orderBy('view_odr', 'asc')
->get()
->getResultArray();
}
public function getCategoryCodeList($category = [], $useYn = '')
public function getCodeLists(array $categories): array
{
$this->db->select('category, cd, cd_nm, use_yn');
$this->db->from('codes');
$this->db->where_in('category', $category);
if (!empty($useYn)) {
$this->db->where('use_yn', $useYn);
if (empty($categories)) {
return [];
}
$this->db->order_by('category', 'asc');
$this->db->order_by('view_odr', 'asc');
$query = $this->db->get();
$result = $this->db->table('codes')
->select('category, category_nm, cd, cd_nm')
->whereIn('category', $categories)
->where('use_yn', 'Y')
->orderBy('category', 'asc')
->orderBy('view_odr', 'asc')
->get()
->getResultArray();
//echo $this->db->last_query()."<br>";
$groupedData = [];
foreach ($result as $item) {
$category = $item['category'];
if (!isset($groupedData[$category])) {
$groupedData[$category] = [
'name' => $item['category_nm'],
'items' => []
];
}
$groupedData[$category]['items'][$item['cd']] = $item['cd_nm'];
}
return $groupedData;
}
public function getCategoryCodeList(array $category = [], string $useYn = ''): array
{
if (empty($category)) {
return [];
}
$builder = $this->db->table('codes');
$builder->select('category, cd, cd_nm, use_yn');
$builder->whereIn('category', $category);
if (!empty($useYn)) {
$builder->where('use_yn', $useYn);
}
$builder->orderBy('category', 'asc');
$builder->orderBy('view_odr', 'asc');
$query = $builder->get();
//여기 아래부분을 해줘야 배열을 카테고리로 뽑아쓸수있다 위에는 배열에 배열이담김
$codes = [];
foreach ($query->getResultArray() as $row) {
$codes[$row['category']][] = ['cd' => $row['cd'], 'cd_nm' => $row['cd_nm']];
}
return $codes;
}
/**
* 코드 상세
*/
public function getCodeDetail($category, $code)
public function getCodeDetail(string $category, string $code): array
{
$sql = "SELECT category, category_nm, cd, cd_nm FROM codes" .
" WHERE category = ? and cd = ?";
$data = [$category, $code];
$query = $this->db->query($sql, $data);
$row = $query->getResultArray();
return $row;
return $this->db->table('codes')
->select('category, category_nm, cd, cd_nm')
->where('category', $category)
->where('cd', $code)
->get()
->getResultArray();
}
}

View File

@@ -99,10 +99,11 @@ class AssignModel extends Model
public function getTotalCount($data)
{
$sql = "SELECT
COUNT(*) AS cnt
COUNT(DISTINCT b.usr_sq) AS cnt
FROM result a
INNER JOIN users b ON b.usr_sq = a.usr_sq
INNER JOIN receipt d ON d.rcpt_sq = a.rcpt_sq
INNER JOIN departments c ON c.dept_sq = a.dept_sq
WHERE 1=1 ";
@@ -138,13 +139,13 @@ class AssignModel extends Model
if (!empty($data['srchTxt'])) {
if ($data['srchType'] === "1") {
$sql .= "AND usr_id like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
$sql .= "AND b.usr_id like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
} else if ($data['srchType'] === "2") {
$sql .= "AND usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
$sql .= "AND b.usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
} else {
$sql .= "AND (
usr_id like CONCAT('%', '{$data['srchTxt']}', '%' )
OR usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' )
b.usr_id like CONCAT('%', '{$data['srchTxt']}', '%' )
OR b.usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' )
) ";
}
}
@@ -157,6 +158,10 @@ class AssignModel extends Model
public function getUserList($start, $end, $data)
{
$sql = "SELECT
sub.*,
COUNT(*) OVER() as total_count
FROM (
SELECT
b.usr_nm, b.usr_id, b.usr_sq
, SUM(CASE WHEN a.rsrv_tm_hour IN ('00','01','02','03','04','05','06','07','08','09','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24') THEN 1 ELSE 0 END) TODAY
, SUM(CASE WHEN a.rsrv_tm_ap = 'AM' AND a.rsrv_tm_hour = '09' THEN 1 ELSE 0 END) AM09
@@ -174,7 +179,8 @@ class AssignModel extends Model
, SUM(CASE WHEN a.rsrv_tm_ap = 'PM' AND a.rsrv_tm_hour IN ('00','08','09','10','11','12','20','21','22','23','24') THEN 1 ELSE 0 END) PMETC
FROM result a
INNER JOIN users b ON b.usr_sq = a.usr_sq
INNER JOIN receipt d ON d.rcpt_sq = a.rcpt_sq
INNER JOIN departments c ON c.dept_sq = a.dept_sq
WHERE 1=1 ";
@@ -210,20 +216,20 @@ class AssignModel extends Model
if (!empty($data['srchTxt'])) {
if ($data['srchType'] === "1") {
$sql .= "AND usr_id like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
$sql .= "AND b.usr_id like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
} else if ($data['srchType'] === "2") {
$sql .= "AND usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
$sql .= "AND b.usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' ) ";
} else {
$sql .= "AND (
usr_id like CONCAT('%', '{$data['srchTxt']}', '%' )
OR usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' )
b.usr_id like CONCAT('%', '{$data['srchTxt']}', '%' )
OR b.usr_nm like CONCAT('%', '{$data['srchTxt']}', '%' )
) ";
}
}
$sql .= "GROUP BY b.usr_id, b.usr_nm ";
$sql .= "LIMIT {$start}, {$end}";
$sql .= "GROUP BY b.usr_id, b.usr_nm
) sub
LIMIT {$start}, {$end}";
$query = $this->db->query($sql);

View File

@@ -0,0 +1,119 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
/**
* BaseV2Model
* V2 모듈 공통 메서드: 지역/본부/팀/담당자 조회
* 각 모듈 Model은 이 클래스를 상속받아 getTotalCount/getResultList/getExcelList 등 모듈 고유 메서드만 구현합니다.
*/
abstract class BaseV2Model extends Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부 조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 담당자 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
}

View File

@@ -2,121 +2,11 @@
namespace App\Models\v2;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M701Model extends Model
class M701Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
$sql = "SELECT
@@ -144,7 +34,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 +254,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 +443,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'])) {
@@ -1345,7 +1235,7 @@ class M701Model extends Model
$comment = implode('|', $comment);
}
$usr_sq = $this->session->userdata('usr_sq');
$usr_sq = session('usr_sq');
$sql = "INSERT INTO v2_check_list" .
"(vr_sq, vrfc_type, type, code, comment, insert_user, insert_tm)" .
"VALUES" .

View File

@@ -2,119 +2,10 @@
namespace App\Models\v2;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M702Model extends Model
class M702Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{

View File

@@ -3,119 +3,10 @@ namespace App\Models\v2;
use App\Models\receipt\ReceiptModel;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M703Model extends Model
class M703Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
@@ -2117,8 +2008,8 @@ class M703Model extends Model
*/
public function saveChangeStep($fax_sq, $vr_sq, $stat_cd)
{
$insert_user = $this->session->userdata('usr_sq');
$insert_id = $this->session->userdata('usr_id');
$insert_user = session('usr_sq');
$insert_id = session('usr_id');
$this->db->transStart();

View File

@@ -2,119 +2,10 @@
namespace App\Models\v2;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M704Model extends Model
class M704Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{

View File

@@ -1,119 +1,10 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M705Model extends Model
class M705Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
@@ -1187,7 +1078,7 @@ class M705Model extends Model
public function InsResChar($atcl_vr_sq)
{
$usr_id = $this->session->userdata('usr_id');
$usr_id = session('usr_id');
$sql = "UPDATE v2_article_info" .
" SET reg_charger = ?" .

View File

@@ -2,119 +2,10 @@
namespace App\Models\v2;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M706Model extends Model
class M706Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
@@ -1056,7 +947,7 @@ class M706Model extends Model
public function insertChkList($vr_sq, $vrfc_type, $type, $code, $comment)
{ //v2_check_list INSERT
$usr_sq = $this->session->userdata('usr_sq');
$usr_sq = session('usr_sq');
$sql = "INSERT INTO v2_check_list" .

View File

@@ -3,119 +3,10 @@ namespace App\Models\v2;
use App\Models\receipt\ReceiptModel;
use App\Models\webfax\FaxModel;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M708Model extends Model
class M708Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{

View File

@@ -1,119 +1,10 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M709Model extends Model
class M709Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 사용자 부서 조회
public function getDepartmentPath($usr_sq)

View File

@@ -1,121 +1,11 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M710Model extends Model
class M710Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
$sql = "SELECT

View File

@@ -1,9 +1,9 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M711Model extends Model
class M711Model extends BaseV2Model
{
}

View File

@@ -1,119 +1,10 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M712Model extends Model
class M712Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
@@ -906,6 +797,504 @@ class M712Model extends Model
}
}
/* 현재 상태 확인 */
public function chkStat($vr_sq)
{
$sql = "SELECT stat_cd FROM v2_vrfc_req WHERE vr_sq = ?";
$data = array(
$vr_sq
);
$query = $this->db->query($sql, $data);
return $query->getRowArray();
}
//1차 검증인지 2차 검증인지 확인.
public function chkRegiTryCnt($atcl_vr_sq)
{
$sql = "SELECT reg_try_cnt FROM v2_vrfc_req WHERE vr_sq = ?";
$query = $this->db->query($sql, [$atcl_vr_sq]);
return $query->getRowArray();
}
//검증결과 table에 있는지 확인.
public function chkConfirm($atcl_vr_sq, $reg_yn)
{
$builder = $this->db->table('v2_confirm a');
$builder->select('a.vr_sq');
$builder->where('vr_sq', $atcl_vr_sq);
if ($reg_yn) {
$builder->where('vrfc_type', $reg_yn);
}
$query = $builder->get();
return $query->getNumRows();
}
public function getUpdateFailTime($vr_sq)
{
$sql = "select vr_sq, stat_cd, insert_user, insert_tm " .
"from v2_chg_stat " .
"where vr_sq = ? and stat_cd = '49' " .
"order by insert_tm desc " .
"limit 1";
$data = array($vr_sq);
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
return $row;
}
//v2_confirm INSERT
public function insertConfirm($vr_sq, $vrfc_type, $success, $type, $usr_id = '', $usr_sq = '')
{
if (empty($usr_sq))
$usr_sq = session('usr_sq');
if (empty($usr_id))
$usr_id = session('usr_id');
$sql = "INSERT INTO v2_confirm" .
"(vr_sq, vrfc_type, success, type, charger, date, insert_user, insert_tm, update_user, update_tm)" .
"VALUES" .
"(?, ?, ?, ?, ?, '" . date('YmdHis') . "', ?, NOW(), ?, NOW()) " .
" ON DUPLICATE KEY UPDATE" .
" success=values(success), type=values(type), charger=values(charger), date=values(date)
, update_user=values(update_user), update_tm=values(update_tm)";
$data = array(
$vr_sq,
$vrfc_type,
$success,
$type,
$usr_id,
$usr_sq,
$usr_sq
);
$this->db->query($sql, $data);
}
public function updateConfirm($vr_sq, $vrfc_type, $success)
{
$data = [
'success' => $success,
];
$builder = $this->db->table('v2_confirm');
$builder->where('vr_sq', $vr_sq);
$builder->where('vrfc_type', $vrfc_type);
$builder->update($data);
return [
'error_number' => $this->db->error()['code'],
'error_message' => $this->db->error()['message']
];
}
public function InsResChar($atcl_vr_sq)
{
$usr_id = session('usr_id');
$sql = "UPDATE v2_article_info" .
" SET reg_charger = ?" .
" WHERE vr_sq = ?";
$data = array(
$usr_id,
$atcl_vr_sq
);
//echo $this->db->last_query();
$res = $this->db->query($sql, $data);
$log_v = $this->db->getLastQuery();
log_message('debug', $log_v);
}
public function add_cert_uncnfrm_status($vr_sq, $cert_uncnfrm_status)
{
$sql = "UPDATE v2_article_info_etc" .
" SET cert_uncnfrm_status = ?" .
" WHERE vr_sq = ?";
$data = array(
$cert_uncnfrm_status,
$vr_sq
);
$this->db->query($sql, $data);
}
public function insertChkList($vr_sq, $vrfc_type, $type, $code, $comment)
{ //v2_check_list INSERT
$usr_sq = session('usr_sq');
$sql = "INSERT INTO v2_check_list" .
"(vr_sq, vrfc_type, type, code, comment, insert_user, insert_tm)" .
"VALUES" .
"(?, ?, ?, ?, ?, ?, NOW())" .
" ON DUPLICATE KEY UPDATE" .
" vr_sq=values(vr_sq), vrfc_type=values(vrfc_type), type=values(type), code=values(code), comment=values(comment), insert_user=values(insert_user), insert_tm=values(insert_tm)";
$data = array(
$vr_sq,
$vrfc_type,
$type,
$code,
$comment,
$usr_sq
);
$this->db->query($sql, $data);
}
/**
* update updatedocument_cert_method
*/
public function updatedocument_cert_method($vr_sq, $document_cert_method)
{
$sql = "UPDATE v2_article_info_etc SET " .
" document_cert_method = ? " .
" WHERE vr_sq = ? ";
$document_cert_method = json_encode($document_cert_method, JSON_UNESCAPED_UNICODE);
if ($document_cert_method == 'false') {
$document_cert_method = NULL;
}
$data = array(
$document_cert_method,
$vr_sq
);
$this->db->query($sql, $data);
$s = $this->db->getLastQuery();
log_message('debug', "====updatedocument_cert_method:712====" . $s);
}
public function update_owner_verifiable($vr_sq, $owner_verifiable)
{
$sql = "UPDATE v2_vrfc_req" .
" SET owner_verifiable = ?" .
" WHERE vr_sq = ?";
$data = array(
$owner_verifiable,
$vr_sq
);
$this->db->query($sql, $data);
$s = $this->db->getLastQuery();
log_message('debug', "====update_owner_verifiable:712====" . $s);
}
/* 등기부등본 API 호출*/
public function getDatacertAPI($vr_sq, $vrfc_type = '')
{
// 요청정보
$sql = "SELECT vr_sq, atcl_no, step, cpid, cp_atcl_id, trade_type, realtor_nm, realtor_tel_no, seller_tel_no, vrfc_type, rgbk_confirm, req_type, rdate, stat_cd, try_cnt, insert_user, insert_tm, owner_verifiable" .
" FROM v2_vrfc_req where vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_vrfc_req = $query->getRowArray();
if (!empty($vrfc_type)) {
$row_vrfc_req['vrfc_type'] = $vrfc_type;
}
log_message('debug', 'getDatacertApi_query => ' . $this->db->getLastQuery());
log_message('debug', 'getDatacertApi_result => ' . json_encode($row_vrfc_req));
// 매물정보
$sql = "SELECT vr_sq, atcl_no, cpid, cp_atcl_id, rlet_type_cd, trade_type, address_code, address1, address2, address3, sply_spc, excls_spc, tot_spc, grnd_spc, bldg_spc, deal_amt, wrrnt_amt, lease_amt, isale_amt, prem_amt, sise, floor, rdate, seller_tel_no, seller_nm, realtor_nm, realtor_tel_no, hscp_no, hscp_nm, ptp_no, ptp_nm, charger, req_price_yn, reg_charger, dept1_sq, dept2_sq, reg_dept1_sq, reg_dept2_sq, floor2, vrfc_type_sub" .
" FROM v2_article_info where vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_article_info = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 수정정보
$sql = "SELECT vr_sq, bild_nm, rm_no, floor, address_code, address2, address3, trade_type, deal_amt, wrrnt_amt, lease_amt, isale_amt, prem_amt, sply_spc, excls_spc, tot_spc, grnd_spc, bldg_spc, hscp_no, hscp_nm, ptp_no, ptp_nm, modify_yn, floor2" .
" FROM v2_modify_info where vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_modify_info = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 검증결과
$sql = "SELECT vr_sq, vrfc_type, success, type, charger, date, insert_user, insert_tm, update_user, update_tm, work_type" .
" FROM v2_confirm where vr_sq = ? and vrfc_type = ?";
$query = $this->db->query($sql, [$vr_sq, $row_vrfc_req['vrfc_type']]);
$row_confirm = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 확인정보
$sql = "SELECT a.type, a.code, a.comment, b.ownerNm, b.owner_birth" .
" FROM v2_check_list a " .
" INNER JOIN v2_article_info b on a.vr_sq = b.vr_sq" .
" WHERE a.vr_sq = ? and a.vrfc_type = ?";
$query = $this->db->query($sql, [$vr_sq, $row_vrfc_req['vrfc_type']]);
$res_check_list = $query->getResultArray();
log_message('debug', $this->db->getLastQuery());
log_message('debug', implode(', ', $row_confirm ?? []));
$atclNo = $row_vrfc_req['atcl_no'];
$type = $row_vrfc_req['try_cnt'];
$success = empty($row_confirm['success']) ? false : true;
$charger = $row_confirm['charger'] ?? '';
$date = $row_confirm['date'] ?? '';
switch ($row_vrfc_req['owner_verifiable']) {
case "1":
case "true":
$ownerVerifiable = true;
break;
default:
$ownerVerifiable = false;
break;
}
$checkList = [];
foreach ($res_check_list as $row) {
$checkList[] = [
'type' => $row['type'],
'code' => $row['code'],
'comment' => $row['comment'],
'ownerNm' => $row['ownerNm'],
'ownerBirth' => $row['owner_birth'],
];
}
$modifyInfo = [];
if ($row_modify_info['modify_yn'] == 'Y') {
if (!empty($row_modify_info['hscp_no'])) {
// 공동주택
$modifyInfo = [
'hscpNo' => $row_modify_info['hscp_no'],
'ptpNo' => $row_modify_info['ptp_no'],
'bildNm' => $row_modify_info['address2'],
'rmNo' => $row_modify_info['address3'],
'tradeType' => $row_modify_info['trade_type'],
'dealAmt' => $row_modify_info['deal_amt'],
'wrrntAmt' => $row_modify_info['wrrnt_amt'],
'leaseAmt' => $row_modify_info['lease_amt'],
'isaleAmt' => $row_modify_info['isale_amt'],
'premAmt' => $row_modify_info['prem_amt'],
'floor' => $row_modify_info['floor'],
];
} else {
// 비공동주택
$modifyInfo = [
'addressCode' => $row_modify_info['address_code'],
'address2' => $row_modify_info['address2'],
'address3' => $row_modify_info['address3'],
'tradeType' => $row_modify_info['trade_type'],
'dealAmt' => $row_modify_info['deal_amt'],
'wrrntAmt' => $row_modify_info['wrrnt_amt'],
'leaseAmt' => $row_modify_info['lease_amt'],
'splySpc' => $row_modify_info['sply_spc'],
'exclsSpc' => $row_modify_info['excls_spc'],
'totSpc' => $row_modify_info['tot_spc'],
'grndSpc' => $row_modify_info['grnd_spc'],
'bldgSpc' => $row_modify_info['bldg_spc'],
'floor' => $row_modify_info['floor'],
'floor2' => $row_modify_info['floor2'],
];
}
return [
'atclNo' => $atclNo,
'type' => $type,
'success' => $success,
'checkList' => $checkList,
'charger' => $charger,
'modifyInfo' => $modifyInfo,
'date' => $date,
'vrfcType' => $row_article_info['vrfc_type_sub'],
'ownerVerifiable' => $ownerVerifiable,
];
} else {
return [
'atclNo' => $atclNo,
'type' => $type,
'success' => $success,
'checkList' => $checkList,
'charger' => $charger,
'date' => $date,
'vrfcType' => $row_article_info['vrfc_type_sub'],
'ownerVerifiable' => $ownerVerifiable,
];
}
}
public function get_send_yn($type)
{
$sql = "SELECT stop_yn
FROM v2_stop_api_chg_stat
WHERE TYPE = ?
ORDER BY pk DESC
LIMIT 1";
$date = array(
$type
);
$query = $this->db->query($sql, $date);
$return = $query->getRowArray();
return $return;
}
public function insert_v2_stop_api_save_info($atcl_no, $vr_sq, $type, $fax_sq)
{
$sql = "INSERT INTO v2_stop_api_save_info(atcl_no,vr_sq,type,status,stop_dt,fax_sq)" .
" VALUE(?,?,?,'stop',now(),?)";
$date = array(
$atcl_no,
$vr_sq,
$type,
$fax_sq
);
$this->db->query($sql, $date);
}
/**
* 712 소유자 확인 을 위한 쿼리
*/
public function getOwnerVerifiable($atcl_no)
{
$sql = "select * ,
case
when owner_verifiable = 'true' then '1'
when owner_verifiable = '1' then '1'
when owner_verifiable = 'false' then '0'
when owner_verifiable = '0' then '0'
ELSE null
END AS OwnerVerifiable_change
from v2_vrfc_req where atcl_no = ? ";
$data = array(
$atcl_no
);
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
return $row;
}
public function chgStat($vr_sq, $stat_cd, $insert_tm)
{ //상태변경 TABLE INSERT
$usr_sq = session('usr_sq');
$usr_id = session('usr_id');
$list = $this->get_detail($vr_sq);
$sql = "INSERT INTO v2_chg_stat (vr_sq, stat_cd, insert_user, insert_tm)" .
"VALUES (?, ?, ?, ?)" .
"ON DUPLICATE KEY " .
"UPDATE vr_sq=VALUES(vr_sq), stat_cd=VALUES(stat_cd), insert_user=VALUES(insert_user), insert_tm=VALUES(insert_tm)";
$data = array(
'vr_sq' => $vr_sq,
'stat_cd' => $stat_cd,
'usr_sq' => $usr_sq,
'insert_tm' => $insert_tm
);
$this->db->transStart();
$res = $this->db->query($sql, $data);
$return['error_number'] = $this->db->_error_number();
$return['error_message'] = $this->db->_error_message();
if (empty($return['error_number'])) {
//로그를 남긴다.
if ($this->db->affected_rows() > 0) {
if (!empty($changed)) {
$this->saveChangedHistory($list['data']['vr_sq'], $stat_cd, 'C9', $usr_id, "상태변경 저장"); //검증결과 변동사항 HISTORY
}
}
}
$this->db->transComplete();
}
public function chgStatVrfc($vr_sq, $stat_cd)
{
$data = ['stat_cd' => $stat_cd];
$builder = $this->db->table('v2_vrfc_req');
$builder->where('vr_sq', $vr_sq);
$builder->update($data);
return [
'error_number' => $this->db->error()['code'],
'error_message' => $this->db->error()['message']
];
}
public function chgStatFax($vr_sq, $stat_cd)
{
$data = ['stat_cd' => $stat_cd];
$builder = $this->db->table('fax_imgs');
$builder->where('vr_sq', $vr_sq);
$builder->update($data);
return [
'error_number' => $this->db->error()['code'],
'error_message' => $this->db->error()['message']
];
}
//v2_vrfc_req try_cnt 값 변경.
public function chgRegiTryCnt($vr_sq, $try_cnt)
{
$sql = "UPDATE v2_vrfc_req" .
" SET reg_try_cnt = ?" .
" WHERE vr_sq = ?";
$data = array(
$try_cnt,
$vr_sq
);
$res = $this->db->query($sql, $data);
}
public function resetTelConf($vr_sq)
{
$sql = "update v2_check_list " .
"set code = '' " .
"where type in ('T11', 'T12', 'T13', 'T14') " .
"and vr_sq = ?";
$data = array($vr_sq);
$this->db->query($sql, $data);
}
// 메모저장
public function saveMemo($data)
{
$usr_id = session('usr_id');
$sql = "UPDATE v2_vrfc_req SET
memo = ?
WHERE vr_sq = ?";
if ($this->db->query($sql, $data) === false) {
return [
'success' => false,
'msg' => '파일정보 저장 실패',
];
}
$row = $this->getDetail($data[1]);
$memo = "메모변경 : " . $row['memo'] . " => " . $data[0];
$this->saveChangedHistory($data[1], $row['pre_stat_cd'], 'C19', $usr_id, $memo);
return [
'success' => true
];
}
// 정보변경 이력 저장
public function saveChangedHistory($vr_sq, $stat_cd, $chg_type, $usr_id, $memo)

View File

@@ -1,119 +1,10 @@
<?php
namespace App\Models\v2;
use CodeIgniter\Model;
use App\Models\v2\BaseV2Model;
class M713Model extends Model
class M713Model extends BaseV2Model
{
// 지역 목록 조회
public function getAreaList($sido = '', $gugun = '')
{
if (!empty($gugun)) {
$gugun = substr($gugun, '0', '5');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,5),'00000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000'" .
" AND a.region_cd LIKE '%00'" .
" AND a.use_yn = 'Y'" .
" ORDER BY a.region_nm ASC";
$query = $this->db->query($sql, [$gugun]);
} else if (!empty($sido)) {
$chk_sido = substr($sido, '0', '2');
if ($chk_sido === '36') {
$sido = substr($sido, '0', '4');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm " .
"FROM region_codes a " .
"LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,4),'000000') " .
"WHERE a.region_cd LIKE concat(?, '%') " .
"AND a.region_cd NOT LIKE '%000000' " .
"AND a.region_cd LIKE '%00' " .
"AND a.use_yn = 'Y' " .
"AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000')) " .
"ORDER BY a.region_nm ASC";
} else {
$sido = substr($sido, '0', '2');
$sql = "SELECT a.region_cd, TRIM(REPLACE(a.region_nm, b.region_nm, '')) region_nm" .
" FROM region_codes a" .
" LEFT JOIN region_codes b ON b.region_cd = CONCAT(SUBSTR(a.region_cd,1,2),'00000000')" .
" WHERE a.region_cd LIKE concat(?, '%')" .
" AND a.region_cd NOT LIKE '%00000000'" .
" AND a.region_cd LIKE '%00000'" .
" AND a.use_yn = 'Y'" .
" AND EXISTS (SELECT 'x' FROM region_codes c WHERE c.region_cd LIKE CONCAT(SUBSTR(a.region_cd,1,5),'%') AND c.region_cd > CONCAT(SUBSTR(a.region_cd,1,5),'00000'))" .
" ORDER BY a.region_nm ASC";
}
$query = $this->db->query($sql, [$sido]);
} else {
$sql = "SELECT a.region_cd, a.region_nm " .
"FROM region_codes a " .
"WHERE (a.region_cd LIKE '%00000000' " .
"AND a.use_yn = 'Y') " .
"OR region_cd = 3611000000;";
$query = $this->db->query($sql);
}
return $query->getResultArray();
}
// 소속본부조회
public function getBonbuList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm, dept_desc, dept_head, use_yn, depth, insert_tm, insert_usr, update_tm, update_usr, lft, rgt" .
" FROM departments" .
" WHERE depth = 1" .
" AND use_yn = 'Y'" .
" ORDER BY lft";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 소속팀 조회
public function getTeamList()
{
$sql = "SELECT dept_sq, pdept_sq, dept_nm" .
" FROM departments" .
" WHERE depth = 2" .
" AND use_yn = 'Y'" .
" ORDER BY dept_nm";
$query = $this->db->query($sql);
return $query->getResultArray();
}
// 유저 조회
public function getUserList()
{
$sql = "SELECT
a.usr_sq, a.usr_id, a.usr_nm, a.dept_sq
FROM users a
WHERE
a.usr_level IN ('3','4','40','5','50','6','60','61','62','7','8','70')
AND a.use_yn = 'Y'
AND EXISTS (
SELECT 'x' FROM departments a1 INNER JOIN departments a2 ON a2.lft BETWEEN a1.lft AND a1.rgt AND a2.use_yn = 'Y'
WHERE 1=1 AND a2.dept_sq = a.dept_sq AND a1.use_yn = 'Y'
)
ORDER BY a.usr_level DESC, a.usr_nm ASC ";
$query = $this->db->query($sql);
return $query->getResultArray();
}
public function getTotalCount($data)
{
@@ -930,6 +821,535 @@ class M713Model extends Model
}
}
/* 현재 상태 확인 */
public function chkStat($vr_sq)
{
$sql = "SELECT stat_cd FROM v2_vrfc_req WHERE vr_sq = ?";
$data = array(
$vr_sq
);
$query = $this->db->query($sql, $data);
return $query->getRowArray();
}
public function chkTryCnt($atcl_vr_sq)
{
// 1차 검증인지 2차 검증인지 확인.
$sql = "SELECT a.try_cnt FROM v2_vrfc_req a WHERE vr_sq = ?";
$query = $this->db->query($sql, [$atcl_vr_sq]);
return $query->getRowArray();
}
public function chkRegiTryCnt($atcl_vr_sq)
{
$sql = "SELECT a.reg_try_cnt FROM v2_vrfc_req a WHERE vr_sq = ?";
$query = $this->db->query($sql, [$atcl_vr_sq]);
return $query->getRowArray();
}
public function chkConfirm($atcl_vr_sq, $reg_yn)
{
// 검증결과 table에 있는지 확인.
$builder = $this->db->table('v2_confirm a');
$builder->select('a.vr_sq');
$builder->where('vr_sq', $atcl_vr_sq);
if ($reg_yn) {
$builder->where('vrfc_type', $reg_yn); // 등기부등본 정보 확인시
}
$query = $builder->get();
$result = $query->getNumRows();
return $result;
}
public function getUpdateFailTime($vr_sq)
{
$sql = "select vr_sq, stat_cd, insert_user, insert_tm " .
"from v2_chg_stat " .
"where vr_sq = ? and stat_cd = '49' " .
"order by insert_tm desc " .
"limit 1";
$data = array($vr_sq);
$query = $this->db->query($sql, $data);
$row = $query->getRowArray();
return $row;
}
public function insertConfirm($vr_sq, $vrfc_type, $success, $type)
{ //v2_confirm INSERT
$usr_sq = session('usr_sq');
$usr_id = session('usr_id');
$sql = "INSERT INTO v2_confirm" .
"(vr_sq, vrfc_type, success, type, charger, date, insert_user, insert_tm, update_user, update_tm)" .
"VALUES" .
"(?, ?, ?, ?, ?, '" . date('YmdHis') . "', ?, NOW(), ?, NOW())";
$data = array(
$vr_sq,
$vrfc_type,
$success,
$type,
$usr_id,
$usr_sq,
$usr_sq
);
$res = $this->db->query($sql, $data);
}
public function updateConfirm($vr_sq, $vrfc_type, $success): void
{
$data = [
'success' => $success
];
$builder = $this->db->table('v2_confirm');
$builder->where('vr_sq', $vr_sq);
$builder->where('vrfc_type', $vrfc_type);
$builder->update($data);
}
public function InsResChar($atcl_vr_sq)
{
$usr_id = session('usr_id');
$sql = "UPDATE v2_article_info" .
" SET reg_charger = ?" .
" WHERE vr_sq = ?";
$data = array(
$usr_id,
$atcl_vr_sq
);
//echo $this->db->last_query();
$res = $this->db->query($sql, $data);
$log_v = $this->db->getLastQuery();
log_message('debug', $log_v);
}
public function add_cert_uncnfrm_status($vr_sq, $cert_uncnfrm_status)
{
$sql = "UPDATE v2_article_info_etc" .
" SET cert_uncnfrm_status = ?" .
" WHERE vr_sq = ?";
$data = array(
$cert_uncnfrm_status,
$vr_sq
);
$this->db->query($sql, $data);
}
public function insertChkList($vr_sq, $vrfc_type, $type, $code, $comment)
{ //v2_check_list INSERT
$usr_sq = session('usr_sq');
$sql = "INSERT INTO v2_check_list" .
"(vr_sq, vrfc_type, type, code, comment, insert_user, insert_tm)" .
"VALUES" .
"(?, ?, ?, ?, ?, ?, NOW())" .
" ON DUPLICATE KEY UPDATE" .
" vr_sq=values(vr_sq), vrfc_type=values(vrfc_type), type=values(type), code=values(code), comment=values(comment), insert_user=values(insert_user), insert_tm=values(insert_tm)";
$data = array(
$vr_sq,
$vrfc_type,
$type,
$code,
$comment,
$usr_sq
);
$res = $this->db->query($sql, $data);
}
public function update_owner_verifiable($vr_sq, $owner_verifiable)
{
$sql = "UPDATE v2_vrfc_req" .
" SET owner_verifiable = ?" .
" WHERE vr_sq = ?";
$data = array(
$owner_verifiable,
$vr_sq
);
$this->db->query($sql, $data);
$s = $this->db->getLastQuery();
log_message('debug', "====update_owner_verifiable====" . $s);
}
/* 등기부등본 API 호출*/
public function getDatacertAPI($vr_sq, $vrfc_type = '')
{
// 요청정보
$sql = "SELECT vr_sq, atcl_no, step, cpid, cp_atcl_id, trade_type, realtor_nm, realtor_tel_no, seller_tel_no, vrfc_type, rgbk_confirm, req_type, rdate, stat_cd, try_cnt, insert_user, insert_tm, owner_verifiable" .
" FROM v2_vrfc_req WHERE vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_vrfc_req = $query->getRowArray();
if (!empty($vrfc_type)) {
$row_vrfc_req['vrfc_type'] = $vrfc_type;
}
log_message('debug', 'getDatacertApi_query => ' . $this->db->getLastQuery());
log_message('debug', 'getDatacertApi_result => ' . json_encode($row_vrfc_req));
// 매물정보
$sql = "SELECT vr_sq, atcl_no, cpid, cp_atcl_id, rlet_type_cd, trade_type, address_code, address1, address2, address3, sply_spc, excls_spc, tot_spc, grnd_spc, bldg_spc, deal_amt, wrrnt_amt, lease_amt, isale_amt, prem_amt, sise, floor, rdate, seller_tel_no, seller_nm, realtor_nm, realtor_tel_no, hscp_no, hscp_nm, ptp_no, ptp_nm, charger, req_price_yn, reg_charger, dept1_sq, dept2_sq, reg_dept1_sq, reg_dept2_sq, floor2, vrfc_type_sub" .
" FROM v2_article_info WHERE vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_article_info = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 수정정보
$sql = "SELECT vr_sq, bild_nm, rm_no, floor, address_code, address2, address3, trade_type, deal_amt, wrrnt_amt, lease_amt, isale_amt, prem_amt, sply_spc, excls_spc, tot_spc, grnd_spc, bldg_spc, hscp_no, hscp_nm, ptp_no, ptp_nm, modify_yn, floor2" .
" FROM v2_modify_info WHERE vr_sq = ?";
$query = $this->db->query($sql, [$vr_sq]);
$row_modify_info = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 검증결과
$sql = "SELECT vr_sq, vrfc_type, success, type, charger, date, insert_user, insert_tm, update_user, update_tm, work_type" .
" FROM v2_confirm WHERE vr_sq = ? AND vrfc_type = ?";
$query = $this->db->query($sql, [$vr_sq, $row_vrfc_req['vrfc_type']]);
$row_confirm = $query->getRowArray();
log_message('debug', $this->db->getLastQuery());
// 확인정보
$sql = "SELECT a.type, a.code, a.comment, b.ownerNm, b.owner_birth" .
" FROM v2_check_list a" .
" INNER JOIN v2_article_info b ON a.vr_sq = b.vr_sq" .
" WHERE a.vr_sq = ? AND a.vrfc_type = ?";
$query = $this->db->query($sql, [$vr_sq, $row_vrfc_req['vrfc_type']]);
$res_check_list = $query->getResultArray();
log_message('debug', $this->db->getLastQuery());
log_message('debug', implode(', ', $row_confirm ?? []));
$atclNo = $row_vrfc_req['atcl_no'];
$type = $row_vrfc_req['try_cnt'];
$success = empty($row_confirm['success']) ? false : true;
$charger = $row_confirm['charger'] ?? '';
$date = $row_confirm['date'] ?? '';
$ownerVerifiable = match ($row_vrfc_req['owner_verifiable']) {
"1", "true" => true,
default => false,
};
$checkList = [];
foreach ($res_check_list as $row) {
$checkList[] = [
'type' => $row['type'],
'code' => $row['code'],
'comment' => $row['comment'],
'ownerNm' => $row['ownerNm'],
'ownerBirth' => $row['owner_birth'],
];
}
$modifyInfo = [];
if ($row_modify_info['modify_yn'] == 'Y') {
if (!empty($row_modify_info['hscp_no'])) {
// 공동주택
$modifyInfo = [
'hscpNo' => $row_modify_info['hscp_no'],
'ptpNo' => $row_modify_info['ptp_no'],
'bildNm' => $row_modify_info['address2'],
'rmNo' => $row_modify_info['address3'],
'tradeType' => $row_modify_info['trade_type'],
'dealAmt' => $row_modify_info['deal_amt'],
'wrrntAmt' => $row_modify_info['wrrnt_amt'],
'leaseAmt' => $row_modify_info['lease_amt'],
'isaleAmt' => $row_modify_info['isale_amt'],
'premAmt' => $row_modify_info['prem_amt'],
'floor' => $row_modify_info['floor'],
];
} else {
// 비공동주택
$modifyInfo = [
'addressCode' => $row_modify_info['address_code'],
'address2' => $row_modify_info['address2'],
'address3' => $row_modify_info['address3'],
'tradeType' => $row_modify_info['trade_type'],
'dealAmt' => $row_modify_info['deal_amt'],
'wrrntAmt' => $row_modify_info['wrrnt_amt'],
'leaseAmt' => $row_modify_info['lease_amt'],
'splySpc' => $row_modify_info['sply_spc'],
'exclsSpc' => $row_modify_info['excls_spc'],
'totSpc' => $row_modify_info['tot_spc'],
'grndSpc' => $row_modify_info['grnd_spc'],
'bldgSpc' => $row_modify_info['bldg_spc'],
'floor' => $row_modify_info['floor'],
'floor2' => $row_modify_info['floor2'],
];
}
$return_data = [
'atclNo' => $atclNo,
'type' => $type,
'success' => $success,
'checkList' => $checkList,
'charger' => $charger,
'modifyInfo' => $modifyInfo,
'date' => $date,
'vrfcType' => $row_article_info['vrfc_type_sub'],
'ownerVerifiable' => $ownerVerifiable,
];
log_message('debug', "713 getDatacertAPI_1 {$atclNo} ::: " . json_encode($return_data) . PHP_EOL);
return $return_data;
} else {
$return_data = [
'atclNo' => $atclNo,
'type' => $type,
'success' => $success,
'checkList' => $checkList,
'charger' => $charger,
'date' => $date,
'vrfcType' => $row_article_info['vrfc_type_sub'],
'ownerVerifiable' => $ownerVerifiable,
];
log_message('debug', "713 getDatacertAPI_2 {$atclNo} ::: " . json_encode($return_data) . PHP_EOL);
return $return_data;
}
}
public function chgStat($vr_sq, $stat_cd, $insert_tm)
{
// 상태변경 TABLE INSERT
$usr_sq = session('usr_sq');
$usr_id = session('usr_id');
$list = $this->getDetail($vr_sq);
$sql = "INSERT INTO v2_chg_stat (vr_sq, stat_cd, insert_user, insert_tm)" .
"VALUES (?, ?, ?, ?)" .
"ON DUPLICATE KEY " .
"UPDATE vr_sq=VALUES(vr_sq), stat_cd=VALUES(stat_cd), insert_user=VALUES(insert_user), insert_tm=VALUES(insert_tm)";
$data = [
$vr_sq,
$stat_cd,
$usr_sq,
$insert_tm
];
$this->db->transStart();
$this->db->query($sql, $data);
$error = $this->db->error();
$return = [
'error_number' => $error['code'],
'error_message' => $error['message']
];
if (empty($return['error_number'])) {
// 로그를 남긴다.
if ($this->db->affectedRows() > 0) {
// $changed = $this->what_is_changed($list, $data, '');
// if (!empty($changed)) {
$this->saveChangedHistory($list['vr_sq'], $stat_cd, 'C9', $usr_id, "상태변경 저장");
// }
}
}
$this->db->transComplete();
return $return;
}
public function chgStatVrfc($vr_sq, $stat_cd)
{
$data = ['stat_cd' => $stat_cd];
$builder = $this->db->table('v2_vrfc_req');
$builder->where('vr_sq', $vr_sq);
$builder->update($data);
$error = $this->db->error();
return [
'error_number' => $error['code'],
'error_message' => $error['message']
];
}
public function chgStatFax($vr_sq, $stat_cd)
{
$data = ['stat_cd' => $stat_cd];
$builder = $this->db->table('fax_imgs');
$builder->where('vr_sq', $vr_sq);
$builder->update($data);
$error = $this->db->error();
return [
'error_number' => $error['code'],
'error_message' => $error['message']
];
}
public function updateStat($vr_sq, $reg_status)
{
$data = ['reg_status' => $reg_status];
$builder = $this->db->table('v2_article_info');
$builder->where('vr_sq', $vr_sq);
$builder->update($data);
$error = $this->db->error();
return [
'error' => [
'code' => $error['code'],
'message' => $error['message']
]
];
}
public function chgRegiTryCnt($vr_sq, $try_cnt)
{ //v2_vrfc_req try_cnt 값 변경.
$sql = "UPDATE v2_vrfc_req" .
" SET reg_try_cnt = ?" .
" WHERE vr_sq = ?";
$data = array(
$try_cnt,
$vr_sq
);
$this->db->query($sql, $data);
}
public function modify_info($vr_sq, $owner_birth, $address2, $address2a, $address2b, $address3, $address4, $address_code, $hscp_no, $hscp_nm)
{
$this->db->transStart();
$usr_id = session('usr_id');
$sql = "UPDATE v2_modify_info
SET address2 = ?
,address2a = ?
,address2b = ?
,address3 = ?
,address4 = ?
,address_code = ?
,hscp_no = ?
,hscp_nm = ?
,modify_yn = 'Y'
WHERE vr_sq = ?";
$data = array(
$address2,
$address2a,
$address2b,
$address3,
$address4,
$address_code,
$hscp_no,
$hscp_nm,
$vr_sq
);
if ($this->db->query($sql, $data) === false) {
return [
'success' => false,
'msg' => '저장 실패',
];
}
$sql2 = "UPDATE v2_article_info
SET owner_birth = ?
,address2 = ?
,address3 = ?
,address_code = ?
,hscp_no = ?
,hscp_nm = ?
WHERE vr_sq = ?";
$data2 = array(
$owner_birth,
$address2,
$address3,
$address_code,
$hscp_no,
$hscp_nm,
$vr_sq
);
if ($this->db->query($sql2, $data2) === false) {
return [
'success' => false,
'msg' => '저장 실패',
];
}
$sql3 = "UPDATE v2_article_info_etc
SET address2a = ?
,address2b = ?
WHERE vr_sq = ?";
$data3 = array(
$address2a,
$address2b,
$vr_sq
);
if ($this->db->query($sql3, $data) === false) {
return [
'success' => false,
'msg' => '저장 실패',
];
}
$this->saveChangedHistory($vr_sq, '40', 'C34', $usr_id, '생년월일 정보 변경');
$this->db->transComplete();
return [
'success' => true,
];
}
// 메모저장
public function saveMemo($data)
{
$usr_id = session('usr_id');
$sql = "UPDATE v2_vrfc_req SET
memo = ?
WHERE vr_sq = ?";
if ($this->db->query($sql, $data) === false) {
return [
'success' => false,
'msg' => '파일정보 저장 실패',
];
}
$row = $this->getDetail($data[1]);
$memo = "메모변경 : " . $row['memo'] . " => " . $data[0];
$this->saveChangedHistory($data[1], $row['pre_stat_cd'], 'C19', $usr_id, $memo);
return [
'success' => true
];
}
// 정보변경 이력 저장
public function saveChangedHistory($vr_sq, $stat_cd, $chg_type, $usr_id, $memo)

View File

@@ -40,43 +40,79 @@ class TypeSHandler
{
CLI::write(CLI::color('🟢 Type S 처리 시작 :: ' . $articleNumber, 'green'));
// CI 트랜잭션 strict 모드에서는 이전 실패 상태가 누적될 수 있으므로 시작 전에 초기화
if (method_exists($this->db, 'resetTransStatus')) {
$this->db->resetTransStatus();
}
$this->db->transBegin();
try {
// 1. Receipt 데이터 저장
$receiptData = $this->parameterMapper->mapReceipt($articleNumber, $rawData, $payload);
write_custom_log("Result Insert 데이터: " . json_encode($receiptData, JSON_UNESCAPED_UNICODE), 'INFO', 'service');
if (!$this->receiptModel->insert($receiptData)) {
$lastQuery = (string)$this->receiptModel->getLastQuery();
$errors = json_encode($this->receiptModel->errors());
write_custom_log("Receipt Insert 실패 | SQL: $lastQuery | Errors: $errors", 'ERROR', 'service');
throw new Exception("Receipt Insert 실패: " . json_encode($this->receiptModel->errors()));
}
$rcptSq = $this->receiptModel->getInsertID();
$receiptInsertSql = (string)$this->receiptModel->getLastQuery(); // Receipt SQL 캡처
CLI::write(CLI::color("✅ Receipt 저장 성공 (ID: $rcptSq)", 'blue'));
// 2. Result 데이터 저장
$resultData = $this->parameterMapper->mapResult($rcptSq, $rawData);
write_custom_log("Result Insert 데이터: " . json_encode($resultData, JSON_UNESCAPED_UNICODE), 'INFO', 'service');
if (!$this->resultModel->insert($resultData)) {
throw new Exception("Result Insert 실패");
$lastQuery = (string)$this->resultModel->getLastQuery();
$errors = json_encode($this->resultModel->errors());
write_custom_log("Result Insert 실패 | SQL: $lastQuery | Errors: $errors", 'ERROR', 'service');
throw new Exception("Result Insert 실패: $errors");
}
$resultInsertSql = (string)$this->resultModel->getLastQuery(); // Result SQL 캡처
write_custom_log("Result Insert 성공 | SQL: $resultInsertSql", 'INFO', 'service');
CLI::write(CLI::color('✅ Result 저장 성공', 'blue'));
// 3. 트랜잭션 커밋
$this->db->transComplete();
if ($this->db->transStatus() === false) {
write_custom_log("Type S DB 트랜잭션 최종 실패", 'ERROR', 'service');
$dbError = $this->db->error();
$errorJson = json_encode($dbError, JSON_UNESCAPED_UNICODE);
$receiptLastQuery = (string)$this->receiptModel->getLastQuery();
$resultLastQuery = (string)$this->resultModel->getLastQuery();
write_custom_log(
"Type S DB 트랜잭션 최종 실패 | DB Error: {$errorJson} | ReceiptLastQuery: {$receiptLastQuery} | ResultLastQuery: {$resultLastQuery}",
'ERROR',
'service'
);
throw new Exception("Type S DB 트랜잭션 최종 실패");
}
// 4. 로그 기록
write_custom_log("Type S 처리 성공 | Atcl: $articleNumber | Rcpt_sq: $rcptSq", 'INFO', 'service');
write_custom_log("Receipt Insert SQL: " . (string)$this->receiptModel->getLastQuery(), 'INFO', 'service');
write_custom_log("Result Insert SQL: " . (string)$this->resultModel->getLastQuery(), 'INFO', 'service');
write_custom_log("Receipt Insert SQL: " . $receiptInsertSql, 'INFO', 'service');
write_custom_log("Result Insert SQL: " . $resultInsertSql, 'INFO', 'service');
// 5. 네이버 예약 정보 동기화 (비동기)
try {
$syncResult = $this->naverClient->submitSyncResult($rawData['reserveNo'] ?? '');
write_custom_log("Naver Sync Result Response: " . json_encode($syncResult), 'INFO', 'service');
} catch (Exception $e) {
write_custom_log("Naver Sync 실패 (계속 진행): " . $e->getMessage(), 'WARN', 'service');
}
// try {
// // $syncResult = $this->naverClient->submitSyncResult($rawData['reserveNo'] ?? '');
// $rsrv_date = $receiptData['rsrv_date'] ?? null;
// $reportData = [
// 'type' => 'S11',
// 'code' => '10000',
// 'message' => '현장확인 예약',
// 'reserveDate' => $rsrv_date
// ];
// $syncResult = $this->naverClient->verificationSiteReport($articleNumber, $reportData);
// write_custom_log("Naver Sync Result Response: " . json_encode($syncResult), 'INFO', 'service');
// } catch (Exception $e) {
// write_custom_log("Naver Sync 실패 (계속 진행): " . $e->getMessage(), 'WARN', 'service');
// }
return $rcptSq;

View File

@@ -46,9 +46,11 @@ class TypeV2Handler
public function handle(string $articleNumber, array $rawData, array $payload): int
{
CLI::write(CLI::color('🟢 Type V2 처리 시작 :: ' . $articleNumber, 'green'));
write_custom_log("TypeV2Handler 진입 | Atcl: $articleNumber | Payload: " . json_encode($payload), 'INFO', 'service');
try {
$requestType = $payload['requestType'] ?? 'REG';
CLI::write(CLI::color("🔵 RequestType: $requestType", 'cyan'));
switch ($requestType) {
case 'REG':
@@ -62,7 +64,9 @@ class TypeV2Handler
}
} catch (Exception $e) {
write_custom_log("Type V2 처리 실패: " . $e->getMessage(), 'ERROR', 'service');
$errorDetail = "Type V2 처리 실패 | Atcl: $articleNumber | Error: " . $e->getMessage() . " | File: " . $e->getFile() . ":" . $e->getLine();
write_custom_log($errorDetail, 'ERROR', 'service');
CLI::write(CLI::color("" . $errorDetail, 'red'));
throw $e;
}
}
@@ -136,7 +140,9 @@ class TypeV2Handler
// 기존 검증 요청 확인
$existing = $this->vrfcReqModel->where('atcl_no', $articleNumber)->first();
if (!$existing) {
throw new Exception("수정할 기존 데이터가 없습니다. Atcl: $articleNumber");
CLI::write(CLI::color("⚠️ 수정할 기존 데이터가 없음 → 신규 등록으로 전환 (Atcl: $articleNumber)", 'yellow'));
write_custom_log("MOD → REG 자동 전환 | Atcl: $articleNumber | 사유: 기존 데이터 없음", 'WARNING', 'service');
return $this->handleRegister($articleNumber, $rawData, $payload);
}
$vrSq = $existing['vr_sq'];
$stat_cd = $existing['stat_cd'];
@@ -199,7 +205,9 @@ class TypeV2Handler
// 기존 검증 요청 확인
$existing = $this->vrfcReqModel->where('atcl_no', $articleNumber)->first();
if (!$existing) {
throw new Exception("취소할 기존 데이터가 없습니다. Atcl: $articleNumber");
CLI::write(CLI::color("⚠️ 취소할 데이터가 없음 → 무시 (Atcl: $articleNumber)", 'yellow'));
write_custom_log("CNC 무시 | Atcl: $articleNumber | 사유: 기존 데이터 없음", 'WARNING', 'service');
return 0; // 취소할 데이터가 없으므로 0 반환
}
$vrSq = $existing['vr_sq'];

View File

@@ -13,7 +13,7 @@ use Exception;
* 네이버 부동산 매물 처리 서비스
*
* 네이버 API 응답을 받아서 타입별 처리 로직으로 위임하는 오케스트레이터 역할
* - Type S: 현장확인 (A01)
* - Type S, S_VR: 현장확인 (A01)
* - Type V2: 일반/서류/비공동 (D04, F01 등)
*/
class NaverService
@@ -59,19 +59,33 @@ class NaverService
$vType = $rawData['verificationTypeCode'] ?? '';
// 2. 원본 데이터 Staging 저장
$this->rawStagingModel->insert([
$insertResult = $this->rawStagingModel->insert([
'atcl_no' => $articleNumber,
'verification_type' => $vType,
'request_type' => $requestType,
'raw_json' => $rawData
]);
if (!$insertResult) {
$dbError = $this->db->error();
write_custom_log("naver_raw_staging Insert 실패 | Atcl: $articleNumber | Error: " . json_encode($dbError), 'ERROR', 'service');
throw new Exception("naver_raw_staging 저장 실패: " . json_encode($dbError));
}
CLI::write(CLI::color('🟢 임시테이블 저장 완료', 'green'));
// 3. 타입별 분기 처리
if ($vType === 'S') {
CLI::write(CLI::color("🔵 검증타입 확인: vType = $vType", 'cyan'));
write_custom_log("타입별 분기 | Atcl: $articleNumber | vType: $vType | requestType: $requestType", 'INFO', 'service');
if ($vType === 'S' || $vType === 'S_VR') {
CLI::write(CLI::color('🟢 Type S Handler 호출', 'green'));
return $this->typeSHandler->handle($articleNumber, $rawData, $payload);
} else {
return $this->typeV2Handler->handle($articleNumber, $rawData, $payload);
CLI::write(CLI::color('🟢 Type V2 Handler 호출', 'green'));
$result = $this->typeV2Handler->handle($articleNumber, $rawData, $payload);
write_custom_log("TypeV2Handler 완료 | Atcl: $articleNumber | Result: $result", 'INFO', 'service');
return $result;
}
} catch (Exception $e) {

View File

@@ -2,12 +2,20 @@
namespace App\Services\ParameterMapper;
use App\Models\Entities\RegionModel;
/**
* Type S 파라미터 매퍼
* 현장확인 매물 (A01 등) 데이터를 Receipt 테이블용 파라미터로 변환
*/
class TypeSParameterMapper extends BaseParameterMapper
{
private $regionModel;
public function __construct()
{
$this->regionModel = new RegionModel();
}
/**
* Receipt 테이블용 파라미터 생성
*/
@@ -24,8 +32,8 @@ class TypeSParameterMapper extends BaseParameterMapper
// 평면도 여부 결정
$groundPlan = in_array($rawData['realEstateTypeCode'] ?? '', ['C01', 'C02']) ? 'N' : 'Y';
// 거래 유형 매핑
$tradeType = $this->mapTradeType($rawData['tradeType'] ?? null);
// 거래 유형 코드 (tradeTypeCode 우선, 없으면 tradeType 한글을 변환)
$tradeType = $rawData['tradeTypeCode'] ?? $this->mapTradeType($rawData['tradeType'] ?? null);
return [
'comp_sq' => '2',
@@ -38,10 +46,11 @@ class TypeSParameterMapper extends BaseParameterMapper
'rcpt_product_info2' => $price['dealAmount'] ?? '0',
'rcpt_product_info4' => $price['preSaleAmount'] ?? '0',
'rcpt_product_info5' => $price['premiumAmount'] ?? '0',
'rcpt_product_info6' => $price['preSaleOptionAmount'] ?? '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,
@@ -87,6 +96,11 @@ class TypeSParameterMapper extends BaseParameterMapper
'rcpt_cpid' => $rawData['cpId'] ?? 'naver',
'isSiteVRVerification' => ($rawData['site']['isVrVerification'] ?? false) ? 'Y' : 'N',
'isPromotionApply' => ($rawData['site']['isVrRepresentativeApply'] ?? false) ? 'Y' : 'N',
'dealAmount' => $price['dealAmount'] ?? null,
'warrantyAmount' => $price['warrantyAmount'] ?? null,
'leaseAmount' => $price['leaseAmount'] ?? null,
'preSaleAmount' => $price['preSaleAmount'] ?? null,
'premiumAmount' => $price['premiumAmount'] ?? null
];
}
@@ -97,9 +111,51 @@ class TypeSParameterMapper extends BaseParameterMapper
{
$now = db_now();
// VR 검증 여부에 따른 담당자 설정
$deptSq = ($rawData['site']['isVrVerification'] ?? false) ? '29' : null;
$usrSq = ($rawData['site']['isVrVerification'] ?? false) ? '1993' : null;
$address = $rawData['address'] ?? [];
$sectorNumber = $address['legalDivision']['sectorNumber'] ?? null;
// VR 검증 여부 확인
$isVrVerification = ($rawData['site']['isVrVerification'] ?? false);
// 1. 지역별 담당자 조회
$charge = null;
if ($sectorNumber) {
$charge = $this->regionModel->getChargeByRegionCd($sectorNumber);
log_message('info', "[TypeSParameterMapper] 지역코드: {$sectorNumber}, 조회 결과: " . json_encode($charge, JSON_UNESCAPED_UNICODE));
}
// 2. 기본 담당자 설정 (지역별 담당자가 없으면)
$deptSq = $charge['dept_sq'] ?? '26';
$usrSq = $charge['usr_sq'] ?? '1';
// 담당자 존재 여부 검증 (users 테이블 확인)
if ($usrSq && $usrSq !== '1') {
$db = \Config\Database::connect();
$userExists = $db->table('users')->where('usr_sq', $usrSq)->countAllResults() > 0;
if (!$userExists) {
log_message('warning', "[TypeSParameterMapper] usr_sq={$usrSq}가 users 테이블에 없음. 기본값(1)으로 폴백");
$usrSq = '1';
$deptSq = '26';
}
}
log_message('info', "[TypeSParameterMapper] 기본 담당자 - dept_sq: {$deptSq}, usr_sq: {$usrSq}, VR검증: " . ($isVrVerification ? 'Y' : 'N'));
// 3. VR 검증인 경우 환경별 담당자로 덮어쓰기
if ($isVrVerification) {
log_message('info', "[TypeSParameterMapper] ENVIRONMENT 상수 값: " . ENVIRONMENT);
if (ENVIRONMENT === 'development') {
$deptSq = '29';
$usrSq = '472'; // vradmin
log_message('info', "[TypeSParameterMapper] VR 검증 (DEV) - dept_sq: {$deptSq}, usr_sq: {$usrSq}");
} else {
// production - TODO: 실제 프로덕션 VR 담당자로 변경 필요
$deptSq = '29';
$usrSq = '472'; // 임시: vradmin (프로덕션 VR 담당자 확인 후 수정)
log_message('warning', "[TypeSParameterMapper] VR 검증 (PROD) - 프로덕션 VR 담당자 미설정, 임시 담당자 사용: usr_sq={$usrSq}");
}
}
return [
'rcpt_sq' => $rcptSq,

View File

@@ -90,6 +90,7 @@ class TypeV2ParameterMapper extends BaseParameterMapper
'lease_amt' => $price['leaseAmount'] ?? 0,
'isale_amt' => $price['preSaleAmount'] ?? 0,
'prem_amt' => $price['premiumAmount'] ?? 0,
'preopt_amt' => $price['preSaleOptionAmount'] ?? 0,
'sise' => null,
'floor' => $floor['correspondenceFloorCount'] ?? null,
'floor2' => $floor['totalFloorCount'] ?? 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

@@ -0,0 +1,2 @@
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.bootstrap5.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

View File

@@ -0,0 +1,3 @@
<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>

View File

@@ -0,0 +1,2 @@
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/2.0.7/css/dataTables.dataTables.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">

View File

@@ -0,0 +1,2 @@
<script src="https://cdn.datatables.net/2.0.7/js/dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>

View File

@@ -0,0 +1,67 @@
<script type="text/javascript">
/**
* DataTables v2 layout topEnd 버튼 헬퍼
* @param {Object} options - 옵션 객체
* @param {boolean} options.showSendButton - 등기부등본 전송 버튼 표시 여부 (기본값: false)
* @param {string} options.sendButtonText - 전송 버튼 텍스트
* @param {boolean} options.showExcelButton - 엑셀 버튼 표시 여부 (기본값: true)
* @param {string} options.excelButtonId - 엑셀 버튼 id
* @param {string} options.excelButtonClass - 엑셀 버튼 class
* @param {string} options.excelButtonHtml - 엑셀 버튼 innerHTML
* @returns {Function} DataTable layout.topEnd 콜백 함수
*/
function v2TopEndButtons(options) {
const opts = options || {};
return function () {
const container = document.createElement('div');
container.className = 'd-flex';
container.style.gap = '8px';
container.style.justifyContent = 'flex-end';
if (opts.showSendButton === true) {
const btnSend = document.createElement('button');
btnSend.className = 'btn btn-sm btn-outline-light';
btnSend.textContent = opts.sendButtonText || '등기부등본 전송';
container.append(btnSend);
}
if (opts.showExcelButton !== false) {
const btnExcel = document.createElement('button');
btnExcel.id = opts.excelButtonId || 'excel-download';
btnExcel.className = opts.excelButtonClass || 'btn btn-sm btn-outline-success';
btnExcel.innerHTML = opts.excelButtonHtml || '<i class="fa fa-fw fa-file-excel-o" aria-hidden="true"></i> 엑셀다운로드';
container.append(btnExcel);
}
return container;
};
}
/**
* DataTables v2 layout bottomStart/bottomEnd 통합 설정
* @param {Object} options - 옵션 객체
* @param {boolean} options.hasPageLength - pageLength 표시 여부 (기본값: true)
* @param {boolean} options.hasInfo - info 표시 여부 (기본값: true)
* @returns {Object} { bottomStart, bottomEnd } 객체
*/
function v2BottomLayout(options) {
const opts = options || {};
const hasPageLength = opts.hasPageLength !== false;
const hasInfo = opts.hasInfo !== false;
const config = {};
if (hasPageLength && hasInfo) {
config.bottomStart = ['pageLength', 'info'];
} else if (hasPageLength) {
config.bottomStart = 'pageLength';
} else if (hasInfo) {
config.bottomStart = 'info';
}
config.bottomEnd = 'paging';
return config;
}
</script>

View File

@@ -39,13 +39,13 @@
$serverIp = $_SERVER['SERVER_ADDR'] ?? '';
// 개발 서버
$devServers = ['192.168.200.8', '192.168.10.231'];
$devServers = ['192.168.200.8', '192.168.10.231', '172.18.0.5'];
// 도커 테스트 서버
$dockerServers = ['172.18.0.2'];
// 테스트 서버
$testServers = ['192.168.200.9', '192.168.10.237', '175.126.191.182'];
$testServers = ['192.168.200.9', '192.168.10.237', '175.126.191.182', '192.168.10.243'];
// 운영 서버 IP 매핑
$prodServers = [
@@ -58,7 +58,7 @@
if (in_array($serverIp, $devServers, true)) {
// 개발
echo "<img src='/img/gnb_dev_00.png' alt='' />";
echo "개발";
} elseif (in_array($serverIp, $dockerServers, true)) {
// 도커
@@ -80,8 +80,6 @@
echo "{$serverName}";
}
?>
</li>

View File

@@ -0,0 +1,410 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('page_styles') ?>
<style>
.stats-card {
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.stats-card h3 {
margin: 0 0 10px 0;
font-size: 14px;
color: #666;
}
.stats-card .number {
font-size: 32px;
font-weight: bold;
margin: 0;
}
.stats-card.total { background: #f8f9fa; border-left: 4px solid #6c757d; }
.stats-card.retryable { background: #d1ecf1; border-left: 4px solid #17a2b8; }
.stats-card.exhausted { background: #f8d7da; border-left: 4px solid #dc3545; }
.error-type-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
margin-right: 8px;
}
.severity-high { background: #dc3545; color: white; }
.severity-medium { background: #ffc107; color: #000; }
.severity-low { background: #28a745; color: white; }
.solution-box {
background: #e7f3ff;
border-left: 4px solid #007bff;
padding: 15px;
margin-top: 10px;
border-radius: 4px;
}
.solution-box h5 {
margin: 0 0 10px 0;
color: #004085;
}
.solution-box ul {
margin: 0;
padding-left: 20px;
}
.log-table {
font-size: 13px;
}
.log-table th {
background: #f8f9fa;
font-weight: 600;
}
.log-table .error-msg {
max-width: 300px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.log-table .error-msg:hover {
overflow: visible;
white-space: normal;
}
.badge-retry-count {
background: #6c757d;
color: white;
padding: 2px 8px;
border-radius: 10px;
font-size: 11px;
}
.btn-retry-selected {
position: sticky;
top: 20px;
z-index: 100;
}
</style>
<?= $this->endSection() ?>
<?= $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-attention icon-gradient bg-mean-fruit"></i>
</div>
<div>
Worker 실패 로그 관리
<div class="page-title-subheading">
처리 실패한 작업을 분석하고 재처리합니다.
</div>
</div>
</div>
</div>
</div>
<!-- 통계 카드 -->
<div class="row mb-4">
<div class="col-md-4">
<div class="stats-card total">
<h3>전체 실패 건수</h3>
<p class="number"><?= number_format($stats['total_fail']) ?></p>
</div>
</div>
<div class="col-md-4">
<div class="stats-card retryable">
<h3>재시도 가능</h3>
<p class="number"><?= number_format($stats['retry_available']) ?></p>
</div>
</div>
<div class="col-md-4">
<div class="stats-card exhausted">
<h3>재시도 횟수 초과</h3>
<p class="number"><?= number_format($stats['retry_exhausted']) ?></p>
</div>
</div>
</div>
<!-- 오류 유형별 분석 -->
<div class="main-card mb-3 card">
<div class="card-header">오류 유형별 분석</div>
<div class="card-body">
<div class="row">
<?php foreach ($errorTypes as $key => $type): ?>
<?php if ($type['count'] > 0): ?>
<div class="col-md-4 mb-3">
<span class="error-type-badge severity-<?= $type['severity'] ?>">
<?= $type['label'] ?>
</span>
<strong><?= number_format($type['count']) ?>건</strong>
</div>
<?php endif; ?>
<?php endforeach; ?>
</div>
</div>
</div>
<!-- 실패 로그 목록 -->
<div class="main-card mb-3 card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<span>최근 실패 로그 (50건)</span>
<button class="btn btn-primary btn-sm" id="retrySelected" disabled>
<i class="fa fa-refresh"></i> 선택 항목 재처리
</button>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover log-table">
<thead>
<tr>
<th width="40">
<input type="checkbox" id="selectAll">
</th>
<th width="80">ID</th>
<th width="120">매물번호</th>
<th width="100">오류 유형</th>
<th>오류 메시지</th>
<th width="80">재시도</th>
<th width="150">발생시각</th>
<th width="100">액션</th>
</tr>
</thead>
<tbody>
<?php foreach ($logs as $log): ?>
<tr>
<td>
<?php if ($log['can_retry']): ?>
<input type="checkbox" class="log-checkbox" value="<?= $log['seq'] ?>">
<?php else: ?>
<i class="fa fa-ban text-muted" title="재시도 불가"></i>
<?php endif; ?>
</td>
<td><?= $log['seq'] ?></td>
<td><?= $log['atcl_no'] ?? '-' ?></td>
<td>
<?php
$typeInfo = $errorTypes[$log['error_type']] ?? ['label' => '기타', 'severity' => 'low'];
?>
<span class="error-type-badge severity-<?= $typeInfo['severity'] ?>">
<?= $typeInfo['label'] ?>
</span>
</td>
<td>
<div class="error-msg" title="<?= esc($log['error_msg']) ?>">
<?= esc($log['error_msg']) ?>
</div>
</td>
<td class="text-center">
<?php if ($log['retry_cnt'] > 0): ?>
<span class="badge-retry-count"><?= $log['retry_cnt'] ?>회</span>
<?php else: ?>
-
<?php endif; ?>
</td>
<td><?= date('m-d H:i', strtotime($log['created_at'])) ?></td>
<td>
<button class="btn btn-sm btn-info view-detail" data-id="<?= $log['seq'] ?>">
상세
</button>
</td>
</tr>
<?php endforeach; ?>
<?php if (empty($logs)): ?>
<tr>
<td colspan="8" class="text-center text-muted py-4">
실패한 로그가 없습니다.
</td>
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('modals') ?>
<!-- 상세 모달 -->
<div class="modal fade" id="detailModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">로그 상세 정보</h5>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body" id="detailContent">
<div class="text-center py-4">
<div class="spinner-border" role="status"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">닫기</button>
<button type="button" class="btn btn-primary" id="retryOne" style="display:none;">
<i class="fa fa-refresh"></i> 재처리
</button>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<script>
$(document).ready(function() {
// 전체 선택
$('#selectAll').on('change', function() {
$('.log-checkbox').prop('checked', this.checked);
updateRetryButton();
});
// 개별 선택
$('.log-checkbox').on('change', function() {
updateRetryButton();
});
// 재처리 버튼 활성화/비활성화
function updateRetryButton() {
const checked = $('.log-checkbox:checked').length;
$('#retrySelected').prop('disabled', checked === 0);
}
// 선택 항목 재처리
$('#retrySelected').on('click', function() {
const logIds = $('.log-checkbox:checked').map(function() {
return $(this).val();
}).get();
if (logIds.length === 0) {
Swal.fire('알림', '재처리할 항목을 선택해주세요.', 'warning');
return;
}
Swal.fire({
title: '재처리 확인',
text: `선택한 ${logIds.length}건을 재처리하시겠습니까?`,
icon: 'question',
showCancelButton: true,
confirmButtonText: '재처리',
cancelButtonText: '취소'
}).then((result) => {
if (result.isConfirmed) {
retryLogs(logIds);
}
});
});
// 재처리 실행
function retryLogs(logIds) {
const btn = $('#retrySelected');
btn.prop('disabled', true).html('<i class="fa fa-spinner fa-spin"></i> 처리 중...');
$.ajax({
url: '<?= base_url('manage/worker/retry') ?>',
method: 'POST',
data: { log_ids: logIds },
dataType: 'json',
success: function(response) {
if (response.success) {
const results = response.results;
let message = `성공: ${results.success}건, 실패: ${results.fail}건\n\n`;
results.details.forEach(detail => {
const icon = detail.status === 'success' ? '✅' :
detail.status === 'skip' ? '⏭' : '❌';
message += `${icon} [${detail.atcl_no}] ${detail.message}\n`;
});
Swal.fire({
title: '재처리 완료',
text: message,
icon: results.success > 0 ? 'success' : 'warning',
preConfirm: () => location.reload()
});
} else {
Swal.fire('오류', response.message, 'error');
}
},
error: function() {
Swal.fire('오류', '재처리 중 오류가 발생했습니다.', 'error');
},
complete: function() {
btn.prop('disabled', false).html('<i class="fa fa-refresh"></i> 선택 항목 재처리');
}
});
}
// 상세 보기
$('.view-detail').on('click', function() {
const logId = $(this).data('id');
$('#detailContent').html('<div class="text-center py-4"><div class="spinner-border"></div></div>');
$('#detailModal').modal('show');
$.ajax({
url: `<?= base_url('manage/worker/detail') ?>/${logId}`,
method: 'GET',
dataType: 'json',
success: function(response) {
if (response.success) {
displayDetail(response.log);
} else {
$('#detailContent').html('<div class="alert alert-danger">' + response.message + '</div>');
}
},
error: function() {
$('#detailContent').html('<div class="alert alert-danger">로그를 불러오는 중 오류가 발생했습니다.</div>');
}
});
});
// 상세 정보 표시
function displayDetail(log) {
const solution = log.solution;
const errorType = log.error_type;
let html = `
<div class="mb-3">
<strong>로그 ID:</strong> ${log.seq}<br>
<strong>매물번호:</strong> ${log.atcl_no || '-'}<br>
<strong>상태:</strong> <span class="badge badge-danger">${log.status}</span><br>
<strong>재시도 횟수:</strong> ${log.retry_cnt || 0}회<br>
<strong>발생시각:</strong> ${log.created_at}
</div>
<div class="mb-3">
<strong>오류 메시지:</strong>
<div class="alert alert-danger">${log.error_msg}</div>
</div>
<div class="solution-box mb-3">
<h5>${solution.title}</h5>
<ul>
${solution.steps.map(step => `<li>${step}</li>`).join('')}
</ul>
</div>
<div class="mb-3">
<strong>원본 Payload:</strong>
<pre class="bg-light p-3" style="max-height: 300px; overflow-y: auto;">${JSON.stringify(log.parsed_payload, null, 2)}</pre>
</div>
`;
$('#detailContent').html(html);
// 재처리 버튼 표시
if (log.can_retry) {
$('#retryOne').show().off('click').on('click', function() {
$('#detailModal').modal('hide');
retryLogs([log.seq]);
});
} else {
$('#retryOne').hide();
}
}
});
</script>
<?= $this->endSection() ?>

View File

@@ -2675,9 +2675,10 @@ $usr_level = session('usr_level');
title: "정상 처리되었습니다.",
icon: "success",
draggable: true
})
location.reload();
}).then(() => {
// 녹취파일 체크박스 활성화 및 체크
$('#chk_record').prop('disabled', false).prop('checked', true);
});
} else {
Swal.fire({
title: result.msg,

View File

@@ -7,12 +7,19 @@ $usr_nm = session('usr_nm');
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -65,19 +72,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -100,133 +135,115 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>조직별 배정 현황</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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">
<ul class="nav nav-tabs">
<li class="nav-item"><a data-bs-toggle="tab" href="#tab-eg10-0" class="active nav-link">검색</a></li>
<li class="nav-item"><a data-bs-toggle="tab" href="#tab-eg10-1" class="nav-link">조직별 통계</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="tab-eg10-0" role="tabpanel">
<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="card mb-3">
<div class="card-body">
<div class="row g-3 align-items-end">
<!-- 매물ID -->
<div class="col-12 col-md-2 col-lg-1">
<!-- 검색 폼 -->
<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="hscp_no_enter(event)">
</div>
<!-- 지역구분 -->
<div class="col-12 col-md-6 col-lg-3">
<label class="form-label mb-1">지역구분</label>
<div class="row g-2">
<div class="col-4">
<select class="form-select" name="srcSido" id="srcSido">
<option value="">시/도</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>"><?= $s['region_nm'] ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-4">
<select class="form-select" name="srcGugun" id="srcGugun">
<option value="">시/군/구</option>
</select>
</div>
<div class="col-4">
<select class="form-select" name="srcDong" id="srcDong">
<option value="">읍/면/동</option>
</select>
</div>
</div>
</div>
<!-- 접수일자 -->
<div class="col-12 col-md-6 col-lg-3">
<label class="form-label mb-1">접수일자</label>
<div class="input-group">
<input type="date" class="form-control" name="sdate" id="sdate" placeholder="시작일">
<span class="input-group-text">~</span>
<input type="date" class="form-control" name="date" id="edate" placeholder="종료일">
</div>
</div>
<!-- 예약일자 -->
<div class="col-12 col-md-6 col-lg-4">
<div class="col-md-4">
<label class="form-label mb-1">예약일자</label>
<div class="input-group">
<select class="form-select" name="rsrv_tm_ap">
<div class="input-group input-group-sm">
<select class="form-select form-select-sm" name="rsrv_tm_ap">
<option value="">오전/오후</option>
<option value="AM">오전</option>
<option value="PM">오후</option>
</select>
<input type="date" class="form-control" name="rsrv_sdate" id="rsrv_sdate" placeholder="시작일">
<input type="date" class="form-control form-control-sm" name="rsrv_sdate" id="rsrv_sdate" placeholder="시작일">
<span class="input-group-text">~</span>
<input type="date" class="form-control" name="rsrv_edate" id="rsrv_edate" placeholder="종료일">
<input type="date" class="form-control form-control-sm" name="rsrv_edate" id="rsrv_edate" placeholder="종료일">
</div>
</div>
<!-- 방문담당 -->
<div class="col-12 col-lg-4">
<div class="col-md-3">
<label class="form-label mb-1">관할조직</label>
<div class="row g-2">
<div class="col-4">
<select class="form-select" name="bonbu" id="bonbu">
<div class="d-flex gap-1">
<select name="bonbu" id="bonbu" class="form-select form-select-sm">
<option value="">-본부-</option>
<?php foreach ($bonbu as $d): ?>
<option value="<?= $d['dept_sq'] ?>"><?= $d['dept_nm'] ?></option>
<option value="<?= $d['dept_sq'] ?>">
<?= $d['dept_nm'] ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="col-4">
<select class="form-select" name="team" id="team">
<select name="team" id="team" class="form-select form-select-sm">
<option value="">-팀-</option>
</select>
</div>
<div class="col-4">
<select class="form-select" name="damdang" id="damdang">
<select name="damdang" id="damdang" class="form-select form-select-sm">
<option value="">-담당자-</option>
</select>
</div>
</div>
<div class="col-md-3">
<label class="form-label mb-1">지역별조회</label>
<div class="d-flex gap-1">
<select name="srcSido" id="srcSido" class="form-select form-select-sm">
<option value="">-시/도-</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>">
<?= $s['region_nm'] ?>
</option>
<?php endforeach; ?>
</select>
<select name="srcGugun" id="srcGugun" class="form-select form-select-sm">
<option value="">-시/군/구-</option>
</select>
<select name="srcDong" id="srcDong" class="form-select form-select-sm">
<option value="">-읍/면/동-</option>
</select>
</div>
</div>
<div class="col-12 col-md-2 col-lg-1">
<label class="form-label mb-1">평면도 유무</label>
<select class="form-select" name="ground_plan_yn">
<option value="">선택</option>
<div class="col-md-1">
<label class="form-label mb-1">평면도유무</label>
<select class="form-select form-select-sm" name="ground_plan_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
</div>
<div class="row g-3">
<div class="col-md-1">
<label class="form-label mb-1">평면도요청</label>
<select class="form-select form-select-sm" name="ground_plan">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
<div class="col-12 col-md-2 col-lg-1">
<label class="form-label mb-1">평면도 요청</label>
<select class="form-select" name="ground_plan">
<option value="">선택</option>
<option value="Y">Y</option>
<option value="N">N</option>
</select>
</div>
<div class="col-12 col-md-2 col-lg-1">
<div class="col-md-1">
<label class="form-label mb-1">직거래</label>
<select class="form-select" name="direct_trad_yn">
<option value="">선택</option>
<select class="form-select form-select-sm" name="direct_trad_yn">
<option value="">전체</option>
<option value="Y">Y</option>
<option value="N">N</option>
</select>
@@ -235,7 +252,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>
@@ -245,14 +262,13 @@ $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-12 col-lg-10">
<div class="col-md-6">
<label class="form-label mb-1">진행상태</label>
<div class="d-flex flex-wrap gap-2 align-items-center border rounded p-2">
<div class="form-check me-2">
<div class="d-flex flex-wrap gap-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="rcpt_stat_all" value="Y"
id="rcpt_stat_all" onclick="progressStatAll(this, this.checked);">
<label class="form-check-label" for="rcpt_stat_all">전체</label>
@@ -270,81 +286,26 @@ $usr_nm = session('usr_nm');
</div>
</div>
<div class="col-12 col-lg-1 d-grid">
<div class="col-md-1 d-grid">
<label class="form-label mb-1 invisible">검색</label>
<button type="button" class="btn btn-primary" id="btnSearch">
<i class="pe-7s-search me-1"></i>검색
</button>
</div>
</div>
</div><!-- /row -->
</div><!-- /card-body -->
</div><!-- /card -->
</form>
</div>
<div class="tab-pane" id="tab-eg10-1" role="tabpanel">
<div class="row">
<div class="col-md-3">
<div class="card mb-3" style="max-width: 380px;">
<div class="card-body p-0">
<div class="table-scroll">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center">
<thead class="table-light">
<tr>
<th style="width:42px;">
<input class="form-check-input" type="checkbox" id="depChkAll">
</th>
<th>관할본부</th>
<th>방문담당</th>
<th style="width:90px;">배정건수</th>
</tr>
</thead>
<tbody id="deptArea"></tbody>
</table>
</div>
</div>
<div class="card-footer d-flex justify-content-end gap-1">
<button type="button" class="btn btn-outline-secondary btn-sm" onclick="printMap()">
<i class="pe-7s-print"></i> 인쇄하기
</button>
<button type="button" class="btn btn-primary btn-sm" onclick="deptMap()">
<i class="pe-7s-map-2"></i> 지도로 보기
</button>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card mb-3" style="max-width: 380px;">
<div class="card-body p-0">
<div class="table-scroll">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center">
<thead class="table-light">
<tr>
<th>지역구분</th>
<th style="width:90px;">요청건수</th>
</tr>
</thead>
<tbody id="statsArea"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</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;">
<select class="form-select form-select-sm" id="bonbu2" style="width:140px;">
<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">
<!-- 배정변경 조직 선택 -->
<select class="form-select form-select-sm" id="bonbu2" style="width:120px;">
<option value="">-본부-</option>
<?php foreach ($bonbu as $d): ?>
<option value="<?= $d['dept_sq'] ?>">
@@ -353,34 +314,36 @@ $usr_nm = session('usr_nm');
<?php endforeach; ?>
</select>
<select class="form-select form-select-sm" id="team2" style="width:160px;">
<select class="form-select form-select-sm" id="team2" style="width:140px;">
<option value="">-팀-</option>
</select>
<select class="form-select form-select-sm" id="damdang2" style="width:160px;">
<select class="form-select form-select-sm" id="damdang2" style="width:140px;">
<option value="">-담당자-</option>
</select>
<button type="button" class="btn btn-sm btn-outline-primary" id="btn_part_change">
<button type="button" class="btn btn-sm btn-outline-primary" id="btn_part_change" onclick="updateAssign()">
배정변경
</button>
</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> 엑셀다운로드
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>
엑셀다운로드
</button>
<button class="btn btn-sm btn-outline-secondary" id="excel-download2">
<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">
<thead>
<th class="text-center">
<tr>
<th>
<input type="checkbox" class="form-check-input" name="chkAll" id="chkAll" />
</th>
<th>진행상태</th>
@@ -396,45 +359,18 @@ $usr_nm = session('usr_nm');
<th>평면도유무</th>
<th>평면도요청</th>
<th>면적확인</th>
</tr>
</thead>
<tbody>
<!-- 여기는 비워둠: AJAX로 채움 -->
</tbody>
</table>
</div>
</div>
<div class="card-footer justify-content-start gap-1">
<button type="button" class="btn btn-light">
예약 확인
</button>
<button type="button" class="btn btn-outline-light">
검수지연
</button>
<button type="button" class="btn btn-outline-light">
검수지연 삭제
</button>
</div>
</div>
</div>
<?= $this->section('modals') ?>
<div class="modal fade" id="deptMapModal" 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">
<div id="dialog-deptmap-content"></div>
</div>
</div>
</div>
</div>
<?= $this->endSection() ?>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
@@ -622,61 +558,6 @@ $usr_nm = session('usr_nm');
d.start = d.start || 0
d.length = d.length || 10
},
dataSrc: function (d) {
const deptList = d.widgets?.deptList;
const areaStats = d.widgets?.areaStats ?? [];
if (deptList.length > 0) {
var str = "";
for (var i = 0; i < deptList.length; i++) {
str += `
<tr>
<td><input class="form-check-input depChk" type="checkbox" name="depChk[]" value="${deptList[i].dept_sq}"></td>
<td>${deptList[i].bonbu_nm}</td>
<td>${deptList[i].team_nm}</td>
<td><span class="badge bg-primary">${deptList[i].cnt} 건</span></td>
</tr>
`;
}
$("#deptArea").html(str);
} else {
str = `
<tr>
<td colspan="4">조회 가능한 데이터가 없습니다.</td>
</tr>
`;
$("#deptArea").html(str);
}
if (areaStats.length > 0) {
var str = "";
for (var i = 0; i < areaStats.length; i++) {
str += `
<tr>
<td>${areaStats[i].rcpt_dong}</td>
<td><span class="badge bg-warning">${areaStats[i].cnt} 건</span></td>
</tr>
`;
}
$("#statsArea").html(str);
} else {
str = `
<tr>
<td colspan="2">조회 가능한 데이터가 없습니다.</td>
</tr>
`;
$("#statsArea").html(str);
}
return d.data;
}
},
columnDefs: [
@@ -700,7 +581,7 @@ $usr_nm = session('usr_nm');
{ data: 'exp_spc_yn' },
],
// 옵션들 예시
pdestroy: true,
destroy: true,
deferRender: true,
scrollX: false,
autoWidth: false,
@@ -718,7 +599,7 @@ $usr_nm = session('usr_nm');
const rcpt_key = rowData.rcpt_key;
location.href = "<?= site_url('article/dept/detail') ?>/" + rcpt_key;
window.open("<?= site_url('article/dept/detail') ?>/" + rcpt_key, '_blank');
});
$(document).on('change', '#chkAll', function () {
@@ -737,18 +618,6 @@ $usr_nm = session('usr_nm');
$('#chkAll').prop('checked', total > 0 && total === checkedCnt);
});
// 전체 선택
$(document).on('change', '#depChkAll', function () {
$('.depChk').prop('checked', this.checked);
});
// 개별 체크 시 전체 체크 동기화
$(document).on('change', '.depChk', function () {
const total = $('.depChk').length;
const checked = $('.depChk:checked').length;
$('#depChkAll').prop('checked', total === checked);
});
table.on('draw', function () {
$('#chkAll').prop('checked', false);
});
@@ -815,6 +684,15 @@ $usr_nm = session('usr_nm');
}
function hscp_no_enter(event) {
if (event.keyCode == 13) {
table.ajax.reload()
}
}
function progressStatAll(el, checked) {
$('input[name="stat[]"]').prop('checked', checked);
}
/** datatable render */
function fn_chk_render(data, type, row, meta) {
@@ -890,56 +768,9 @@ $usr_nm = session('usr_nm');
/** datatable render */
// 인쇄하기
function printMap() {
var data = $('input[name="depChk[]"]').serialize();
var usr_id = $('input[name="usr_id"]').serialize();
if (data == '') {
alert('팀을 선택해주세요');
return;
}
var url = '/article/dept/print?' + data;
window.open(url, '', '');
}
function deptMap() {
const data = $('input[name="depChk[]"]:checked').serialize();
if (!data) {
alert('팀을 선택해주세요');
return;
}
const url = '/article/dept/print?' + data;
$('#dialog-deptmap-content').html(
`<iframe style="border:0;width:100%;height:650px;" src="${url}"></iframe>`
);
const modal = new bootstrap.Modal(document.getElementById('deptMapModal'));
modal.show();
}
// 엑셀 다운로드
function downloadExcel(data) {
const ws = XLSX.utils.json_to_sheet(data);
// ws['!cols'] = [
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 150 },
// { wpx: 120 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// { wpx: 100 },
// ];
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
@@ -1047,7 +878,7 @@ $usr_nm = session('usr_nm');
var arr = new Array();
const bonbu = $("#bonbu2").val();
const team = $("#team2").val();
const user = $("#user2").val();
const user = $("#damdang2").val();
$('#resultList tbody .row-chk:checked').each(function () {
const rowData = table.row($(this).closest('tr')).data();
@@ -1088,14 +919,12 @@ $usr_nm = session('usr_nm');
return;
}
swal.fire({
Swal.fire({
text: "배정을 변경하시겠습니까?",
type: "warning",
icon: "warning",
showCancelButton: true,
confirmButtonText: "예",
cancelButtonText: "아니오",
closeOnConfirm: false,
closeOnCancel: true,
confirmButtonColor: "#3085d6",
cancelButtonColor: "#d33",
}).then((result) => {

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,12 @@ $usr_nm = session('usr_nm');
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -65,19 +71,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -100,12 +134,27 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>현장확인V2 조직별 배정 현황</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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">
<ul class="nav nav-tabs">
<li class="nav-item"><a data-bs-toggle="tab" href="#tab-eg10-0" class="active nav-link">검색</a></li>

View File

@@ -14,6 +14,12 @@ $usr_nm = session('usr_nm');
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -66,19 +72,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -101,12 +135,27 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>평면도 관리</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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="alert alert-warning py-2 mb-3">

View File

@@ -749,7 +749,7 @@
if (!rowData) return;
const id = rowData.rcpt_no;
location.href = "<?= site_url('article/apt/detail') ?>/" + id;
window.open("<?= site_url('article/apt/detail') ?>/" + id, '_blank');
});
$('#btnSearch').on('click', function () {

View File

@@ -4,21 +4,18 @@
table th {
text-align: center;
}
.tab-header {
display: inline;
}
</style>
<h4 class="mb-3">처리가능 수량관리</h4>
<div class="col-12">
<div class="main-card mb-3 card">
<!-- 탭은 card-header 안에 -->
<div class="card-header tab-header pb-0">
<ul class="nav nav-tabs card-header-tabs">
<!-- 타이틀 -->
<div class="card-header bg-white border-bottom shadow-sm">
<h4 class="mb-0 fw-bold text-dark">처리가능 수량관리</h4>
</div>
<!-- 탭 -->
<ul class="nav nav-tabs px-3 pt-3 bg-white border-bottom">
<li class="nav-item">
<a class="nav-link active" data-bs-toggle="tab" href="#tab-eg10-0">일자별 처리가능 수량</a>
</li>
@@ -29,79 +26,16 @@
<a class="nav-link" data-bs-toggle="tab" href="#tab-eg10-2">기본 수량</a>
</li>
</ul>
</div>
<div class="card-body">
<!-- 공통 검색/필터 영역 -->
<div class="d-flex flex-wrap align-items-end justify-content-between gap-2 mb-3">
<div class="d-flex flex-wrap align-items-end gap-2">
<label class="form-label mb-1 small me-2">조회조건</label>
<!-- 첫번째탭 -->
<div id="form1" class="d-flex flex-wrap align-items-end gap-2">
<div class="input-group input-group-sm" style="min-width: 320px;">
<input type="date" class="form-control" name="sdate" id="sdate">
<span class="input-group-text">~</span>
<input type="date" class="form-control" name="edate" id="edate">
</div>
</div>
<!-- 두번째탭 -->
<div id="form2" class="d-none">
<div class="d-flex align-items-end gap-1">
<select class="form-select form-select-sm" name="region2" id="region2" style="min-width: 180px;">
<option value="">지역 선택</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>" <?php if ($s['region_cd'] == "1100000000") {
echo "selected";
} ?>>
<?= $s['region_nm'] ?>
</option>
<?php endforeach; ?>
</select>
<div class="input-group input-group-sm" style="min-width: 180px;">
<input type="date" class="form-control" name="sdate2" id="sdate2">
</div>
</div>
</div>
<!-- 세번째탭 -->
<div id="form3" class="d-none">
<div class="d-flex align-items-end gap-1">
<select class="form-select form-select-sm" name="region3" id="region3" style="min-width: 180px;">
<option value="">지역 선택</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>" <?php if ($s['region_cd'] == "1100000000") {
echo "selected";
} ?>>
<?= $s['region_nm'] ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
</div>
<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> 엑셀다운로드
</button>
<button class="btn btn-sm btn-outline-light" type="button" id="btnSearch">
조회
</button>
</div>
</div>
<!-- 탭 컨텐츠는 tab-content 바로 아래에 -->
<div class="tab-content">
<!-- 1) 일자별 -->
<div class="tab-pane fade show active" id="tab-eg10-0" role="tabpanel">
<div class="border rounded p-3 bg-white">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center w-100" id="tbl1">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center w-100" id="tbl1" >
<thead>
<tr>
<th rowspan="2" class="align-middle">날짜</th>
@@ -121,6 +55,36 @@
<!-- 2) 지역별 -->
<div class="tab-pane fade" id="tab-eg10-1" role="tabpanel">
<!-- 조회조건 -->
<div class="d-flex flex-wrap align-items-end justify-content-between gap-2 mb-3">
<div class="d-flex flex-wrap align-items-end gap-2">
<label class="form-label mb-1 small me-2">조회조건</label>
<div id="form2" class="d-flex align-items-end gap-1">
<select class="form-select form-select-sm" name="region2" id="region2" style="min-width: 180px;">
<option value="">지역 선택</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>" <?php if ($s['region_cd'] == "1100000000") {
echo "selected";
} ?>>
<?= $s['region_nm'] ?>
</option>
<?php endforeach; ?>
</select>
<div class="input-group input-group-sm" style="min-width: 180px;">
<input type="date" class="form-control" name="sdate2" id="sdate2">
</div>
</div>
</div>
<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> 엑셀다운로드
</button>
<button class="btn btn-sm btn-outline-light" type="button" id="btnSearch">
조회
</button>
</div>
</div>
<div class="border rounded p-3 bg-white">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center w-100" id="tbl2">
<thead>
@@ -142,6 +106,33 @@
<!-- 3) 기본 수량 -->
<div class="tab-pane fade" id="tab-eg10-2" role="tabpanel">
<!-- 조회조건 -->
<div class="d-flex flex-wrap align-items-end justify-content-between gap-2 mb-3">
<div class="d-flex flex-wrap align-items-end gap-2">
<label class="form-label mb-1 small me-2">조회조건</label>
<div id="form3" class="d-flex align-items-end gap-1">
<select class="form-select form-select-sm" name="region3" id="region3" style="min-width: 180px;">
<option value="">지역 선택</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>" <?php if ($s['region_cd'] == "1100000000") {
echo "selected";
} ?>>
<?= $s['region_nm'] ?>
</option>
<?php endforeach; ?>
</select>
</div>
</div>
<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> 엑셀다운로드
</button>
<button class="btn btn-sm btn-outline-light" type="button" id="btnSearch">
조회
</button>
</div>
</div>
<div class="border rounded p-3 bg-white">
<table class="table table-sm table-hover table-striped mb-0 align-middle text-center w-100" id="tbl3">
<thead>
@@ -193,9 +184,12 @@
initForm();
$("#sdate, #edate").on("change", function () {
table1.ajax.reload();
// DataTable 초기화 후 날짜 변경 이벤트 등록
setTimeout(() => {
$("#sdate-dt, #edate-dt").on("change", function () {
if (table1) table1.ajax.reload();
});
}, 500);
$("#btnSearch").on("click", function () {
@@ -216,6 +210,47 @@
language: lang_kor,
serverSide: true,
processing: true,
dom: '<"d-flex flex-wrap align-items-end justify-content-between gap-2 mb-2"<"#tbl1-filter">r>tip',
initComplete: function () {
// DataTable 생성 완료 후 필터 영역에 조회조건 삽입
const fmt = d => d.toISOString().slice(0, 10);
const lastDate = getLastDateOfMonth(date.getFullYear(), date.getMonth() + 1);
$('#tbl1-filter').html(`
<div class="d-flex flex-wrap align-items-end gap-2">
<label class="form-label mb-1 small me-2">조회조건</label>
<div class="input-group input-group-sm" style="min-width: 320px;">
<input type="date" class="form-control" id="sdate-dt" value="${fmt(date)}">
<span class="input-group-text">~</span>
<input type="date" class="form-control" id="edate-dt" value="${fmt(lastDate)}">
</div>
</div>
<div class="d-flex gap-1 ms-auto">
<button id="excel-download-dt" class="btn btn-sm btn-outline-success" type="button">
<i class="fa fa-fw fa-file-excel-o"></i> 엑셀다운로드
</button>
<button id="btnSearch1" class="btn btn-sm btn-outline-light" type="button">조회</button>
</div>
`);
// 이벤트 바인딩
$('#sdate-dt, #edate-dt').on('change', function () {
table1.ajax.reload();
});
$('#btnSearch1').on('click', function () {
table1.ajax.reload();
});
$('#excel-download-dt').on('click', function () {
$.ajax({
url: "/article/processible/excel",
method: "GET",
data: { sdate: $("#sdate-dt").val(), edate: $("#edate-dt").val() },
beforeSend: function () { blockUI.blockPage({ message: tpl }) },
complete: function () { blockUI.unblockPage() },
success: function (result) { downloadExcelWithHeader(result.data); }
});
});
},
ajax: {
url: '/article/processible/getList1',
type: 'GET',
@@ -228,11 +263,15 @@
blockUI.unblockPage()
},
data: function (d) {
d.sdate = $("#sdate").val(); // 시작일
d.edate = $("#edate").val(); // 종료일
const fmt = d2 => d2.toISOString().slice(0, 10);
const lastDate = getLastDateOfMonth(date.getFullYear(), date.getMonth() + 1);
d.start = d.start || 0
d.length = d.length || 10
// input이 DOM에 있으면 그 값, 없으면 오늘/말일 기본값
d.sdate = $("#sdate-dt").val() || fmt(date);
d.edate = $("#edate-dt").val() || fmt(lastDate);
d.start = d.start || 0;
d.length = d.length || 10;
},
},
"columnDefs": [
@@ -357,10 +396,10 @@
const fmt = d => d.toISOString().slice(0, 10);
$('#sdate').val(fmt(date));
$('#sdate-dt').val(fmt(date));
const lastDate = getLastDateOfMonth(date.getFullYear(), date.getMonth() + 1);
$('#edate').val(fmt(lastDate));
$('#edate-dt').val(fmt(lastDate));
$('#sdate2').val(fmt(date));
}
@@ -513,7 +552,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 +745,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

@@ -14,6 +14,12 @@ $usr_nm = session('usr_nm');
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -66,19 +72,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -101,33 +135,47 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>확인매물 현황</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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>
@@ -175,37 +223,34 @@ $usr_nm = session('usr_nm');
<label class="form-label mb-1">현재상태</label>
<div class="d-flex gap-1">
<select name="rcpt_stat1" class="form-select form-select-sm">
<option value="">예약확인지연</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "STEP_VERIFICATION"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<option value="">선택</option>
<?php foreach (($codes['STEP_VERIFICATION']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
<select name="rcpt_stat2" id="srcGugun" class="form-select form-select-sm">
<!-- <select name="rcpt_stat2" id="srcGugun" class="form-select form-select-sm">
<option value="">-상태2-</option>
</select>
<select name="rcpt_stat3" id="srcDong" class="form-select form-select-sm">
<option value="">-상태3-</option>
</select>
</select> -->
</div>
</div>
<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"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['NHN_DEAL_TYPE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cdNm ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
<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 +259,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 +268,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,31 +277,27 @@ $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"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['CP_ID']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
<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"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['ARTICLE_TYPE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
<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 +306,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 +317,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 +326,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 +335,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 +344,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 +354,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 +365,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 +382,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">
@@ -404,6 +444,12 @@ $usr_nm = session('usr_nm');
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 srchUser = <?= json_encode((!empty($srchUser) ? $srchUser : null), JSON_UNESCAPED_UNICODE); ?>;
const sBonbu = "<?= $sBonbu ?? '' ?>";
const sTeam = "<?= $sTeam ?? '' ?>";
const userColumns = <?= ($usr_level != '45')
? "[{ data: 'dept_nm' }, { data: 'usr_nm' }]"
: "[]" ?>;
const date = new Date();
var table;
@@ -412,6 +458,15 @@ $usr_nm = session('usr_nm');
initReceiptDate();
// srchUser 데이터가 있으면 초기값 설정 (usr_id 파라미터)
if (srchUser) {
initSrchUser();
}
// bonbu, dept_sq 파라미터가 있으면 초기값 설정
else if (sBonbu || sTeam) {
initSrchParam();
}
$("#srcSido, #srcGugun, #srcSido2, #srcGugun2").on("change", function (e) {
const targetId = this.id;
@@ -572,6 +627,7 @@ $usr_nm = session('usr_nm');
language: lang_kor,
serverSide: true,
processing: true,
autoWidth: false,
ajax: {
url: '/article/receipt/getResultList',
type: 'GET',
@@ -630,27 +686,23 @@ $usr_nm = session('usr_nm');
columns: [
{ data: 'rcpt_stat_nm' },
{ data: 'rcpt_atclno' },
{ data: 'insert_tm' },
{ data: 'insert_tm', className: 'tw-80' },
{ data: null, render: fn_rsrv_render },
{ data: 'rsrv_tm_hour' },
{ data: 'photo_save_dt' },
{ data: 'rcpt_cpid' },
{ data: null, render: fn_agent_render },
{ data: null, render: fn_agent_render , className: 'tw-150' },
{ data: null, render: fn_addr_render },
{ data: null, render: fn_prd_render },
{ data: 'rcpt_product_info1' },
<?php if ($usr_level != "45"): ?>
{ data: 'dept_nm' },
{ data: 'usr_nm' },
<?php endif; ?>
{ data: 'rcpt_product_info1' }
].concat(userColumns, [
{ data: 'parcel_out_yn' },
{ data: 'conf_img_yn' },
{ data: 'exp_movie_yn' },
{ data: 'ground_plan_yn' },
{ data: 'ground_plan' },
{ data: 'exp_spc_yn' },
],
{ data: 'exp_spc_yn' }
]),
// 옵션들 예시
destroy: true,
deferRender: true,
@@ -669,7 +721,7 @@ $usr_nm = session('usr_nm');
if (!rowData) return;
const rcpt_atclno = rowData.rcpt_atclno;
location.href = "<?= site_url('article/receipt/detail') ?>/" + rcpt_atclno;
window.location.href = "<?= site_url('article/receipt/detail') ?>/" + rcpt_atclno;
});
@@ -710,6 +762,79 @@ $usr_nm = session('usr_nm');
}
// 검색 사용자 초기화 (usr_id 파라미터용)
function initSrchUser() {
if (!srchUser) return;
const pdept_sq = srchUser.pdept_sq;
const dept_sq = srchUser.dept_sq;
const usr_id = srchUser.usr_id;
// 1단계: 본부 선택
if (pdept_sq) {
$("#bonbu").val(pdept_sq);
// 2단계: 팀 목록 로드 및 선택
let teamStr = `<option value="">-팀-</option>`;
if (teamArr.length > 0) {
for (let i = 0; i < teamArr.length; i++) {
if (String(teamArr[i].pdept_sq) === String(pdept_sq)) {
const selected = String(teamArr[i].dept_sq) === String(dept_sq) ? 'selected' : '';
teamStr += `<option value="${teamArr[i].dept_sq}" ${selected}>${teamArr[i].dept_nm}</option>`;
}
}
}
$("#team").html(teamStr);
// 3단계: 담당자 목록 로드 및 선택
if (dept_sq) {
let damdangStr = `<option value="">-담당자-</option>`;
if (userArr.length > 0) {
for (let i = 0; i < userArr.length; i++) {
if (String(userArr[i].dept_sq) === String(dept_sq)) {
const selected = String(userArr[i].usr_id) === String(usr_id) ? 'selected' : '';
damdangStr += `<option value="${userArr[i].usr_id}" ${selected}>${userArr[i].usr_nm}</option>`;
}
}
}
$("#damdang").html(damdangStr);
}
}
}
// 검색 파라미터 초기화 (bonbu, dept_sq 파라미터용)
function initSrchParam() {
// 1단계: 본부 선택
if (sBonbu) {
$("#bonbu").val(sBonbu);
// 2단계: 팀 목록 로드 및 선택
let teamStr = `<option value="">-팀-</option>`;
if (teamArr.length > 0) {
for (let i = 0; i < teamArr.length; i++) {
if (String(teamArr[i].pdept_sq) === String(sBonbu)) {
const selected = String(teamArr[i].dept_sq) === String(sTeam) ? 'selected' : '';
teamStr += `<option value="${teamArr[i].dept_sq}" ${selected}>${teamArr[i].dept_nm}</option>`;
}
}
}
$("#team").html(teamStr);
// 3단계: 팀이 선택되어 있으면 담당자 목록 로드
if (sTeam) {
let damdangStr = `<option value="">-담당자-</option>`;
if (userArr.length > 0) {
for (let i = 0; i < userArr.length; i++) {
if (String(userArr[i].dept_sq) === String(sTeam)) {
damdangStr += `<option value="${userArr[i].usr_id}">${userArr[i].usr_nm}</option>`;
}
}
}
$("#damdang").html(damdangStr);
}
}
}
function atcl_no_enter(event) {
if (event.keyCode == 13) {
table.ajax.reload()
@@ -742,14 +867,16 @@ $usr_nm = session('usr_nm');
function fn_addr_render(data, type, row) {
var str = "";
var addr = row.addr || '';
var lineBreak = addr ? "<br/>" : "";
if (row.rcpt_jibun_addr == null || row.rcpt_jibun_addr == "") {
str = row.addr + "<br/>" + row.rcpt_hscp_nm + " " + row.rcpt_dtl_addr + " " + row.rcpt_ho;
str = addr + lineBreak + (row.rcpt_hscp_nm || '') + " " + (row.rcpt_dtl_addr || '') + " " + (row.rcpt_ho || '');
} else {
str = row.addr + "<br/>" + row.rcpt_hscp_nm + " " + row.rcpt_li_addr + " " + row.rcpt_jibun_addr + " " + row.rcpt_etc_addr;
str = addr + lineBreak + (row.rcpt_hscp_nm || '') + " " + (row.rcpt_li_addr || '') + " " + (row.rcpt_jibun_addr || '') + " " + (row.rcpt_etc_addr || '');
}
return str;
return str.trim();
}
function fn_prd_render(data, type, row) {

View File

@@ -14,6 +14,12 @@ $usr_nm = session('usr_nm');
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -66,19 +72,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -101,12 +135,27 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>현장확인V2 매물 접수 현황</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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;">
@@ -176,10 +225,8 @@ $usr_nm = session('usr_nm');
<div class="d-flex gap-1">
<select name="rcpt_stat1" class="form-select form-select-sm">
<option value="">예약확인지연</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "STEP_VERIFICATION"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['STEP_VERIFICATION']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
<select name="rcpt_stat2" id="srcGugun" class="form-select form-select-sm">
@@ -195,10 +242,8 @@ $usr_nm = session('usr_nm');
<label class="form-label mb-1">거래구분</label>
<select class="form-select" name="rcpt_product_info1">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "NHN_DEAL_TYPE"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['NHN_DEAL_TYPE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cdNm ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -234,10 +279,8 @@ $usr_nm = session('usr_nm');
<label class="form-label mb-1">CP ID</label>
<select class="form-select" name="rcpt_cpid">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "CP_ID"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['CP_ID']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -246,10 +289,8 @@ $usr_nm = session('usr_nm');
<label class="form-label mb-1">매물종류</label>
<select class="form-select" name="rcpt_product">
<option value="">전체</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "ARTICLE_TYPE"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['ARTICLE_TYPE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -420,6 +461,9 @@ $usr_nm = session('usr_nm');
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 userColumns = <?= ($usr_level != '45')
? "[{ data: 'dept_nm' }, { data: 'usr_nm' }]"
: "[]" ?>;
const date = new Date();
var table;
@@ -660,14 +704,11 @@ $usr_nm = session('usr_nm');
{ data: null, render: fn_agent_render },
{ data: null, render: fn_addr_render },
{ data: null, render: fn_prd_render },
{ data: 'rcpt_product_info1' },
<?php if ($usr_level != "45"): ?>
{ data: 'dept_nm' },
{ data: 'usr_nm' },
<?php endif; ?>
{ data: 'rcpt_product_info1' }
].concat(userColumns, [
{ data: 'parcel_out_yn' },
{ data: 'conf_img_yn' },
],
{ data: 'conf_img_yn' }
]),
// 옵션들 예시
destroy: true,
deferRender: true,

View File

@@ -2277,6 +2277,7 @@ $usr_level = session('usr_level');
}
}
// 가격수정 저장
function modifyPriceInfo() {
swal.fire({
@@ -2675,9 +2676,10 @@ $usr_level = session('usr_level');
title: "정상 처리되었습니다.",
icon: "success",
draggable: true
})
location.reload();
}).then(() => {
// 녹취파일 체크박스 활성화 및 체크
$('#chk_record').prop('disabled', false).prop('checked', true);
});
} else {
Swal.fire({
title: result.msg,

View File

@@ -14,6 +14,12 @@ $usr_nm = session('usr_nm');
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#resultList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
@@ -66,19 +72,47 @@ $usr_nm = session('usr_nm');
overflow-x: auto !important;
}
/* 테이블 폭: 내용 기준으로 커지되, 최소는 100% */
/* 테이블 폭: 내용에 따라 자동 조정, 스크롤 필요시 표시 */
.table-responsive #resultList {
width: max-content !important;
min-width: 100% !important;
width: 100% !important;
table-layout: auto !important;
}
/* 줄바꿈 금지 */
/* 줄바꿈 허용 - 공백 기준으로 줄바꿈 */
#resultList th,
#resultList td {
white-space: nowrap;
white-space: normal !important;
word-wrap: break-word;
}
/* tw-* 클래스가 DataTable의 inline 스타일보다 우선순위 높이기 */
#resultList th.tw-30,
#resultList td.tw-30 { width: 30px !important; max-width: 30px !important; min-width: 30px !important; }
#resultList th.tw-50,
#resultList td.tw-50 { width: 50px !important; max-width: 50px !important; min-width: 50px !important; }
#resultList th.tw-70,
#resultList td.tw-70 { width: 70px !important; max-width: 70px !important; min-width: 70px !important; }
#resultList th.tw-80,
#resultList td.tw-80 { width: 80px !important; max-width: 80px !important; min-width: 80px !important; }
#resultList th.tw-90,
#resultList td.tw-90 { width: 90px !important; max-width: 90px !important; min-width: 90px !important; }
#resultList th.tw-100,
#resultList td.tw-100 { width: 100px !important; max-width: 100px !important; min-width: 100px !important; }
#resultList th.tw-120,
#resultList td.tw-120 { width: 120px !important; max-width: 120px !important; min-width: 120px !important; }
#resultList th.tw-130,
#resultList td.tw-130 { width: 130px !important; max-width: 130px !important; min-width: 130px !important; }
#resultList th.tw-140,
#resultList td.tw-140 { width: 140px !important; max-width: 140px !important; min-width: 140px !important; }
#resultList th.tw-150,
#resultList td.tw-150 { width: 150px !important; max-width: 150px !important; min-width: 150px !important; }
#resultList th.tw-180,
#resultList td.tw-180 { width: 180px !important; max-width: 180px !important; min-width: 180px !important; }
#resultList th.tw-200,
#resultList td.tw-200 { width: 200px !important; max-width: 200px !important; min-width: 200px !important; }
#resultList th.tw-250,
#resultList td.tw-250 { width: 250px !important; max-width: 250px !important; min-width: 250px !important; }
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
@@ -101,12 +135,27 @@ $usr_nm = session('usr_nm');
.card-body {
min-width: 0;
}
</style>
<h1>녹취매물 내역</h1>
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<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;">
@@ -227,18 +276,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">
@@ -520,7 +568,7 @@ $usr_nm = session('usr_nm');
if (!rowData) return;
const rcpt_key = rowData.rcpt_key;
location.href = "<?= site_url('article/record/detail') ?>/" + rcpt_key;
window.open("<?= site_url('article/record/detail') ?>/" + rcpt_key, '_blank');
});

View File

@@ -69,6 +69,15 @@
<div class="h-100 bg-plum-plate bg-animation">
<div class="d-flex h-100 justify-content-center align-items-center py-4">
<div class="mx-auto col-sm-10 col-md-8 col-lg-6 col-xl-5">
<!-- Redis 장애 경고 영역 -->
<div id="redis-warning" class="alert alert-warning alert-dismissible fade d-none mb-3"
style="border-radius: 16px; background: rgba(255, 193, 7, 0.95); backdrop-filter: blur(10px); box-shadow: 0 4px 12px rgba(0,0,0,0.15);">
<strong><i class="fa fa-exclamation-triangle me-2"></i>시스템 알림</strong>
<p id="redis-warning-message" class="mb-0 mt-2"></p>
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
</div>
<div class="card border-0"
style="border-radius: 24px; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(20px); box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);">
<div class="card-body p-5">
@@ -202,6 +211,27 @@
const tpl = document.querySelector('.my-loader-template');
var table;
// Redis 장애 경고 표시 함수
function showRedisWarning(message) {
const warningDiv = $('#redis-warning');
const messageEl = $('#redis-warning-message');
messageEl.text(message);
warningDiv.removeClass('d-none').addClass('show');
// 10초 후 자동 숨김 (선택사항)
setTimeout(function() {
warningDiv.fadeOut();
}, 15000);
}
// 시스템 상태 체크 함수
function checkSystemStatus(responseData) {
if (responseData.system && responseData.system.redis_fallback) {
showRedisWarning(responseData.system.warning_message);
}
}
$(function () {
$("#btnSearch").on("click", function () {
@@ -231,6 +261,9 @@
console.log(xhr.responseText);
},
success: function (result) {
// 시스템 상태 체크 (Redis 장애 여부)
checkSystemStatus(result);
if (result.code === "0") {
location.href = '/'
} else {

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

@@ -4,6 +4,17 @@
<style>
th {
font-size: 11px;
text-align: center;
}
/* 테이블 헤더 좌우 여백 조정 */
#userList thead th {
padding-left: 4px !important;
padding-right: 4px !important;
}
td {
text-align: center;
}
#userList tbody tr {
@@ -18,24 +29,61 @@
background-color: #ff0000 !important;
color: #fff !important;
}
/* PC에서 가로 스크롤이 잘리는 대표 구간들 강제 해제 */
.main-card,
.card,
.card-body {
overflow-x: visible !important;
}
/* 만약 레이아웃 wrapper가 숨기고 있으면 이것도 */
.app-main__outer,
.app-main__inner,
.app-main {
overflow-x: visible !important;
}
/* flex 환경에서 필수 */
.app-main,
.app-main__outer,
.app-main__inner,
.card,
.card-body {
min-width: 0;
}
/* 검색 영역 행마다 구분선 추가 */
#frm_srch_info .row.g-3 {
padding: 12px 0;
border-bottom: 1px solid #e9ecef;
}
#frm_srch_info .row.g-3:last-child {
border-bottom: none;
}
</style>
<h1>현장확인인원별배정현황</h1>
<div class="row">
<div class="col-md-12 col-xl-12">
<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;">
<form id="frm_srch_info" onsubmit="return false;">
<!-- 1줄 -->
<div class="row mb-3">
<div class="row g-3 mb-3">
<!-- 관할조직 -->
<div class="col-md-2">
<label class="form-label mb-1">관할조직</label>
<label class="form-label mb-1 text-sm fw-semibold text-muted">관할조직</label>
<div class="row g-2">
<div class="col-6">
<select class="form-control" name="bonbu" id="bonbu">
<select class="form-control form-control-sm" name="bonbu" id="bonbu">
<option value="">선택</option>
<?php foreach ($bonbu as $d): ?>
<option value="<?= $d['dept_sq'] ?>"><?= $d['dept_nm'] ?></option>
@@ -43,7 +91,7 @@
</select>
</div>
<div class="col-6">
<select class="form-control" name="dept_sq" id="dept_sq">
<select class="form-control form-control-sm" name="dept_sq" id="dept_sq">
<option value="">선택</option>
</select>
</div>
@@ -52,8 +100,8 @@
<!-- 유형 -->
<div class="col-md-1">
<label class="form-label mb-1">유형</label>
<select class="form-control" name="schDateGb">
<label class="form-label mb-1 text-sm fw-semibold text-muted">유형</label>
<select class="form-control form-control-sm" name="schDateGb">
<option value="1">예약일자</option>
<option value="2">등록일자</option>
</select>
@@ -61,24 +109,24 @@
<!-- 기준일자 -->
<div class="col-md-3">
<label class="form-label mb-1">기준일자</label>
<label class="form-label mb-1 text-sm fw-semibold text-muted">기준일자</label>
<div class="row g-2">
<div class="col-5">
<input type="date" class="form-control" id="sdate" name="sdate">
<input type="date" class="form-control form-control-sm" id="sdate" name="sdate">
</div>
<div class="col-2 d-flex align-items-center justify-content-center">~</div>
<div class="col-5">
<input type="date" class="form-control" id="edate" name="edate">
<input type="date" class="form-control form-control-sm" id="edate" name="edate">
</div>
</div>
</div>
<!-- 지역검색 -->
<div class="col-md-4">
<label class="form-label mb-1">지역검색</label>
<label class="form-label mb-1 text-sm fw-semibold text-muted">지역검색</label>
<div class="row g-2">
<div class="col-4">
<select class="form-control" name="srcSido" id="srcSido">
<select class="form-control form-control-sm" name="srcSido" id="srcSido">
<option value="">시/도</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>"><?= $s['region_nm'] ?></option>
@@ -86,12 +134,12 @@
</select>
</div>
<div class="col-4">
<select class="form-control" name="srcGugun" id="srcGugun">
<select class="form-control form-control-sm" name="srcGugun" id="srcGugun">
<option value="">시/군/구</option>
</select>
</div>
<div class="col-4">
<select class="form-control" name="srcDong" id="srcDong">
<select class="form-control form-control-sm" name="srcDong" id="srcDong">
<option value="">읍/면/동</option>
</select>
</div>
@@ -100,11 +148,11 @@
</div>
<!-- 2줄 -->
<div class="row mb-3">
<div class="row g-3">
<!-- 검색유형 -->
<div class="col-md-1">
<label class="form-label mb-1">검색유형</label>
<select class="form-control" name="srchType">
<label class="form-label mb-1 text-sm fw-semibold text-muted">검색유형</label>
<select class="form-control form-control-sm" name="srchType">
<option value="">선택</option>
<option value="1">아이디</option>
<option value="2">이름</option>
@@ -113,13 +161,13 @@
<!-- 검색어 -->
<div class="col-md-2">
<label class="form-label mb-1">검색어</label>
<input type="text" class="form-control" name="srchTxt" placeholder="검색어 입력">
<label class="form-label mb-1 text-sm fw-semibold text-muted">검색어</label>
<input type="text" class="form-control form-control-sm" name="srchTxt" placeholder="검색어 입력">
</div>
<!-- 검색버튼 -->
<div class="col-md-1 d-grid align-items-end">
<button type="button" class="btn btn-primary" id="btnSearch">검색</button>
<div class="col-md-1 d-flex align-items-end">
<button type="button" class="btn btn-primary btn-sm w-100" id="btnSearch">검색</button>
</div>
</div>
@@ -127,20 +175,21 @@
</div>
</div>
</div>
</div>
<div class="col-md-12 col-xl-12">
<div class="col-md-12 col-xl-12">
<div class="main-card mb-3 card">
<div class="card-header d-flex align-items-center">
<h3 class="card-title mb-0">사용자 목록</h3>
<div class="ms-auto d-flex align-items-center gap-3">
<button class="mb-2 me-2 border-0 btn-transition btn btn-shadow btn-outline-success"
id="excel-download">
<i class="fa fa-fw" aria-hidden="true" title="file-excel-o"></i>엑셀다운로드
<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 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>
엑셀다운로드
</button>
</div>
</div>
</div>
<div class="card-body">
<table id="userList" class="table table-hover table-striped table-bordered">
<thead>
@@ -174,7 +223,6 @@
</table>
</div>
</div>
</div>
</div>
@@ -269,7 +317,8 @@
let table = $('#userList').DataTable({
language: lang_kor,
processing: true,
serverSide: false,
serverSide: true,
pageLength: 25,
ajax: {
url: '/results/assign/getUserList',
type: 'GET',
@@ -291,20 +340,17 @@
d.srchType = $("#frm_srch_info [name=srchType]").val()
d.srchTxt = $("#frm_srch_info [name=srchTxt]").val()
d.start = d.start || 0
d.length = d.length || 10
}
},
"columnDefs": [
{ 'targets': '_all', "defaultContent": "" },
{ 'className': 'text-center', 'targets': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] },
columnDefs: [
{ targets: '_all', defaultContent: "" },
{ className: 'text-center', targets: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] },
],
columns: [
{
"data": null,
"width": "50px",
"render": function (data, type, row, meta) {
data: null,
width: "50px",
render: function (data, type, row, meta) {
return meta.row + meta.settings._iDisplayStart + 1;
}
},
@@ -325,11 +371,9 @@
{ data: 'PM07' },
{ data: 'TODAY' },
],
// 옵션들 예시
paging: true,
searching: false,
ordering: false,
serverSide: true,
});
@@ -337,7 +381,9 @@
const row = table.row(this).data()
if (!row) return
location.href = '/article/receipt/lists';
location.href = '/article/receipt/lists?usr_id=' + row.usr_id;
});
// [검색] 버튼 눌렀을 때 다시 조회

View File

@@ -0,0 +1,534 @@
<?= $this->extend('layouts/main') ?>
<?= $this->section('content') ?>
<style>
th {
font-size: 11px;
}
#userList 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-body">
<form class="row align-items-end" id="frm_srch_info" onsubmit="return false;">
<!-- 1줄 -->
<div class="row mb-3">
<!-- 관할조직 -->
<div class="col-md-2">
<label class="form-label mb-1">관할조직</label>
<div class="row g-2">
<div class="col-6">
<select class="form-control" name="bonbu" id="bonbu">
<option value="">선택</option>
<?php foreach ($bonbu as $d): ?>
<option value="<?= $d['dept_sq'] ?>"><?= $d['dept_nm'] ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-6">
<select class="form-control" name="dept_sq" id="dept_sq">
<option value="">선택</option>
</select>
</div>
</div>
</div>
<!-- 유형 -->
<div class="col-md-1">
<label class="form-label mb-1">유형</label>
<select class="form-control" name="schDateGb">
<option value="1">예약일자</option>
<option value="2">등록일자</option>
</select>
</div>
<!-- 기준일자 -->
<div class="col-md-3">
<label class="form-label mb-1">기준일자</label>
<div class="row g-2">
<div class="col-5">
<input type="date" class="form-control" id="sdate" name="sdate">
</div>
<div class="col-2 d-flex align-items-center justify-content-center">~</div>
<div class="col-5">
<input type="date" class="form-control" id="edate" name="edate">
</div>
</div>
</div>
<!-- 지역검색 -->
<div class="col-md-4">
<label class="form-label mb-1">지역검색</label>
<div class="row g-2">
<div class="col-4">
<select class="form-control" name="srcSido" id="srcSido">
<option value="">시/도</option>
<?php foreach ($sido as $s): ?>
<option value="<?= $s['region_cd'] ?>"><?= $s['region_nm'] ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="col-4">
<select class="form-control" name="srcGugun" id="srcGugun">
<option value="">시/군/구</option>
</select>
</div>
<div class="col-4">
<select class="form-control" name="srcDong" id="srcDong">
<option value="">읍/면/동</option>
</select>
</div>
</div>
</div>
</div>
<!-- 2줄 -->
<div class="row mb-3">
<!-- 검색유형 -->
<div class="col-md-1">
<label class="form-label mb-1">검색유형</label>
<select class="form-control" name="srchType">
<option value="">선택</option>
<option value="1">아이디</option>
<option value="2">이름</option>
</select>
</div>
<!-- 검색어 -->
<div class="col-md-2">
<label class="form-label mb-1">검색어</label>
<input type="text" class="form-control" name="srchTxt" placeholder="검색어 입력">
</div>
<!-- 검색버튼 -->
<div class="col-md-1 d-grid align-items-end">
<button type="button" class="btn btn-primary" id="btnSearch">검색</button>
</div>
</div>
</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">
<h3 class="card-title mb-0">사용자 목록</h3>
<div class="ms-auto d-flex align-items-center gap-3">
<button class="mb-2 me-2 border-0 btn-transition btn btn-shadow 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="userList" class="table table-hover table-striped table-bordered">
<thead>
<tr>
<th rowspan="2">순번</th>
<th rowspan="2">아이디</th>
<th rowspan="2">이름</th>
<th colspan="5" style="text-align: center;">오전</th>
<th colspan="8" style="text-align: center;">오후</th>
<th rowspan="2">합계</th>
</tr>
<tr>
<th width="50">무관</th>
<th width="50">9</th>
<th width="50">10</th>
<th width="50">11</th>
<th width="50">12</th>
<th width="50">무관</th>
<th width="50">1</th>
<th width="50">2</th>
<th width="50">3</th>
<th width="50">4</th>
<th width="50">5</th>
<th width="50">6</th>
<th width="50">7</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</div>
</div>
</div>
</div>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.13.6/css/jquery.dataTables.min.css" />
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<script type="text/javascript">
// const tpl = document.querySelector('.my-loader-template');
var teamArr = <?= json_encode($team, JSON_UNESCAPED_UNICODE); ?>;
let date = new Date();
$(function () {
$("#bonbu").on("change", function (e) {
var dept_sq = e.target.value
$("#dept_sq").empty()
var str = "<option value=''>선택</option>"
if (teamArr != null) {
for (var i = 0; i < teamArr.length; i++) {
if (dept_sq === teamArr[i].pdept_sq) {
str += "<option value='" + teamArr[i].dept_sq + "'>" + teamArr[i].dept_nm + "</option>"
}
}
}
$("#dept_sq").append(str)
});
$("#srcSido, #srcGugun").on("change", function (e) {
const targetId = this.id;
$.ajax({
url: "/manage/areas/getAreaList",
method: "POST",
dataType: "json",
data: {
'srcSido': $("#frm_srch_info [name=srcSido]").val(),
'srcGugun': $("#frm_srch_info [name=srcGugun]").val(),
},
beforeSend: function () {
blockUI.blockPage({
message: tpl
})
},
complete: function () {
blockUI.unblockPage()
},
success: function (result) {
switch (targetId) {
case "srcSido":
$("#srcGugun").empty()
var str = "";
str += "<option value=''>시/군/구</option>";
if (result.length > 0) {
for (var i = 0; i < result.length; i++) {
str += "<option value='" + result[i]['region_cd'] + "'>" + result[i].region_nm + "</option>";
}
}
$("#srcGugun").append(str);
break;
case "srcGugun":
$("#srcDong").empty()
var str = "";
str += "<option value=''>읍/면/동</option>";
if (result.length > 0) {
for (var i = 0; i < result.length; i++) {
str += "<option value='" + result[i]['region_cd'] + "'>" + result[i].region_nm + "</option>";
}
}
$("#srcDong").append(str);
break;
}
}
});
});
let table = $('#userList').DataTable({
language: lang_kor,
processing: true,
serverSide: false,
ajax: {
url: '/results/assign/getUserList',
type: 'GET',
beforeSend: function () {
blockUI.blockPage({
message: tpl
})
},
complete: function () {
blockUI.unblockPage()
},
data: function (d) {
d.schDateGb = $("#frm_srch_info [name=schDateGb]").val()
d.sdate = $("#frm_srch_info [name=sdate]").val()
d.edate = $("#frm_srch_info [name=edate]").val()
d.bonbu = $("#frm_srch_info [name=bonbu]").val()
d.team = $("#frm_srch_info [name=dept_sq]").val()
d.srchType = $("#frm_srch_info [name=srchType]").val()
d.srchTxt = $("#frm_srch_info [name=srchTxt]").val()
d.start = d.start || 0
d.length = d.length || 10
}
},
"columnDefs": [
{ 'targets': '_all', "defaultContent": "" },
{ 'className': 'text-center', 'targets': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] },
],
columns: [
{
"data": null,
"width": "50px",
"render": function (data, type, row, meta) {
return meta.row + meta.settings._iDisplayStart + 1;
}
},
{ data: 'usr_id' },
{ data: 'usr_nm' },
{ data: 'AMETC' },
{ data: 'AM09' },
{ data: 'AM10' },
{ data: 'AM11' },
{ data: 'AM12' },
{ data: 'PMETC' },
{ data: 'PM01' },
{ data: 'PM02' },
{ data: 'PM03' },
{ data: 'PM04' },
{ data: 'PM05' },
{ data: 'PM06' },
{ data: 'PM07' },
{ data: 'TODAY' },
],
// 옵션들 예시
paging: true,
searching: false,
ordering: false,
serverSide: true,
});
$('#userList tbody').on('click', 'tr', function () {
const row = table.row(this).data()
if (!row) return
location.href = '/article/receipt/lists?usr_id=' + row.usr_id;
});
// [검색] 버튼 눌렀을 때 다시 조회
$('#btnSearch').on('click', function () {
table.ajax.reload()
});
// 유저 등록 모달
$("#addUser").on("click", function () {
// $("#frm_user_info")[0].reset()
// $("#frm_user_info [name=usr_sq]").val("")
// $("#frm_user_info [name=type]").val("create")
// $("#frm_user_info [name=addUserId]").prop("readonly", false)
// const modalEl = document.getElementById('userModal');
// const myModal = new bootstrap.Modal(modalEl);
// myModal.show();
});
// 엑셀다운 click
$("#excel-download").on("click", function () {
$.ajax({
url: "/results/assign/excel",
method: "GET",
dataType: "json",
data: $("#frm_srch_info").serialize(),
beforeSend: function () {
blockUI.blockPage({
message: tpl
})
},
complete: function () {
blockUI.unblockPage()
},
success: function (result) {
// downloadExcel(result.data);
downloadExcelWithHeader(result.data);
}
});
});
});
// 엑셀 다운로드
function downloadExcelWithHeader(dataRows) {
// 1) 헤더 (16컬럼)
const header1 = [
"아이디", "이름",
"오전", "", "", "", "",
"오후", "", "", "", "", "", "", "",
"합계"
];
const header2 = [
"", "",
"무관", "9", "10", "11", "12",
"무관", "1", "2", "3", "4", "5", "6", "7",
""
];
// 2) 바디 (16컬럼 정확히 맞춤)
const body = dataRows.map(r => ([
r.usr_id,
r.usr_nm,
r.AMETC, r.AM09, r.AM10, r.AM11, r.AM12,
r.PMETC, r.PM01, r.PM02, r.PM03, r.PM04, r.PM05, r.PM06, r.PM07,
r.TODAY
]));
const aoa = [header1, header2, ...body];
// 3) 시트 생성
const ws = XLSX.utils.aoa_to_sheet(aoa);
// 4) 병합(colspan / rowspan)
ws["!merges"] = [
// 아이디, 이름 (rowspan 2)
{ s: { r: 0, c: 0 }, e: { r: 1, c: 0 } }, // A1:A2
{ s: { r: 0, c: 1 }, e: { r: 1, c: 1 } }, // B1:B2
// 오전 (colspan 5)
{ s: { r: 0, c: 2 }, e: { r: 0, c: 6 } }, // C1:G1
// 오후 (colspan 8)
{ s: { r: 0, c: 7 }, e: { r: 0, c: 14 } }, // H1:O1
// 합계 (rowspan 2)
{ s: { r: 0, c: 15 }, e: { r: 1, c: 15 } }, // P1:P2
];
ws['!cols'] = [
{ wpx: 80 }, // A: 아이디
{ wpx: 100 }, // B: 이름
{ wpx: 50 }, // C: 오전-무관
{ wpx: 50 }, // D: 오전-9
{ wpx: 50 }, // E: 오전-10
{ wpx: 50 }, // F: 오전-11
{ wpx: 50 }, // G: 오전-12
{ wpx: 50 }, // H: 오후-무관
{ wpx: 50 }, // I: 오후-1
{ wpx: 50 }, // J: 오후-2
{ wpx: 50 }, // K: 오후-3
{ wpx: 50 }, // L: 오후-4
{ wpx: 50 }, // M: 오후-5
{ wpx: 50 }, // N: 오후-6
{ wpx: 50 }, // O: 오후-7
{ wpx: 60 }, // P: 합계
];
// 6) 저장
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
XLSX.writeFile(
wb,
"현장확인인원별배정현황" + getDateTimeString() + ".xlsx"
);
}
// 엑셀 다운로드
function downloadExcel(data) {
const ws = XLSX.utils.json_to_sheet(data);
ws['!cols'] = [
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
{ wpx: 80 },
];
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
const blob = new Blob([wbout], { type: 'application/octet-stream' });
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = "현장확인인원별배정현황" + getDateTimeString() + ".xlsx";
link.click();
URL.revokeObjectURL(link.href);
}
function getDateTimeString() {
const d = new Date();
const yyyy = d.getFullYear();
const mm = String(d.getMonth() + 1).padStart(2, '0');
const dd = String(d.getDate()).padStart(2, '0');
const hh = String(d.getHours()).padStart(2, '0');
const mi = String(d.getMinutes()).padStart(2, '0');
const ss = String(d.getSeconds()).padStart(2, '0');
return `${yyyy}${mm}${dd}${hh}${mi}${ss}`;
}
window.addEventListener("DOMContentLoaded", function () {
// 오늘 날짜
const today = new Date();
// 이번 달 1일
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
// 이번 달 말일 (다음달 0일 = 이번달 말일)
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
// yyyy-mm-dd 형태로 변환
const toDate = (d) => d.toISOString().split("T")[0];
document.getElementById("sdate").value = toDate(firstDay);
document.getElementById("edate").value = toDate(lastDay);
});
</script>
<?= $this->endSection() ?>

View File

@@ -144,13 +144,14 @@
$nRow = 1;
foreach ($st_list as $row) {
// if ($row['depth'] == '1') {
// $rowPars = array_merge($pars, array('bonbu' => $row['dept_sq']));
// } else {
// $rowPars = array_merge($pars, array('bonbu' => $row['pdept_sq'], 'dept_sq' => $row['dept_sq']));
// }
$pars = [];
if ($row['depth'] == '1') {
$rowPars = array_merge($pars, array('bonbu' => $row['dept_sq']));
} else {
$rowPars = array_merge($pars, array('bonbu' => $row['pdept_sq'], 'dept_sq' => $row['dept_sq']));
}
echo '<tr onmouseover="this.className=\'highlight\'" onmouseout="this.className=\'normal\'" style="cursor:pointer" onclick="tr_onclick();">';
echo '<tr onmouseover="this.className=\'highlight\'" onmouseout="this.className=\'normal\'" style="cursor:pointer" onclick="tr_onclick(\'' . make_query_string($rowPars) . '\');">';
echo '<td>' . $nRow . '</td>';
echo '<td style="text-align:left">' . str_replace(' ', '&nbsp;', $row['dept_nm']) . '</td>';
echo '<td>' . $row['region_cnt'] . '</td>';
@@ -231,8 +232,8 @@
});
function tr_onclick() {
location.href = '/article/receipt/lists';
function tr_onclick(pars) {
location.href = '/article/receipt/lists' + pars;
}
// 엑셀 다운로드

View File

@@ -326,7 +326,7 @@
// myModal.show();
location.href = '/article/receipt/lists';
location.href = '/article/receipt/lists?usr_id=' + row.usr_id;
});

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>
@@ -180,12 +160,10 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<select class="form-select form-select-sm" name="atcl_vrtc_way"
id="atcl_vrtc_way" disabled>
<option value="">-선택-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "VRFCREQ_WAY"): ?>
<option value="<?= $c['cd'] ?>" <?= ($c['cd'] === $data['vrfc_type_cd']) ? 'selected' : '' ?>>
<?= $c['cd_nm'] ?>
<?php foreach (($codes['VRFCREQ_WAY']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>" <?= ($cd === $data['vrfc_type_cd']) ? 'selected' : '' ?>>
<?= $cdNm ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
<?= $data['update_res_tm'] ?>
@@ -300,7 +278,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 +297,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 +532,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 +556,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,20 +592,18 @@ 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): ?>
<?php if ($c['category'] === "STEP_VERIFICATION"): ?>
<?php foreach (($codes['STEP_VERIFICATION']['items'] ?? []) as $cd => $cdNm): ?>
<button class="mb-2 me-2 btn btn-light"
onclick="fn_status_change(<?= $data['vr_sq'] ?>, '<?= $c['cd'] ?>', '<?= $c['cd_nm'] ?>');"><?= $c['cd_nm'] ?></button>
<?php endif; ?>
onclick="fn_status_change(<?= $data['vr_sq'] ?>, '<?= $cd ?>', '<?= $cdNm ?>');"><?= $cdNm ?></button>
<?php endforeach; ?>
</div>
</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 +621,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 +645,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 +653,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 +684,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>
@@ -720,12 +702,10 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<select class="form-select" id="fax_conf_res_d11"
name="fax_conf_res_d11">
<option value="">-선택-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "CONFIRM_RESULT_D11"): ?>
<option value="<?= $c['cd'] ?>" <?= ($c['cd'] === $data['result_d11']) ? 'selected' : '' ?>>
<?= $c['cd_nm'] ?>
<?php foreach (($codes['CONFIRM_RESULT_D11']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>" <?= ($cd === $data['result_d11']) ? 'selected' : '' ?>>
<?= $cdNm ?>
</option>
<?php endif; ?>
<?php endforeach; ?>
</select>
</td>
@@ -734,7 +714,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']);
@@ -749,12 +729,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
];
$nCnt = 0;
$code_comment = [];
foreach ($codes as $c) {
if ($c['category'] === "CONSULTANT_COMMENT") {
array_push($code_comment, $c);
}
}
$code_comment = $codes['CONSULTANT_COMMENT']['items'] ?? [];
foreach ($code_comment as $key => $value) {
if ($nCnt % 2 == 0 && $nCnt != 0) {
@@ -774,7 +749,7 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
id="comment_<?= $key ?>" disabled>
<label class="form-check-label ms-1 small"
for="price_ignore1">
<?= $value['cd_nm'] ?>
<?= $value ?>
</label>
</div>
</td>
@@ -864,14 +839,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>
@@ -897,12 +872,10 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<td>
<select class="form-select" name="tel_agree" id="tel_agree">
<option value="">-선택-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "CONFIRM_RESULT_T11"): ?>
<option value="<?= $c['cd'] ?>" <?php if ($c['cd'] === $data['tel_agree']) {
<?php foreach (($codes['CONFIRM_RESULT_T11']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>" <?php if ($cd === $data['tel_agree']) {
echo "selected";
} ?>><?= $c['cd_nm'] ?></option>
<?php endif; ?>
} ?>><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</td>
@@ -1045,7 +1018,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>
@@ -1059,14 +1032,11 @@ if (!empty($data['cert_register']) && $data['cert_register_save_yn'] != 'Y') { /
<th>통화실패사유</th>
<td class="d-flex gap-2">
<select class="form-select" name="tel_fail_cause" id="tel_fail_cause">
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "TEL_FAIL_CAUSE"): ?>
<option value="<?= $c['cd'] ?>" <?php if ($c['cd'] === $data['tel_fail_cause']) {
<?php foreach (($codes['TEL_FAIL_CAUSE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>" <?php if ($cd === $data['tel_fail_cause']) {
echo 'selected';
} ?>><?= $c['cd_nm'] ?></option>
<?php endif; ?>
} ?>><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</td>
</tr>
@@ -1086,7 +1056,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 +1073,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 +1094,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 +1132,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 +1318,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 +1569,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>
@@ -79,10 +38,8 @@
<label class="form-label mb-1">현재상태</label>
<select name="stat_cd" class="form-select form-select-sm">
<option value="">-선택-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "STEP_VERIFICATION"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['STEP_VERIFICATION']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -175,10 +132,8 @@
<div class="d-flex gap-2">
<select name="vrfcreq_way" id="vrfcreq_way" class="form-select form-select-sm">
<option value="">-검증방식-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "VRFCREQ_WAY"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['VRFCREQ_WAY']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
<select name="vrfc_type_sub" id="vrfc_type_sub" class="form-select form-select-sm">
@@ -192,10 +147,8 @@
<label class="form-label mb-1">매체사</label>
<select name="rcpt_cpid" class="form-select form-select-sm">
<option value="">-전체-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "CP_ID"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['CP_ID']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -205,10 +158,8 @@
<label class="form-label mb-1">매물종류</label>
<select name="rlet_type_cd" class="form-select form-select-sm">
<option value="">-매물종류-</option>
<?php foreach ($codes as $c): ?>
<?php if ($c['category'] === "ARTICLE_TYPE"): ?>
<option value="<?= $c['cd'] ?>"><?= $c['cd_nm'] ?></option>
<?php endif; ?>
<?php foreach (($codes['ARTICLE_TYPE']['items'] ?? []) as $cd => $cdNm): ?>
<option value="<?= $cd ?>"><?= $cdNm ?></option>
<?php endforeach; ?>
</select>
</div>
@@ -246,23 +197,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,11 +226,18 @@
</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') ?>
<?= $this->include('layouts/partials/datatables_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>
<script defer src="/architectui/assets/js/datatable.kor.js"></script>
<style>
#resultList_wrapper .dt-start { display: flex; align-items: center; gap: 1rem; align-items: baseline;}
</style>
<?= $this->endSection() ?>
<?= $this->section('page_scripts') ?>
<?= $this->include('layouts/partials/datatables_js') ?>
<script type="text/javascript" src="https://oapi.map.naver.com/openapi/v3/maps.js?ncpKeyId=dtounkwjc5"></script>
<script type="text/javascript">
@@ -305,7 +248,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 +453,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 +518,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 +539,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;
location.href = "<?= site_url('m701/m701a/detail') ?>/" + vr_sq;
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>

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