feat: 데이터베이스 및 웹 UI 대규모 리팩토링
- 삭제된 DB 테이블들과 관련 코드 정리: * 12개 사용하지 않는 테이블 삭제 (activity_logs, CuttingPlan, DailyIssueReports 등) * 관련 모델, 컨트롤러, 라우트 파일들 삭제 * index.js에서 삭제된 라우트들 제거 - 웹 UI 페이지 정리: * 21개 사용하지 않는 페이지 삭제 * issue-reports 폴더 전체 삭제 * 모든 사용자 권한을 그룹장 대시보드로 통일 - 데이터베이스 스키마 정리: * v1 스키마로 통일 (daily_work_reports 테이블) * JSON 데이터 임포트 스크립트 구현 * 외래키 관계 정리 및 데이터 일관성 확보 - 통합 Docker Compose 설정: * 모든 서비스를 단일 docker-compose.yml로 통합 * 20000번대 포트 유지 * JWT 시크릿 및 환경변수 설정 - 문서화: * DATABASE_SCHEMA.md: 현재 DB 스키마 문서화 * DELETED_TABLES.md: 삭제된 테이블 목록 * DELETED_PAGES.md: 삭제된 페이지 목록
This commit is contained in:
166
DATABASE_SCHEMA.md
Normal file
166
DATABASE_SCHEMA.md
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# TK-FB 프로젝트 데이터베이스 스키마
|
||||||
|
|
||||||
|
**업데이트 날짜**: 2025-11-03
|
||||||
|
**데이터베이스**: hyungi
|
||||||
|
**구조**: v1 (원본 JSON 데이터 호환)
|
||||||
|
|
||||||
|
## 📊 메인 테이블
|
||||||
|
|
||||||
|
### `daily_work_reports` - 일일 작업 보고서
|
||||||
|
```sql
|
||||||
|
- id (PK, AUTO_INCREMENT)
|
||||||
|
- report_date (DATE, NOT NULL) - 작업 날짜
|
||||||
|
- worker_id (INT, NOT NULL) - 작업자 ID
|
||||||
|
- project_id (INT, NOT NULL) - 프로젝트 ID
|
||||||
|
- work_type_id (INT, NOT NULL) - 작업 유형 ID
|
||||||
|
- work_status_id (INT, DEFAULT 1) - 작업 상태 ID (1:정규, 2:에러)
|
||||||
|
- error_type_id (INT, NULL) - 에러 유형 ID
|
||||||
|
- work_hours (DECIMAL(4,2), NOT NULL) - 작업 시간
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
- created_by (INT, DEFAULT 1) - 작성자 user_id
|
||||||
|
- updated_by (INT, NULL) - 수정자 user_id
|
||||||
|
```
|
||||||
|
|
||||||
|
## 👥 마스터 데이터 테이블
|
||||||
|
|
||||||
|
### `workers` - 작업자 정보
|
||||||
|
```sql
|
||||||
|
- worker_id (PK, AUTO_INCREMENT)
|
||||||
|
- worker_name (VARCHAR(100), NOT NULL) - 작업자명
|
||||||
|
- join_date (DATE) - 입사일
|
||||||
|
- job_type (VARCHAR(100)) - 직종
|
||||||
|
- salary (DECIMAL(10,2)) - 급여
|
||||||
|
- annual_leave (INT) - 연차
|
||||||
|
- status (TEXT, DEFAULT 'active') - 상태
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `projects` - 프로젝트 정보
|
||||||
|
```sql
|
||||||
|
- project_id (PK, AUTO_INCREMENT)
|
||||||
|
- job_no (VARCHAR(50), NOT NULL) - 작업 번호
|
||||||
|
- project_name (VARCHAR(255), NOT NULL) - 프로젝트명
|
||||||
|
- contract_date (DATE) - 계약일
|
||||||
|
- due_date (DATE) - 완료 예정일
|
||||||
|
- delivery_method (VARCHAR(100)) - 납품 방법
|
||||||
|
- site (VARCHAR(100)) - 현장
|
||||||
|
- pm (VARCHAR(100)) - 프로젝트 매니저
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `users` - 사용자 정보
|
||||||
|
```sql
|
||||||
|
- user_id (PK, AUTO_INCREMENT)
|
||||||
|
- username (VARCHAR(100), UNIQUE, NOT NULL) - 사용자명
|
||||||
|
- password (VARCHAR(255), NOT NULL) - 비밀번호 (해시)
|
||||||
|
- role (VARCHAR(30)) - 역할
|
||||||
|
- name (VARCHAR(50)) - 실명
|
||||||
|
- email (VARCHAR(255), UNIQUE) - 이메일
|
||||||
|
- worker_id (INT, FK) - 연결된 작업자 ID
|
||||||
|
- is_active (TINYINT(1), DEFAULT 1) - 활성 상태
|
||||||
|
- access_level (VARCHAR(30)) - 접근 레벨
|
||||||
|
- last_login_at (DATETIME) - 마지막 로그인
|
||||||
|
- password_changed_at (DATETIME) - 비밀번호 변경일
|
||||||
|
- failed_login_attempts (INT, DEFAULT 0) - 로그인 실패 횟수
|
||||||
|
- locked_until (DATETIME) - 잠금 해제 시간
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📋 코드 테이블
|
||||||
|
|
||||||
|
### `work_types` - 작업 유형
|
||||||
|
```sql
|
||||||
|
- id (PK, AUTO_INCREMENT)
|
||||||
|
- name (VARCHAR(100), NOT NULL) - 유형명
|
||||||
|
- description (TEXT) - 설명
|
||||||
|
- category (VARCHAR(50)) - 카테고리
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
|
||||||
|
데이터:
|
||||||
|
1. Base(구조물)
|
||||||
|
2. Vessel(용기)
|
||||||
|
3. Piping Assembly(배관)
|
||||||
|
4. 작업대기
|
||||||
|
```
|
||||||
|
|
||||||
|
### `work_status_types` - 작업 상태 유형
|
||||||
|
```sql
|
||||||
|
- id (PK, AUTO_INCREMENT)
|
||||||
|
- name (VARCHAR(50), NOT NULL) - 상태명
|
||||||
|
- description (TEXT) - 설명
|
||||||
|
- is_error (TINYINT(1), DEFAULT 0) - 에러 여부
|
||||||
|
- created_at (TIMESTAMP)
|
||||||
|
|
||||||
|
데이터:
|
||||||
|
1. 정규 (is_error: 0)
|
||||||
|
2. 에러 (is_error: 1)
|
||||||
|
```
|
||||||
|
|
||||||
|
### `error_types` - 에러 유형
|
||||||
|
```sql
|
||||||
|
- id (PK, AUTO_INCREMENT)
|
||||||
|
- name (VARCHAR(100), NOT NULL) - 에러명
|
||||||
|
- description (TEXT) - 설명
|
||||||
|
- severity (ENUM: low/medium/high/critical) - 심각도
|
||||||
|
- solution_guide (TEXT) - 해결 가이드
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
|
||||||
|
데이터:
|
||||||
|
1. 설계미스
|
||||||
|
2. 외주작업 불량
|
||||||
|
3. 입고지연
|
||||||
|
4. 작업불량
|
||||||
|
5. 설비고장
|
||||||
|
6. 검사불량
|
||||||
|
```
|
||||||
|
|
||||||
|
### `tasks` - 작업 정보
|
||||||
|
```sql
|
||||||
|
- task_id (PK, AUTO_INCREMENT)
|
||||||
|
- category (VARCHAR(255), NOT NULL) - 카테고리
|
||||||
|
- subcategory (VARCHAR(255)) - 하위 카테고리
|
||||||
|
- task_name (VARCHAR(255), NOT NULL) - 작업명
|
||||||
|
- description (TEXT) - 설명
|
||||||
|
- created_at, updated_at (TIMESTAMP)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 기타 테이블
|
||||||
|
|
||||||
|
### `IssueTypes` - 이슈 유형
|
||||||
|
### `WorkReports` - 작업 보고서 (별도)
|
||||||
|
### `login_logs` - 로그인 로그
|
||||||
|
### `password_change_logs` - 비밀번호 변경 로그
|
||||||
|
### `work_report_audit_log` - 작업 보고서 감사 로그
|
||||||
|
|
||||||
|
## 🔗 관계 (Foreign Keys)
|
||||||
|
|
||||||
|
```
|
||||||
|
daily_work_reports.worker_id → workers.worker_id
|
||||||
|
daily_work_reports.project_id → projects.project_id
|
||||||
|
daily_work_reports.work_type_id → work_types.id
|
||||||
|
daily_work_reports.work_status_id → work_status_types.id
|
||||||
|
daily_work_reports.error_type_id → error_types.id
|
||||||
|
daily_work_reports.created_by → users.user_id
|
||||||
|
|
||||||
|
users.worker_id → workers.worker_id
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📈 인덱스
|
||||||
|
|
||||||
|
```sql
|
||||||
|
daily_work_reports:
|
||||||
|
- idx_report_date (report_date)
|
||||||
|
- idx_worker_date (worker_id, report_date)
|
||||||
|
- idx_project_date (project_id, report_date)
|
||||||
|
- idx_work_type (work_type_id)
|
||||||
|
- idx_work_status (work_status_id)
|
||||||
|
- idx_error_type (error_type_id)
|
||||||
|
- idx_created_by (created_by)
|
||||||
|
```
|
||||||
|
|
||||||
|
## ⚠️ 주의사항
|
||||||
|
|
||||||
|
1. **v1 구조 사용**: 원본 JSON 데이터와 완전 호환
|
||||||
|
2. **테이블명**: 소문자 사용 (workers, projects, users)
|
||||||
|
3. **작업 상태**: 1=정규, 2=에러
|
||||||
|
4. **에러 유형**: work_status_id=2일 때만 error_type_id 사용
|
||||||
83
DELETED_PAGES.md
Normal file
83
DELETED_PAGES.md
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
# 삭제된 웹 페이지 목록
|
||||||
|
|
||||||
|
**삭제 날짜**: 2025-11-03
|
||||||
|
**사유**: 사용하지 않는 페이지들 정리 및 단일 대시보드 통일
|
||||||
|
|
||||||
|
## 삭제된 페이지들
|
||||||
|
|
||||||
|
### 테스트/임시 페이지
|
||||||
|
1. `common/12.html` - 테스트 페이지
|
||||||
|
2. `common/123.html` - 테스트 페이지
|
||||||
|
3. `common/123456.html` - 테스트 페이지
|
||||||
|
|
||||||
|
### 사용하지 않는 관리 페이지
|
||||||
|
4. `admin/factory-upload.html` - 공장 업로드
|
||||||
|
5. `admin/manage-pipespec.html` - 파이프 사양 관리
|
||||||
|
6. `admin/attendance-validation.html` - 출석 검증
|
||||||
|
7. `admin/work-review.html` - 작업 검토
|
||||||
|
|
||||||
|
### 사용하지 않는 공통 페이지
|
||||||
|
8. `common/factory-upload.html` - 공장 업로드
|
||||||
|
9. `common/factory-view.html` - 공장 보기
|
||||||
|
10. `common/attendance.html` - 출석
|
||||||
|
|
||||||
|
### 전체 폴더 삭제
|
||||||
|
11. `issue-reports/` - 이슈 보고서 관련 전체 폴더
|
||||||
|
|
||||||
|
## 현재 사용 중인 페이지들
|
||||||
|
|
||||||
|
### 📊 대시보드 (통일됨)
|
||||||
|
- `dashboard/group-leader.html` - **메인 대시보드** (모든 권한 사용) ✅
|
||||||
|
- `dashboard/admin.html` - 관리자 대시보드 (미사용)
|
||||||
|
- `dashboard/system.html` - 시스템 대시보드 (미사용)
|
||||||
|
- `dashboard/user.html` - 사용자 대시보드 (미사용)
|
||||||
|
|
||||||
|
### 📋 관리 페이지
|
||||||
|
- `admin/admin dashboard.html` - 관리자 대시보드
|
||||||
|
- `admin/dashboard.html` - 대시보드
|
||||||
|
- `admin/manage-daily-work.html` - 일일 작업 관리 ✅
|
||||||
|
- `admin/manage-issue.html` - 이슈 관리
|
||||||
|
- `admin/manage-project.html` - 프로젝트 관리 ✅
|
||||||
|
- `admin/manage-task.html` - 작업 관리 ✅
|
||||||
|
- `admin/manage-user.html` - 사용자 관리 ✅
|
||||||
|
- `admin/manage-worker.html` - 작업자 관리 ✅
|
||||||
|
|
||||||
|
### 📈 분석 페이지
|
||||||
|
- `analysis/daily_work_analysis.html` - 일일 작업 분석 ✅
|
||||||
|
- `analysis/project-worktype-analysis.html` - 프로젝트-작업유형 분석 ✅
|
||||||
|
- `analysis/work-report-analytics.html` - 작업보고서 분석 ✅
|
||||||
|
|
||||||
|
### 📄 공통 페이지
|
||||||
|
- `common/management-dashboard.html` - 관리 대시보드 ✅
|
||||||
|
- `common/daily-work-report-viewer.html` - 일일 작업보고서 뷰어 ✅
|
||||||
|
- `common/daily-work-report.html` - 일일 작업보고서 ✅
|
||||||
|
- `common/project-analysis.html` - 프로젝트 분석 ✅
|
||||||
|
- `common/work-report-review.html` - 작업보고서 검토 ✅
|
||||||
|
- `common/work-report-validation.html` - 작업보고서 검증 ✅
|
||||||
|
|
||||||
|
### 👤 프로필 페이지
|
||||||
|
- `profile/change-password.html` - 비밀번호 변경 ✅
|
||||||
|
- `profile/my-profile.html` - 내 프로필 ✅
|
||||||
|
|
||||||
|
### 📝 작업보고서 페이지
|
||||||
|
- `work-reports/work-report-create.html` - 작업보고서 생성 ✅
|
||||||
|
- `work-reports/work-report-manage.html` - 작업보고서 관리 ✅
|
||||||
|
|
||||||
|
## 변경사항
|
||||||
|
|
||||||
|
### 로그인 리다이렉트 통일
|
||||||
|
- **이전**: 권한별로 다른 대시보드 (`system.html`, `admin.html`, `user.html` 등)
|
||||||
|
- **현재**: 모든 권한이 `group-leader.html`로 통일 ✅
|
||||||
|
|
||||||
|
### 권한 구조
|
||||||
|
- `system` → `group-leader.html`
|
||||||
|
- `admin` → `group-leader.html`
|
||||||
|
- `leader` → `group-leader.html`
|
||||||
|
- `support` → `group-leader.html`
|
||||||
|
- `user` → `group-leader.html`
|
||||||
|
|
||||||
|
## 주의사항
|
||||||
|
|
||||||
|
- 삭제된 페이지들을 참조하는 링크가 있다면 수정 필요
|
||||||
|
- 모든 사용자가 동일한 대시보드를 사용하므로 권한별 기능 제한은 백엔드에서 처리
|
||||||
|
- 향후 개선 시 권한별 대시보드 분리 가능
|
||||||
39
DELETED_TABLES.md
Normal file
39
DELETED_TABLES.md
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# 삭제된 테이블 목록
|
||||||
|
|
||||||
|
**삭제 날짜**: 2025-11-03
|
||||||
|
**사유**: 사용하지 않는 테이블들 정리
|
||||||
|
|
||||||
|
## 삭제된 테이블들
|
||||||
|
|
||||||
|
1. `activity_logs` - 활동 로그
|
||||||
|
2. `CuttingPlan` - 커팅 계획 (대문자)
|
||||||
|
3. `DailyIssueReports` - 일일 이슈 보고서 (대문자)
|
||||||
|
4. `daily_worker_summary` - 일일 작업자 요약
|
||||||
|
5. `EquipmentList` - 장비 목록 (대문자)
|
||||||
|
6. `FactoryInfo` - 공장 정보 (대문자)
|
||||||
|
7. `PipeSpecs` - 파이프 사양 (대문자)
|
||||||
|
8. `Processes` - 프로세스 (대문자)
|
||||||
|
9. `uploaded_documents` - 업로드된 문서
|
||||||
|
10. `worker_groups` - 작업자 그룹
|
||||||
|
11. `WorkReports` - 작업 보고서 (별도, 새로 만들 예정)
|
||||||
|
12. `work_report_audit_log` - 작업 보고서 감사 로그
|
||||||
|
|
||||||
|
## 현재 사용 중인 테이블들
|
||||||
|
|
||||||
|
- `daily_work_reports` - 일일 작업 보고서 ✅
|
||||||
|
- `workers` - 작업자 정보 ✅
|
||||||
|
- `projects` - 프로젝트 정보 ✅
|
||||||
|
- `tasks` - 작업 정보 ✅
|
||||||
|
- `users` - 사용자 정보 ✅
|
||||||
|
- `work_types` - 작업 유형 ✅
|
||||||
|
- `work_status_types` - 작업 상태 유형 ✅
|
||||||
|
- `error_types` - 에러 유형 ✅
|
||||||
|
- `IssueTypes` - 이슈 유형
|
||||||
|
- `login_logs` - 로그인 로그
|
||||||
|
- `password_change_logs` - 비밀번호 변경 로그
|
||||||
|
|
||||||
|
## 주의사항
|
||||||
|
|
||||||
|
- 삭제된 테이블들을 참조하는 코드가 있다면 제거해야 함
|
||||||
|
- 향후 필요시 백업에서 복구 가능
|
||||||
|
- 데이터베이스 구조가 단순해져서 성능 향상 기대
|
||||||
@@ -19,29 +19,9 @@ const login = async (req, res) => {
|
|||||||
return res.status(result.status || 400).json({ error: result.error });
|
return res.status(result.status || 400).json({ error: result.error });
|
||||||
}
|
}
|
||||||
|
|
||||||
// 로그인 성공 후, 역할에 따라 리디렉션 URL을 결정
|
// 로그인 성공 후, 모든 권한을 그룹장 대시보드로 통일
|
||||||
const user = result.data.user;
|
const user = result.data.user;
|
||||||
let redirectUrl;
|
let redirectUrl = '/pages/dashboard/group-leader.html'; // 모든 사용자를 그룹장 대시보드로 리다이렉트
|
||||||
|
|
||||||
switch (user.role) {
|
|
||||||
case 'system': // 시스템 계정 전용 대시보드
|
|
||||||
redirectUrl = '/pages/dashboard/system.html';
|
|
||||||
break;
|
|
||||||
case 'admin':
|
|
||||||
redirectUrl = '/pages/dashboard/admin.html';
|
|
||||||
break;
|
|
||||||
case 'leader':
|
|
||||||
redirectUrl = '/pages/dashboard/group-leader.html';
|
|
||||||
break;
|
|
||||||
case 'support':
|
|
||||||
// 예시: 지원팀 대시보드가 있다면
|
|
||||||
// redirectUrl = '/pages/dashboard/support.html';
|
|
||||||
// 없다면 일반 사용자 대시보드로
|
|
||||||
redirectUrl = '/pages/dashboard/user.html';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
redirectUrl = '/pages/dashboard/user.html';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 최종 응답에 redirectUrl을 포함하여 전달
|
// 최종 응답에 redirectUrl을 포함하여 전달
|
||||||
res.json({
|
res.json({
|
||||||
|
|||||||
@@ -1,85 +0,0 @@
|
|||||||
// controllers/cuttingPlanController.js
|
|
||||||
const cuttingPlanModel = require('../models/cuttingPlanModel');
|
|
||||||
|
|
||||||
// 1. 생성
|
|
||||||
exports.createCuttingPlan = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const planData = req.body;
|
|
||||||
const lastID = await new Promise((resolve, reject) => {
|
|
||||||
cuttingPlanModel.create(planData, (err, id) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
resolve(id);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
res.json({ success: true, cutting_plan_id: lastID });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 전체 조회
|
|
||||||
exports.getAllCuttingPlans = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const rows = await new Promise((resolve, reject) => {
|
|
||||||
cuttingPlanModel.getAll((err, data) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
resolve(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
res.json(rows);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 단일 조회
|
|
||||||
exports.getCuttingPlanById = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const cutting_plan_id = parseInt(req.params.cutting_plan_id, 10);
|
|
||||||
const row = await new Promise((resolve, reject) => {
|
|
||||||
cuttingPlanModel.getById(cutting_plan_id, (err, data) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
resolve(data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (!row) return res.status(404).json({ error: 'CuttingPlan not found' });
|
|
||||||
res.json(row);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4. 수정
|
|
||||||
exports.updateCuttingPlan = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const cutting_plan_id = parseInt(req.params.cutting_plan_id, 10);
|
|
||||||
const planData = { ...req.body, cutting_plan_id };
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
cuttingPlanModel.update(planData, (err, count) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
resolve(count);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'No changes or not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5. 삭제
|
|
||||||
exports.removeCuttingPlan = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const cutting_plan_id = parseInt(req.params.cutting_plan_id, 10);
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
cuttingPlanModel.remove(cutting_plan_id, (err, count) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
resolve(count);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'CuttingPlan not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// controllers/equipmentListController.js
|
|
||||||
const equipmentListModel = require('../models/equipmentListModel');
|
|
||||||
|
|
||||||
// 1. 등록
|
|
||||||
exports.createEquipment = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const equipmentData = req.body;
|
|
||||||
const id = await new Promise((resolve, reject) => {
|
|
||||||
equipmentListModel.create(equipmentData, (err, insertId) =>
|
|
||||||
err ? reject(err) : resolve(insertId)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
res.json({ success: true, equipment_id: id });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 전체 조회
|
|
||||||
exports.getAllEquipment = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const rows = await new Promise((resolve, reject) => {
|
|
||||||
equipmentListModel.getAll((err, data) =>
|
|
||||||
err ? reject(err) : resolve(data)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
res.json(rows);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 단일 조회
|
|
||||||
exports.getEquipmentById = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.equipment_id, 10);
|
|
||||||
const row = await new Promise((resolve, reject) => {
|
|
||||||
equipmentListModel.getById(id, (err, data) =>
|
|
||||||
err ? reject(err) : resolve(data)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (!row) return res.status(404).json({ error: 'Equipment not found' });
|
|
||||||
res.json(row);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4. 수정
|
|
||||||
exports.updateEquipment = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.equipment_id, 10);
|
|
||||||
const data = { ...req.body, equipment_id: id };
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
equipmentListModel.update(data, (err, affectedRows) =>
|
|
||||||
err ? reject(err) : resolve(affectedRows)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'No changes or not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5. 삭제
|
|
||||||
exports.removeEquipment = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.equipment_id, 10);
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
equipmentListModel.remove(id, (err, affectedRows) =>
|
|
||||||
err ? reject(err) : resolve(affectedRows)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'Equipment not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
// controllers/factoryInfoController.js
|
|
||||||
const factoryInfoModel = require('../models/factoryInfoModel');
|
|
||||||
|
|
||||||
// 1. 공장 정보 생성
|
|
||||||
exports.createFactoryInfo = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const factoryData = req.body;
|
|
||||||
const id = await new Promise((resolve, reject) => {
|
|
||||||
factoryInfoModel.create(factoryData, (err, insertId) =>
|
|
||||||
err ? reject(err) : resolve(insertId)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
res.json({ success: true, factory_id: id });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 전체 공장 정보 조회
|
|
||||||
exports.getAllFactoryInfo = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const rows = await new Promise((resolve, reject) => {
|
|
||||||
factoryInfoModel.getAll((err, data) =>
|
|
||||||
err ? reject(err) : resolve(data)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
res.json(rows);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 단일 조회
|
|
||||||
exports.getFactoryInfoById = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.factory_id, 10);
|
|
||||||
const row = await new Promise((resolve, reject) => {
|
|
||||||
factoryInfoModel.getById(id, (err, data) =>
|
|
||||||
err ? reject(err) : resolve(data)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (!row) return res.status(404).json({ error: 'FactoryInfo not found' });
|
|
||||||
res.json(row);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4. 수정
|
|
||||||
exports.updateFactoryInfo = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.factory_id, 10);
|
|
||||||
const data = { ...req.body, factory_id: id };
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
factoryInfoModel.update(data, (err, affectedRows) =>
|
|
||||||
err ? reject(err) : resolve(affectedRows)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'No changes or not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5. 삭제
|
|
||||||
exports.removeFactoryInfo = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.factory_id, 10);
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
factoryInfoModel.remove(id, (err, affectedRows) =>
|
|
||||||
err ? reject(err) : resolve(affectedRows)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'FactoryInfo not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
// controllers/pingController.js
|
|
||||||
const { getDb } = require('../dbPool');
|
|
||||||
const pingModel = require('../models/pingModel');
|
|
||||||
|
|
||||||
exports.ping = async (req, res) => {
|
|
||||||
const data = pingModel.ping();
|
|
||||||
try {
|
|
||||||
// DB 연결 테스트
|
|
||||||
const db = await getDb();
|
|
||||||
await db.query('SELECT 1');
|
|
||||||
return res.json({
|
|
||||||
success: true,
|
|
||||||
...data,
|
|
||||||
db: 'ok'
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[PING ERROR]', err);
|
|
||||||
return res.status(500).json({
|
|
||||||
success: false,
|
|
||||||
message: 'db error',
|
|
||||||
timestamp: data.timestamp,
|
|
||||||
error: err.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
// ✅ 전체 스펙 목록 (프론트 드롭다운용 label 포함)
|
|
||||||
exports.getAll = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(`
|
|
||||||
SELECT spec_id, material, diameter_in, schedule
|
|
||||||
FROM PipeSpecs
|
|
||||||
ORDER BY material, diameter_in
|
|
||||||
`);
|
|
||||||
|
|
||||||
const result = rows.map(row => ({
|
|
||||||
spec_id: row.spec_id,
|
|
||||||
label: `${row.material} / ${row.diameter_in} / ${row.schedule}`
|
|
||||||
}));
|
|
||||||
|
|
||||||
res.json(result);
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[getAll 오류]', err);
|
|
||||||
res.status(500).json({ error: '파이프 스펙 전체 조회 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ 등록
|
|
||||||
exports.create = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const { material, diameter_in, schedule } = req.body;
|
|
||||||
if (!material || !diameter_in || !schedule) {
|
|
||||||
return res.status(400).json({ error: '모든 항목이 필요합니다.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = await getDb();
|
|
||||||
|
|
||||||
// 중복 체크
|
|
||||||
const [existing] = await db.query(
|
|
||||||
`SELECT * FROM PipeSpecs WHERE material = ? AND diameter_in = ? AND schedule = ?`,
|
|
||||||
[material.trim(), diameter_in.trim(), schedule.trim()]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existing.length > 0) {
|
|
||||||
return res.status(409).json({ error: '이미 등록된 스펙입니다.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
await db.query(
|
|
||||||
`INSERT INTO PipeSpecs (material, diameter_in, schedule) VALUES (?, ?, ?)`,
|
|
||||||
[material.trim(), diameter_in.trim(), schedule.trim()]
|
|
||||||
);
|
|
||||||
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[create 오류]', err);
|
|
||||||
res.status(500).json({ error: '파이프 스펙 등록 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ 삭제
|
|
||||||
exports.remove = async (req, res) => {
|
|
||||||
const { spec_id } = req.params;
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM PipeSpecs WHERE spec_id = ?`,
|
|
||||||
[spec_id]
|
|
||||||
);
|
|
||||||
if (result.affectedRows === 0) {
|
|
||||||
return res.status(404).json({ error: '해당 스펙이 존재하지 않습니다.' });
|
|
||||||
}
|
|
||||||
res.json({ success: true });
|
|
||||||
} catch (err) {
|
|
||||||
console.error('[remove 오류]', err);
|
|
||||||
res.status(500).json({ error: '파이프 스펙 삭제 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ 재질 목록
|
|
||||||
exports.getMaterials = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT DISTINCT material FROM PipeSpecs ORDER BY material`
|
|
||||||
);
|
|
||||||
res.json(rows.map(row => row.material));
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: '재질 목록 조회 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ 직경 목록 (material 기준)
|
|
||||||
exports.getDiameters = async (req, res) => {
|
|
||||||
const { material } = req.query;
|
|
||||||
if (!material) {
|
|
||||||
return res.status(400).json({ error: 'material 파라미터가 필요합니다.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT DISTINCT diameter_in FROM PipeSpecs WHERE material = ? ORDER BY diameter_in`,
|
|
||||||
[material]
|
|
||||||
);
|
|
||||||
res.json(rows.map(row => row.diameter_in));
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: '직경 목록 조회 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// ✅ 스케줄 목록 (material + 직경 기준)
|
|
||||||
exports.getSchedules = async (req, res) => {
|
|
||||||
const { material, diameter_in } = req.query;
|
|
||||||
if (!material || !diameter_in) {
|
|
||||||
return res.status(400).json({ error: 'material과 diameter_in이 필요합니다.' });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT DISTINCT schedule FROM PipeSpecs
|
|
||||||
WHERE material = ? AND diameter_in = ?
|
|
||||||
ORDER BY schedule`,
|
|
||||||
[material, diameter_in]
|
|
||||||
);
|
|
||||||
res.json(rows.map(row => row.schedule));
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: '스케줄 목록 조회 실패' });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
const processModel = require('../models/processModel');
|
|
||||||
const projectModel = require('../models/projectModel');
|
|
||||||
|
|
||||||
// 1. 공정 등록
|
|
||||||
exports.createProcess = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const processData = req.body;
|
|
||||||
|
|
||||||
if (!processData.process_end) {
|
|
||||||
const project = await new Promise((resolve, reject) => {
|
|
||||||
projectModel.getById(processData.project_id, (err, row) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
if (!row) return reject({ status: 404, message: 'Project not found' });
|
|
||||||
resolve(row);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
processData.process_end = project.due_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
const lastID = await new Promise((resolve, reject) => {
|
|
||||||
processModel.create(processData, (err, id) => (err ? reject(err) : resolve(id)));
|
|
||||||
});
|
|
||||||
|
|
||||||
res.json({ success: true, process_id: lastID });
|
|
||||||
} catch (err) {
|
|
||||||
const status = err.status || 500;
|
|
||||||
res.status(status).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 2. 전체 조회
|
|
||||||
exports.getAllProcesses = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const rows = await new Promise((resolve, reject) => {
|
|
||||||
processModel.getAll((err, data) => (err ? reject(err) : resolve(data)));
|
|
||||||
});
|
|
||||||
res.json(rows);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 3. 단일 조회
|
|
||||||
exports.getProcessById = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.process_id, 10);
|
|
||||||
const row = await new Promise((resolve, reject) => {
|
|
||||||
processModel.getById(id, (err, data) => (err ? reject(err) : resolve(data)));
|
|
||||||
});
|
|
||||||
if (!row) return res.status(404).json({ error: 'Process not found' });
|
|
||||||
res.json(row);
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 4. 수정
|
|
||||||
exports.updateProcess = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.process_id, 10);
|
|
||||||
const processData = { ...req.body, process_id: id };
|
|
||||||
|
|
||||||
if (!processData.process_end) {
|
|
||||||
const project = await new Promise((resolve, reject) => {
|
|
||||||
projectModel.getById(processData.project_id, (err, row) => {
|
|
||||||
if (err) return reject(err);
|
|
||||||
if (!row) return reject({ status: 404, message: 'Project not found' });
|
|
||||||
resolve(row);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
processData.process_end = project.due_date;
|
|
||||||
}
|
|
||||||
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
processModel.update(processData, (err, ch) => (err ? reject(err) : resolve(ch)));
|
|
||||||
});
|
|
||||||
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'No changes or not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
const status = err.status || 500;
|
|
||||||
res.status(status).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 5. 삭제
|
|
||||||
exports.removeProcess = async (req, res) => {
|
|
||||||
try {
|
|
||||||
const id = parseInt(req.params.process_id, 10);
|
|
||||||
const changes = await new Promise((resolve, reject) => {
|
|
||||||
processModel.remove(id, (err, ch) => (err ? reject(err) : resolve(ch)));
|
|
||||||
});
|
|
||||||
if (changes === 0) return res.status(404).json({ error: 'Process not found' });
|
|
||||||
res.json({ success: true, changes });
|
|
||||||
} catch (err) {
|
|
||||||
res.status(500).json({ error: err.message || String(err) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -16,6 +16,7 @@ class WorkAnalysisController {
|
|||||||
this.getErrorAnalysis = this.getErrorAnalysis.bind(this);
|
this.getErrorAnalysis = this.getErrorAnalysis.bind(this);
|
||||||
this.getMonthlyComparison = this.getMonthlyComparison.bind(this);
|
this.getMonthlyComparison = this.getMonthlyComparison.bind(this);
|
||||||
this.getWorkerSpecialization = this.getWorkerSpecialization.bind(this);
|
this.getWorkerSpecialization = this.getWorkerSpecialization.bind(this);
|
||||||
|
this.getProjectWorkTypeAnalysis = this.getProjectWorkTypeAnalysis.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 날짜 유효성 검사
|
// 날짜 유효성 검사
|
||||||
@@ -367,6 +368,142 @@ class WorkAnalysisController {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 프로젝트별-작업별 시간 분석 (총시간, 정규시간, 에러시간)
|
||||||
|
async getProjectWorkTypeAnalysis(req, res) {
|
||||||
|
try {
|
||||||
|
const { start, end } = req.query;
|
||||||
|
this.validateDateRange(start, end);
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// 먼저 데이터 존재 여부 확인
|
||||||
|
const testQuery = `
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_count,
|
||||||
|
MIN(report_date) as min_date,
|
||||||
|
MAX(report_date) as max_date,
|
||||||
|
SUM(work_hours) as total_hours
|
||||||
|
FROM daily_work_reports
|
||||||
|
WHERE report_date BETWEEN ? AND ?
|
||||||
|
`;
|
||||||
|
|
||||||
|
const testResults = await db.query(testQuery, [start, end]);
|
||||||
|
console.log('📊 데이터 확인:', testResults[0]);
|
||||||
|
|
||||||
|
// 프로젝트별-작업별 시간 분석 쿼리 (간단한 버전으로 테스트)
|
||||||
|
const query = `
|
||||||
|
SELECT
|
||||||
|
COALESCE(p.project_id, 0) as project_id,
|
||||||
|
COALESCE(p.project_name, 'Unknown Project') as project_name,
|
||||||
|
COALESCE(p.job_no, 'N/A') as job_no,
|
||||||
|
dwr.work_type_id,
|
||||||
|
CONCAT('Work Type ', dwr.work_type_id) as work_type_name,
|
||||||
|
|
||||||
|
-- 총 시간
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
|
||||||
|
-- 정규 시간 (work_status_id = 1)
|
||||||
|
SUM(CASE WHEN dwr.work_status_id = 1 THEN dwr.work_hours ELSE 0 END) as regular_hours,
|
||||||
|
|
||||||
|
-- 에러 시간 (work_status_id = 2)
|
||||||
|
SUM(CASE WHEN dwr.work_status_id = 2 THEN dwr.work_hours ELSE 0 END) as error_hours,
|
||||||
|
|
||||||
|
-- 작업 건수
|
||||||
|
COUNT(*) as total_reports,
|
||||||
|
COUNT(CASE WHEN dwr.work_status_id = 1 THEN 1 END) as regular_reports,
|
||||||
|
COUNT(CASE WHEN dwr.work_status_id = 2 THEN 1 END) as error_reports,
|
||||||
|
|
||||||
|
-- 에러율 계산
|
||||||
|
ROUND(
|
||||||
|
(SUM(CASE WHEN dwr.work_status_id = 2 THEN dwr.work_hours ELSE 0 END) /
|
||||||
|
SUM(dwr.work_hours)) * 100, 2
|
||||||
|
) as error_rate_percent
|
||||||
|
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
|
WHERE dwr.report_date BETWEEN ? AND ?
|
||||||
|
GROUP BY p.project_id, p.project_name, p.job_no, dwr.work_type_id
|
||||||
|
ORDER BY p.project_name, dwr.work_type_id
|
||||||
|
`;
|
||||||
|
|
||||||
|
const results = await db.query(query, [start, end]);
|
||||||
|
|
||||||
|
// 데이터를 프로젝트별로 그룹화
|
||||||
|
const groupedData = {};
|
||||||
|
|
||||||
|
results.forEach(row => {
|
||||||
|
const projectKey = `${row.project_id}_${row.project_name}`;
|
||||||
|
|
||||||
|
if (!groupedData[projectKey]) {
|
||||||
|
groupedData[projectKey] = {
|
||||||
|
project_id: row.project_id,
|
||||||
|
project_name: row.project_name,
|
||||||
|
job_no: row.job_no,
|
||||||
|
total_project_hours: 0,
|
||||||
|
total_regular_hours: 0,
|
||||||
|
total_error_hours: 0,
|
||||||
|
work_types: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 프로젝트 총계 누적
|
||||||
|
groupedData[projectKey].total_project_hours += parseFloat(row.total_hours);
|
||||||
|
groupedData[projectKey].total_regular_hours += parseFloat(row.regular_hours);
|
||||||
|
groupedData[projectKey].total_error_hours += parseFloat(row.error_hours);
|
||||||
|
|
||||||
|
// 작업 유형별 데이터 추가
|
||||||
|
groupedData[projectKey].work_types.push({
|
||||||
|
work_type_id: row.work_type_id,
|
||||||
|
work_type_name: row.work_type_name,
|
||||||
|
total_hours: parseFloat(row.total_hours),
|
||||||
|
regular_hours: parseFloat(row.regular_hours),
|
||||||
|
error_hours: parseFloat(row.error_hours),
|
||||||
|
total_reports: row.total_reports,
|
||||||
|
regular_reports: row.regular_reports,
|
||||||
|
error_reports: row.error_reports,
|
||||||
|
error_rate_percent: parseFloat(row.error_rate_percent) || 0
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 프로젝트별 에러율 계산
|
||||||
|
Object.values(groupedData).forEach(project => {
|
||||||
|
project.project_error_rate = project.total_project_hours > 0
|
||||||
|
? Math.round((project.total_error_hours / project.total_project_hours) * 100 * 100) / 100
|
||||||
|
: 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 전체 요약 통계
|
||||||
|
const totalStats = {
|
||||||
|
total_projects: Object.keys(groupedData).length,
|
||||||
|
total_work_types: new Set(results.map(r => r.work_type_id)).size,
|
||||||
|
grand_total_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_project_hours, 0),
|
||||||
|
grand_regular_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_regular_hours, 0),
|
||||||
|
grand_error_hours: Object.values(groupedData).reduce((sum, p) => sum + p.total_error_hours, 0)
|
||||||
|
};
|
||||||
|
|
||||||
|
totalStats.grand_error_rate = totalStats.grand_total_hours > 0
|
||||||
|
? Math.round((totalStats.grand_error_hours / totalStats.grand_total_hours) * 100 * 100) / 100
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
summary: totalStats,
|
||||||
|
projects: Object.values(groupedData),
|
||||||
|
period: { start, end }
|
||||||
|
},
|
||||||
|
message: '프로젝트별-작업별 시간 분석 완료'
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('프로젝트별-작업별 시간 분석 오류:', error);
|
||||||
|
res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = new WorkAnalysisController();
|
module.exports = new WorkAnalysisController();
|
||||||
381
api.hyungi.net/controllers/workReportAnalysisController.js
Normal file
381
api.hyungi.net/controllers/workReportAnalysisController.js
Normal file
@@ -0,0 +1,381 @@
|
|||||||
|
// controllers/workReportAnalysisController.js - 데일리 워크 레포트 분석 전용 컨트롤러
|
||||||
|
const dailyWorkReportModel = require('../models/dailyWorkReportModel');
|
||||||
|
const { getDb } = require('../dbPool');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 📋 분석용 필터 데이터 조회 (프로젝트, 작업자, 작업유형 목록)
|
||||||
|
*/
|
||||||
|
const getAnalysisFilters = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// 프로젝트 목록
|
||||||
|
const [projects] = await db.query(`
|
||||||
|
SELECT DISTINCT p.project_id, p.project_name
|
||||||
|
FROM projects p
|
||||||
|
INNER JOIN daily_work_reports dwr ON p.project_id = dwr.project_id
|
||||||
|
ORDER BY p.project_name
|
||||||
|
`);
|
||||||
|
|
||||||
|
// 작업자 목록
|
||||||
|
const [workers] = await db.query(`
|
||||||
|
SELECT DISTINCT w.worker_id, w.worker_name
|
||||||
|
FROM workers w
|
||||||
|
INNER JOIN daily_work_reports dwr ON w.worker_id = dwr.worker_id
|
||||||
|
ORDER BY w.worker_name
|
||||||
|
`);
|
||||||
|
|
||||||
|
// 작업 유형 목록
|
||||||
|
const [workTypes] = await db.query(`
|
||||||
|
SELECT DISTINCT wt.id as work_type_id, wt.name as work_type_name
|
||||||
|
FROM work_types wt
|
||||||
|
INNER JOIN daily_work_reports dwr ON wt.id = dwr.work_type_id
|
||||||
|
ORDER BY wt.name
|
||||||
|
`);
|
||||||
|
|
||||||
|
// 날짜 범위 (최초/최신 데이터)
|
||||||
|
const [dateRange] = await db.query(`
|
||||||
|
SELECT
|
||||||
|
MIN(report_date) as min_date,
|
||||||
|
MAX(report_date) as max_date
|
||||||
|
FROM daily_work_reports
|
||||||
|
`);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
projects,
|
||||||
|
workers,
|
||||||
|
workTypes,
|
||||||
|
dateRange: dateRange[0]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('필터 데이터 조회 오류:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: '필터 데이터 조회 중 오류가 발생했습니다.',
|
||||||
|
detail: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 📊 기간별 작업 분석 데이터 조회
|
||||||
|
*/
|
||||||
|
const getAnalyticsByPeriod = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { start_date, end_date, project_id, worker_id } = req.query;
|
||||||
|
|
||||||
|
if (!start_date || !end_date) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'start_date와 end_date가 필요합니다.',
|
||||||
|
example: 'start_date=2025-08-01&end_date=2025-08-31'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
// 기본 조건
|
||||||
|
let whereConditions = ['dwr.report_date BETWEEN ? AND ?'];
|
||||||
|
let queryParams = [start_date, end_date];
|
||||||
|
|
||||||
|
// 프로젝트 필터
|
||||||
|
if (project_id) {
|
||||||
|
whereConditions.push('dwr.project_id = ?');
|
||||||
|
queryParams.push(project_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 작업자 필터
|
||||||
|
if (worker_id) {
|
||||||
|
whereConditions.push('dwr.worker_id = ?');
|
||||||
|
queryParams.push(worker_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const whereClause = whereConditions.join(' AND ');
|
||||||
|
|
||||||
|
// 1. 전체 요약 통계 (에러 분석 포함)
|
||||||
|
const overallSql = `
|
||||||
|
SELECT
|
||||||
|
COUNT(*) as total_entries,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
COUNT(DISTINCT dwr.worker_id) as unique_workers,
|
||||||
|
COUNT(DISTINCT dwr.project_id) as unique_projects,
|
||||||
|
COUNT(DISTINCT dwr.report_date) as working_days,
|
||||||
|
AVG(dwr.work_hours) as avg_hours_per_entry,
|
||||||
|
COUNT(DISTINCT dwr.created_by) as contributors,
|
||||||
|
COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) as error_entries,
|
||||||
|
ROUND((COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) / COUNT(*)) * 100, 2) as error_rate
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
WHERE ${whereClause}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [overallStats] = await db.query(overallSql, queryParams);
|
||||||
|
|
||||||
|
// 2. 일별 통계
|
||||||
|
const dailyStatsSql = `
|
||||||
|
SELECT
|
||||||
|
dwr.report_date,
|
||||||
|
SUM(dwr.work_hours) as daily_hours,
|
||||||
|
COUNT(*) as daily_entries,
|
||||||
|
COUNT(DISTINCT dwr.worker_id) as daily_workers
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY dwr.report_date
|
||||||
|
ORDER BY dwr.report_date ASC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [dailyStats] = await db.query(dailyStatsSql, queryParams);
|
||||||
|
|
||||||
|
// 2.5. 일별 에러 발생 통계
|
||||||
|
const dailyErrorStatsSql = `
|
||||||
|
SELECT
|
||||||
|
dwr.report_date,
|
||||||
|
COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) as daily_errors,
|
||||||
|
COUNT(*) as daily_total,
|
||||||
|
ROUND((COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) / COUNT(*)) * 100, 2) as daily_error_rate
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY dwr.report_date
|
||||||
|
ORDER BY dwr.report_date ASC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [dailyErrorStats] = await db.query(dailyErrorStatsSql, queryParams);
|
||||||
|
|
||||||
|
// 3. 에러 유형별 분석 (간단한 방식으로 수정)
|
||||||
|
const errorAnalysisSql = `
|
||||||
|
SELECT
|
||||||
|
et.id as error_type_id,
|
||||||
|
et.name as error_type_name,
|
||||||
|
COUNT(*) as error_count,
|
||||||
|
SUM(dwr.work_hours) as error_hours,
|
||||||
|
ROUND((COUNT(*) / (SELECT COUNT(*) FROM daily_work_reports WHERE error_type_id IS NOT NULL)) * 100, 2) as error_percentage
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
||||||
|
WHERE ${whereClause} AND dwr.error_type_id IS NOT NULL
|
||||||
|
GROUP BY et.id, et.name
|
||||||
|
ORDER BY error_count DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [errorAnalysis] = await db.query(errorAnalysisSql, queryParams);
|
||||||
|
|
||||||
|
// 4. 작업 유형별 분석
|
||||||
|
const workTypeAnalysisSql = `
|
||||||
|
SELECT
|
||||||
|
wt.id as work_type_id,
|
||||||
|
wt.name as work_type_name,
|
||||||
|
COUNT(*) as work_count,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
AVG(dwr.work_hours) as avg_hours,
|
||||||
|
COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) as error_count,
|
||||||
|
ROUND((COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) / COUNT(*)) * 100, 2) as error_rate
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY wt.id, wt.name
|
||||||
|
ORDER BY total_hours DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [workTypeAnalysis] = await db.query(workTypeAnalysisSql, queryParams);
|
||||||
|
|
||||||
|
// 5. 작업자별 성과 분석
|
||||||
|
const workerAnalysisSql = `
|
||||||
|
SELECT
|
||||||
|
w.worker_id,
|
||||||
|
w.worker_name,
|
||||||
|
COUNT(*) as total_entries,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
AVG(dwr.work_hours) as avg_hours_per_entry,
|
||||||
|
COUNT(DISTINCT dwr.project_id) as projects_worked,
|
||||||
|
COUNT(DISTINCT dwr.report_date) as working_days,
|
||||||
|
COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) as error_count,
|
||||||
|
ROUND((COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) / COUNT(*)) * 100, 2) as error_rate
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY w.worker_id, w.worker_name
|
||||||
|
ORDER BY total_hours DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [workerAnalysis] = await db.query(workerAnalysisSql, queryParams);
|
||||||
|
|
||||||
|
// 6. 프로젝트별 분석
|
||||||
|
const projectAnalysisSql = `
|
||||||
|
SELECT
|
||||||
|
p.project_id,
|
||||||
|
p.project_name,
|
||||||
|
COUNT(*) as total_entries,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
COUNT(DISTINCT dwr.worker_id) as workers_count,
|
||||||
|
COUNT(DISTINCT dwr.report_date) as working_days,
|
||||||
|
AVG(dwr.work_hours) as avg_hours_per_entry,
|
||||||
|
COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) as error_count,
|
||||||
|
ROUND((COUNT(CASE WHEN dwr.error_type_id IS NOT NULL THEN 1 END) / COUNT(*)) * 100, 2) as error_rate
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY p.project_id, p.project_name
|
||||||
|
ORDER BY total_hours DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [projectAnalysis] = await db.query(projectAnalysisSql, queryParams);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
summary: overallStats[0],
|
||||||
|
dailyStats,
|
||||||
|
dailyErrorStats,
|
||||||
|
errorAnalysis,
|
||||||
|
workTypeAnalysis,
|
||||||
|
workerAnalysis,
|
||||||
|
projectAnalysis,
|
||||||
|
period: { start_date, end_date },
|
||||||
|
filters: { project_id, worker_id }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('기간별 분석 데이터 조회 오류:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: '기간별 분석 데이터 조회 중 오류가 발생했습니다.',
|
||||||
|
detail: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 📈 프로젝트별 상세 분석
|
||||||
|
*/
|
||||||
|
const getProjectAnalysis = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { start_date, end_date, project_id } = req.query;
|
||||||
|
|
||||||
|
if (!start_date || !end_date) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'start_date와 end_date가 필요합니다.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
let whereConditions = ['dwr.report_date BETWEEN ? AND ?'];
|
||||||
|
let queryParams = [start_date, end_date];
|
||||||
|
|
||||||
|
if (project_id) {
|
||||||
|
whereConditions.push('dwr.project_id = ?');
|
||||||
|
queryParams.push(project_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const whereClause = whereConditions.join(' AND ');
|
||||||
|
|
||||||
|
// 프로젝트별 통계
|
||||||
|
const projectStatsSql = `
|
||||||
|
SELECT
|
||||||
|
dwr.project_id,
|
||||||
|
p.project_name,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
COUNT(*) as total_entries,
|
||||||
|
COUNT(DISTINCT dwr.worker_id) as workers_count,
|
||||||
|
COUNT(DISTINCT dwr.report_date) as working_days,
|
||||||
|
AVG(dwr.work_hours) as avg_hours_per_entry
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY dwr.project_id
|
||||||
|
ORDER BY total_hours DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [projectStats] = await db.query(projectStatsSql, queryParams);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
projectStats,
|
||||||
|
period: { start_date, end_date }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('프로젝트별 분석 데이터 조회 오류:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: '프로젝트별 분석 데이터 조회 중 오류가 발생했습니다.',
|
||||||
|
detail: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 👤 작업자별 상세 분석
|
||||||
|
*/
|
||||||
|
const getWorkerAnalysis = async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { start_date, end_date, worker_id } = req.query;
|
||||||
|
|
||||||
|
if (!start_date || !end_date) {
|
||||||
|
return res.status(400).json({
|
||||||
|
success: false,
|
||||||
|
error: 'start_date와 end_date가 필요합니다.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = await getDb();
|
||||||
|
|
||||||
|
let whereConditions = ['dwr.report_date BETWEEN ? AND ?'];
|
||||||
|
let queryParams = [start_date, end_date];
|
||||||
|
|
||||||
|
if (worker_id) {
|
||||||
|
whereConditions.push('dwr.worker_id = ?');
|
||||||
|
queryParams.push(worker_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const whereClause = whereConditions.join(' AND ');
|
||||||
|
|
||||||
|
// 작업자별 통계
|
||||||
|
const workerStatsSql = `
|
||||||
|
SELECT
|
||||||
|
dwr.worker_id,
|
||||||
|
w.worker_name,
|
||||||
|
SUM(dwr.work_hours) as total_hours,
|
||||||
|
COUNT(*) as total_entries,
|
||||||
|
COUNT(DISTINCT dwr.project_id) as projects_worked,
|
||||||
|
COUNT(DISTINCT dwr.report_date) as working_days,
|
||||||
|
AVG(dwr.work_hours) as avg_hours_per_entry
|
||||||
|
FROM daily_work_reports dwr
|
||||||
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
|
WHERE ${whereClause}
|
||||||
|
GROUP BY dwr.worker_id
|
||||||
|
ORDER BY total_hours DESC
|
||||||
|
`;
|
||||||
|
|
||||||
|
const [workerStats] = await db.query(workerStatsSql, queryParams);
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
success: true,
|
||||||
|
data: {
|
||||||
|
workerStats,
|
||||||
|
period: { start_date, end_date }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('작업자별 분석 데이터 조회 오류:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
success: false,
|
||||||
|
error: '작업자별 분석 데이터 조회 중 오류가 발생했습니다.',
|
||||||
|
detail: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getAnalysisFilters,
|
||||||
|
getAnalyticsByPeriod,
|
||||||
|
getProjectAnalysis,
|
||||||
|
getWorkerAnalysis
|
||||||
|
};
|
||||||
774
api.hyungi.net/daily_work_reports_backup_20250902_081944.sql
Normal file
774
api.hyungi.net/daily_work_reports_backup_20250902_081944.sql
Normal file
@@ -0,0 +1,774 @@
|
|||||||
|
-- MariaDB dump 10.19 Distrib 10.9.8-MariaDB, for debian-linux-gnu (aarch64)
|
||||||
|
--
|
||||||
|
-- Host: localhost Database: hyungi_dev
|
||||||
|
-- ------------------------------------------------------
|
||||||
|
-- Server version 10.9.8-MariaDB-1:10.9.8+maria~ubu2204
|
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||||
|
/*!40101 SET NAMES utf8mb4 */;
|
||||||
|
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||||
|
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||||
|
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||||
|
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Table structure for table `daily_work_reports`
|
||||||
|
--
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `daily_work_reports`;
|
||||||
|
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||||
|
/*!40101 SET character_set_client = utf8 */;
|
||||||
|
CREATE TABLE `daily_work_reports` (
|
||||||
|
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||||
|
`report_date` date NOT NULL COMMENT '작업 날짜',
|
||||||
|
`worker_id` int(11) NOT NULL COMMENT '작업자 ID',
|
||||||
|
`project_id` int(11) NOT NULL COMMENT '프로젝트 ID',
|
||||||
|
`work_type_id` int(11) NOT NULL COMMENT '작업 유형 ID',
|
||||||
|
`work_status_id` int(11) DEFAULT 1 COMMENT '업무 상태 ID (1:정규, 2:에러)',
|
||||||
|
`error_type_id` int(11) DEFAULT NULL COMMENT '에러 유형 ID (에러일 때만)',
|
||||||
|
`work_hours` decimal(4,2) NOT NULL COMMENT '작업 시간',
|
||||||
|
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||||
|
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
|
||||||
|
`created_by` int(11) NOT NULL DEFAULT 1 COMMENT '작성자 user_id',
|
||||||
|
`updated_by` int(11) DEFAULT NULL COMMENT '수정자 user_id',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_report_date` (`report_date`),
|
||||||
|
KEY `idx_worker_date` (`worker_id`,`report_date`),
|
||||||
|
KEY `idx_project_date` (`project_id`,`report_date`),
|
||||||
|
KEY `idx_work_type` (`work_type_id`),
|
||||||
|
KEY `idx_work_status` (`work_status_id`),
|
||||||
|
KEY `idx_error_type` (`error_type_id`),
|
||||||
|
KEY `idx_created_by` (`created_by`),
|
||||||
|
KEY `idx_date_worker_creator` (`report_date`,`worker_id`,`created_by`)
|
||||||
|
) ENGINE=InnoDB AUTO_INCREMENT=741 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Dumping data for table `daily_work_reports`
|
||||||
|
--
|
||||||
|
|
||||||
|
LOCK TABLES `daily_work_reports` WRITE;
|
||||||
|
/*!40000 ALTER TABLE `daily_work_reports` DISABLE KEYS */;
|
||||||
|
INSERT INTO `daily_work_reports` VALUES
|
||||||
|
(14,'2025-06-02',1,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(15,'2025-06-02',3,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(16,'2025-06-02',4,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(17,'2025-06-02',6,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(18,'2025-06-02',7,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(19,'2025-06-02',9,4,3,1,NULL,8.00,'2025-06-16 05:10:23','2025-06-16 05:10:23',1,NULL),
|
||||||
|
(20,'2025-06-02',2,3,2,1,NULL,8.00,'2025-06-16 05:10:47','2025-06-16 05:10:47',1,NULL),
|
||||||
|
(21,'2025-06-04',1,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(22,'2025-06-04',3,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(23,'2025-06-04',5,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(24,'2025-06-04',7,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(25,'2025-06-04',9,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(26,'2025-06-04',10,4,3,1,NULL,8.00,'2025-06-16 05:11:37','2025-06-16 05:11:37',1,NULL),
|
||||||
|
(27,'2025-06-04',2,3,2,1,NULL,8.00,'2025-06-16 05:12:07','2025-06-16 05:12:07',1,NULL),
|
||||||
|
(28,'2025-06-04',6,3,2,1,NULL,8.00,'2025-06-16 05:12:07','2025-06-16 05:12:07',1,NULL),
|
||||||
|
(29,'2025-06-04',8,3,2,1,NULL,8.00,'2025-06-16 05:12:07','2025-06-16 05:12:07',1,NULL),
|
||||||
|
(30,'2025-06-05',1,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(31,'2025-06-05',3,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(32,'2025-06-05',4,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(33,'2025-06-05',7,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(34,'2025-06-05',10,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(35,'2025-06-05',9,4,3,2,1,8.00,'2025-06-16 05:12:57','2025-06-16 05:12:57',1,NULL),
|
||||||
|
(36,'2025-06-05',2,3,2,1,NULL,8.00,'2025-06-16 05:13:56','2025-06-16 05:13:56',1,NULL),
|
||||||
|
(37,'2025-06-05',5,3,2,1,NULL,8.00,'2025-06-16 05:13:56','2025-06-16 05:13:56',1,NULL),
|
||||||
|
(38,'2025-06-05',6,3,2,1,NULL,8.00,'2025-06-16 05:13:56','2025-06-16 05:13:56',1,NULL),
|
||||||
|
(39,'2025-06-05',8,3,2,1,NULL,8.00,'2025-06-16 05:13:56','2025-06-16 05:13:56',1,NULL),
|
||||||
|
(40,'2025-06-16',5,3,2,1,NULL,8.00,'2025-06-16 06:12:01','2025-06-16 06:12:01',5,NULL),
|
||||||
|
(43,'2025-06-16',2,3,2,1,NULL,8.00,'2025-06-16 06:12:01','2025-06-16 06:12:01',5,NULL),
|
||||||
|
(44,'2025-06-16',6,3,2,2,4,4.00,'2025-06-16 06:13:02','2025-06-16 06:13:02',5,NULL),
|
||||||
|
(45,'2025-06-16',6,3,2,1,NULL,4.00,'2025-06-16 06:13:50','2025-06-16 06:13:50',5,NULL),
|
||||||
|
(46,'2025-06-16',8,3,2,2,4,4.00,'2025-06-16 06:15:22','2025-06-16 06:15:22',5,NULL),
|
||||||
|
(47,'2025-06-16',8,3,2,1,NULL,4.00,'2025-06-16 06:15:22','2025-06-16 06:15:22',5,NULL),
|
||||||
|
(48,'2025-06-16',4,4,3,2,1,8.00,'2025-06-16 06:46:44','2025-06-16 06:46:44',3,NULL),
|
||||||
|
(50,'2025-06-16',1,4,3,2,1,8.00,'2025-06-16 06:46:44','2025-06-16 06:46:44',3,NULL),
|
||||||
|
(51,'2025-06-16',9,4,3,1,NULL,8.00,'2025-06-16 06:48:29','2025-06-16 06:48:29',3,NULL),
|
||||||
|
(52,'2025-06-16',10,4,3,1,NULL,6.00,'2025-06-16 06:50:09','2025-06-16 06:50:09',6,NULL),
|
||||||
|
(53,'2025-06-16',10,4,3,2,1,2.00,'2025-06-16 06:50:09','2025-06-16 06:50:09',6,NULL),
|
||||||
|
(54,'2025-06-16',3,4,3,1,NULL,6.00,'2025-06-16 06:50:09','2025-06-16 06:50:09',6,NULL),
|
||||||
|
(55,'2025-06-16',3,4,3,2,1,2.00,'2025-06-16 06:50:09','2025-06-16 06:50:09',6,NULL),
|
||||||
|
(56,'2025-06-17',2,3,2,1,NULL,8.00,'2025-06-17 08:23:41','2025-06-17 08:23:41',5,NULL),
|
||||||
|
(57,'2025-06-17',2,3,2,1,NULL,2.00,'2025-06-17 08:23:41','2025-06-17 08:23:41',5,NULL),
|
||||||
|
(58,'2025-06-17',5,3,2,1,NULL,8.00,'2025-06-17 08:23:41','2025-06-17 08:23:41',5,NULL),
|
||||||
|
(59,'2025-06-17',5,3,2,1,NULL,2.00,'2025-06-17 08:23:41','2025-06-17 08:23:41',5,NULL),
|
||||||
|
(60,'2025-06-17',6,3,2,1,NULL,8.00,'2025-06-17 08:24:33','2025-06-17 08:24:33',5,NULL),
|
||||||
|
(61,'2025-06-17',6,3,2,2,4,2.00,'2025-06-17 08:24:33','2025-06-17 08:24:33',5,NULL),
|
||||||
|
(62,'2025-06-17',8,3,2,1,NULL,8.00,'2025-06-17 08:24:33','2025-06-17 08:24:33',5,NULL),
|
||||||
|
(63,'2025-06-17',8,3,2,2,4,2.00,'2025-06-17 08:24:33','2025-06-17 08:24:33',5,NULL),
|
||||||
|
(65,'2025-06-17',9,4,3,2,1,4.00,'2025-06-17 08:25:24','2025-06-17 08:25:24',3,NULL),
|
||||||
|
(66,'2025-06-17',1,4,3,2,1,4.00,'2025-06-17 08:27:06','2025-06-17 08:27:06',3,NULL),
|
||||||
|
(67,'2025-06-17',4,4,3,2,1,4.00,'2025-06-17 08:27:06','2025-06-17 08:27:06',3,NULL),
|
||||||
|
(68,'2025-06-17',1,4,3,1,NULL,4.00,'2025-06-17 08:31:06','2025-06-17 08:31:06',3,NULL),
|
||||||
|
(69,'2025-06-17',9,4,3,1,NULL,4.00,'2025-06-17 08:31:06','2025-06-17 08:31:06',3,NULL),
|
||||||
|
(70,'2025-06-17',4,4,3,1,NULL,4.00,'2025-06-17 08:31:06','2025-06-17 08:31:06',3,NULL),
|
||||||
|
(71,'2025-06-17',9,4,3,1,NULL,2.00,'2025-06-17 08:33:06','2025-06-17 08:33:06',3,NULL),
|
||||||
|
(72,'2025-06-17',4,4,3,1,NULL,2.00,'2025-06-17 08:33:06','2025-06-17 08:33:06',3,NULL),
|
||||||
|
(73,'2025-06-17',1,4,3,1,NULL,2.00,'2025-06-17 08:33:06','2025-06-17 08:33:06',3,NULL),
|
||||||
|
(74,'2025-06-17',10,4,3,1,NULL,8.00,'2025-06-17 08:34:11','2025-06-17 08:34:11',6,NULL),
|
||||||
|
(75,'2025-06-17',10,4,3,2,1,2.00,'2025-06-17 08:34:11','2025-06-17 08:34:11',6,NULL),
|
||||||
|
(76,'2025-06-17',3,4,3,1,NULL,8.00,'2025-06-17 08:34:11','2025-06-17 08:34:11',6,NULL),
|
||||||
|
(77,'2025-06-17',3,4,3,2,1,2.00,'2025-06-17 08:34:11','2025-06-17 08:34:11',6,NULL),
|
||||||
|
(78,'2025-06-18',6,3,2,1,NULL,8.00,'2025-06-18 08:40:27','2025-06-18 08:40:27',5,NULL),
|
||||||
|
(79,'2025-06-18',2,3,2,1,NULL,8.00,'2025-06-18 08:40:27','2025-06-18 08:40:27',5,NULL),
|
||||||
|
(80,'2025-06-18',8,3,2,1,NULL,8.00,'2025-06-18 08:40:27','2025-06-18 08:40:27',5,NULL),
|
||||||
|
(81,'2025-06-18',2,3,2,1,NULL,2.00,'2025-06-18 08:41:02','2025-06-18 08:41:02',5,NULL),
|
||||||
|
(82,'2025-06-18',6,3,2,1,NULL,2.00,'2025-06-18 08:41:03','2025-06-18 08:41:03',5,NULL),
|
||||||
|
(83,'2025-06-18',8,3,2,1,NULL,2.00,'2025-06-18 08:41:03','2025-06-18 08:41:03',5,NULL),
|
||||||
|
(84,'2025-06-18',5,4,3,1,NULL,8.00,'2025-06-18 08:41:45','2025-06-18 08:41:45',5,NULL),
|
||||||
|
(85,'2025-06-18',5,4,3,1,NULL,2.00,'2025-06-18 08:41:45','2025-06-18 08:41:45',5,NULL),
|
||||||
|
(86,'2025-06-18',10,4,3,1,NULL,9.00,'2025-06-18 08:47:55','2025-06-18 08:47:55',6,NULL),
|
||||||
|
(87,'2025-06-18',10,4,3,2,1,1.00,'2025-06-18 08:47:55','2025-06-18 08:47:55',6,NULL),
|
||||||
|
(88,'2025-06-18',3,4,3,1,NULL,9.00,'2025-06-18 08:47:55','2025-06-18 08:47:55',6,NULL),
|
||||||
|
(89,'2025-06-18',3,4,3,2,1,1.00,'2025-06-18 08:47:55','2025-06-18 08:47:55',6,NULL),
|
||||||
|
(90,'2025-06-18',4,4,3,2,1,4.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(91,'2025-06-18',4,4,3,1,NULL,6.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(92,'2025-06-18',9,4,3,2,1,4.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(93,'2025-06-18',9,4,3,1,NULL,6.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(94,'2025-06-18',1,4,3,2,1,4.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(95,'2025-06-18',1,4,3,1,NULL,6.00,'2025-06-18 08:50:19','2025-06-18 08:50:19',3,NULL),
|
||||||
|
(96,'2025-06-18',7,4,3,2,1,4.00,'2025-06-18 09:00:17','2025-06-18 09:00:17',3,NULL),
|
||||||
|
(97,'2025-06-18',7,4,3,1,NULL,6.00,'2025-06-18 09:00:17','2025-06-18 09:00:17',3,NULL),
|
||||||
|
(98,'2025-06-19',8,3,2,1,NULL,8.00,'2025-06-19 06:37:59','2025-06-19 06:37:59',5,NULL),
|
||||||
|
(99,'2025-06-19',2,3,2,1,NULL,8.00,'2025-06-19 06:37:59','2025-06-19 06:37:59',5,NULL),
|
||||||
|
(100,'2025-06-19',10,4,3,1,NULL,8.00,'2025-06-19 06:59:36','2025-06-19 06:59:36',6,NULL),
|
||||||
|
(101,'2025-06-19',3,4,3,1,NULL,8.00,'2025-06-19 06:59:36','2025-06-19 06:59:36',6,NULL),
|
||||||
|
(102,'2025-06-19',5,4,3,1,NULL,8.00,'2025-06-19 06:59:36','2025-06-19 06:59:36',6,NULL),
|
||||||
|
(103,'2025-06-19',9,4,3,1,NULL,6.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(104,'2025-06-19',9,4,3,2,1,2.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(105,'2025-06-19',4,4,3,1,NULL,6.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(106,'2025-06-19',4,4,3,2,1,2.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(107,'2025-06-19',1,4,3,1,NULL,6.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(108,'2025-06-19',1,4,3,2,1,2.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(109,'2025-06-19',7,4,3,1,NULL,6.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(110,'2025-06-19',7,4,3,2,1,2.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(111,'2025-06-19',6,4,3,1,NULL,6.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(112,'2025-06-19',6,4,3,2,1,2.00,'2025-06-19 07:01:02','2025-06-19 07:01:02',3,NULL),
|
||||||
|
(113,'2025-06-20',9,4,3,2,1,2.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(114,'2025-06-20',9,4,3,1,NULL,6.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(115,'2025-06-20',4,4,3,2,1,2.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(116,'2025-06-20',4,4,3,1,NULL,6.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(117,'2025-06-20',7,4,3,2,1,2.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(118,'2025-06-20',7,4,3,1,NULL,6.00,'2025-06-20 06:44:01','2025-06-20 06:44:01',3,NULL),
|
||||||
|
(119,'2025-06-20',6,4,3,2,1,2.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(120,'2025-06-20',6,4,3,1,NULL,6.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(121,'2025-06-20',1,4,3,2,1,2.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(122,'2025-06-20',1,4,3,1,NULL,6.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(123,'2025-06-20',5,4,3,2,1,2.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(124,'2025-06-20',5,4,3,1,NULL,6.00,'2025-06-20 06:44:02','2025-06-20 06:44:02',3,NULL),
|
||||||
|
(125,'2025-06-20',10,4,3,1,NULL,8.00,'2025-06-20 06:45:30','2025-06-20 06:45:30',6,NULL),
|
||||||
|
(126,'2025-06-20',3,4,3,1,NULL,8.00,'2025-06-20 06:45:31','2025-06-20 06:45:31',6,NULL),
|
||||||
|
(127,'2025-06-23',10,4,3,1,NULL,8.00,'2025-06-23 06:42:58','2025-06-23 06:42:58',6,NULL),
|
||||||
|
(128,'2025-06-23',3,4,3,1,NULL,8.00,'2025-06-23 06:42:58','2025-06-23 06:42:58',6,NULL),
|
||||||
|
(129,'2025-06-23',5,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(130,'2025-06-23',5,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(131,'2025-06-23',1,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(132,'2025-06-23',1,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(133,'2025-06-23',9,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(134,'2025-06-23',9,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(135,'2025-06-23',4,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(136,'2025-06-23',4,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(137,'2025-06-23',7,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(138,'2025-06-23',7,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(139,'2025-06-23',6,4,3,2,1,2.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(140,'2025-06-23',6,4,3,1,NULL,6.00,'2025-06-23 06:51:28','2025-06-23 06:51:28',3,NULL),
|
||||||
|
(141,'2025-06-24',10,4,3,1,NULL,12.00,'2025-06-24 11:10:32','2025-06-24 11:10:32',6,NULL),
|
||||||
|
(142,'2025-06-24',3,4,3,1,NULL,12.00,'2025-06-24 11:10:32','2025-06-24 11:10:32',6,NULL),
|
||||||
|
(143,'2025-06-24',9,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(144,'2025-06-24',9,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(145,'2025-06-24',5,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(146,'2025-06-24',5,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(147,'2025-06-24',4,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(148,'2025-06-24',4,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(149,'2025-06-24',7,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(150,'2025-06-24',7,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(151,'2025-06-24',6,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(152,'2025-06-24',6,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(153,'2025-06-24',1,4,3,2,1,2.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(154,'2025-06-24',1,4,3,1,NULL,10.00,'2025-06-24 11:11:00','2025-06-24 11:11:00',3,NULL),
|
||||||
|
(155,'2025-06-24',8,3,2,1,NULL,8.00,'2025-06-24 11:11:05','2025-06-24 11:11:05',5,NULL),
|
||||||
|
(156,'2025-06-24',8,3,2,1,NULL,4.00,'2025-06-24 11:11:05','2025-06-24 11:11:05',5,NULL),
|
||||||
|
(157,'2025-06-24',2,3,2,1,NULL,8.00,'2025-06-24 11:11:05','2025-06-24 11:11:05',5,NULL),
|
||||||
|
(158,'2025-06-24',2,3,2,1,NULL,4.00,'2025-06-24 11:11:05','2025-06-24 11:11:05',5,NULL),
|
||||||
|
(159,'2025-06-25',2,3,2,1,NULL,8.00,'2025-06-25 11:08:04','2025-06-25 11:08:04',5,NULL),
|
||||||
|
(160,'2025-06-25',2,3,2,1,NULL,4.00,'2025-06-25 11:08:04','2025-06-25 11:08:04',5,NULL),
|
||||||
|
(161,'2025-06-25',8,3,2,1,NULL,8.00,'2025-06-25 11:08:05','2025-06-25 11:08:05',5,NULL),
|
||||||
|
(162,'2025-06-25',8,3,2,1,NULL,4.00,'2025-06-25 11:08:05','2025-06-25 11:08:05',5,NULL),
|
||||||
|
(163,'2025-06-25',10,4,3,1,NULL,12.00,'2025-06-25 11:11:30','2025-06-25 11:11:30',6,NULL),
|
||||||
|
(164,'2025-06-25',9,4,3,1,NULL,12.00,'2025-06-25 11:11:30','2025-06-25 11:11:30',6,NULL),
|
||||||
|
(165,'2025-06-25',3,4,3,1,NULL,12.00,'2025-06-25 11:11:30','2025-06-25 11:11:30',6,NULL),
|
||||||
|
(166,'2025-06-25',6,4,3,1,NULL,12.00,'2025-06-25 11:11:30','2025-06-25 11:11:30',6,NULL),
|
||||||
|
(167,'2025-06-26',10,4,3,1,NULL,12.00,'2025-06-26 10:29:38','2025-06-26 10:29:38',3,NULL),
|
||||||
|
(168,'2025-06-26',5,4,3,1,NULL,12.00,'2025-06-26 10:29:38','2025-06-26 10:29:38',3,NULL),
|
||||||
|
(169,'2025-06-26',7,4,3,1,NULL,12.00,'2025-06-26 10:29:38','2025-06-26 10:29:38',3,NULL),
|
||||||
|
(170,'2025-06-26',1,4,3,1,NULL,12.00,'2025-06-26 10:29:38','2025-06-26 10:29:38',3,NULL),
|
||||||
|
(171,'2025-06-26',4,4,3,1,NULL,12.00,'2025-06-26 10:29:38','2025-06-26 10:29:38',3,NULL),
|
||||||
|
(172,'2025-06-26',8,3,2,1,NULL,8.00,'2025-06-26 11:11:31','2025-06-26 11:11:31',5,NULL),
|
||||||
|
(173,'2025-06-26',8,3,2,1,NULL,4.00,'2025-06-26 11:11:31','2025-06-26 11:11:31',5,NULL),
|
||||||
|
(174,'2025-06-26',2,3,2,1,NULL,8.00,'2025-06-26 11:11:32','2025-06-26 11:11:32',5,NULL),
|
||||||
|
(175,'2025-06-26',2,3,2,1,NULL,4.00,'2025-06-26 11:11:32','2025-06-26 11:11:32',5,NULL),
|
||||||
|
(176,'2025-06-26',9,3,2,1,NULL,8.00,'2025-06-26 11:11:32','2025-06-26 11:11:32',5,NULL),
|
||||||
|
(177,'2025-06-26',9,3,2,1,NULL,4.00,'2025-06-26 11:11:32','2025-06-26 11:11:32',5,NULL),
|
||||||
|
(178,'2025-06-26',3,3,2,1,NULL,12.00,'2025-06-26 11:19:34','2025-06-26 11:19:34',6,NULL),
|
||||||
|
(179,'2025-06-26',6,3,2,1,NULL,12.00,'2025-06-26 11:19:34','2025-06-26 11:19:34',6,NULL),
|
||||||
|
(182,'2025-06-27',2,3,2,1,NULL,4.00,'2025-06-27 01:54:40','2025-06-27 01:54:40',5,NULL),
|
||||||
|
(183,'2025-06-27',9,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(184,'2025-06-27',10,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(185,'2025-06-27',7,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(186,'2025-06-27',5,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(187,'2025-06-27',4,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(188,'2025-06-27',1,4,3,1,NULL,8.00,'2025-06-27 06:47:43','2025-06-27 06:47:43',3,NULL),
|
||||||
|
(189,'2025-06-27',3,3,2,1,NULL,8.00,'2025-06-27 06:49:08','2025-06-27 06:49:08',6,NULL),
|
||||||
|
(191,'2025-06-27',6,3,2,1,NULL,4.00,'2025-06-27 06:58:46','2025-06-27 06:58:46',6,NULL),
|
||||||
|
(192,'2025-06-27',8,3,2,1,NULL,6.00,'2025-06-27 07:00:10','2025-06-27 07:00:10',5,NULL),
|
||||||
|
(193,'2025-06-30',6,3,2,2,4,2.00,'2025-07-05 01:37:29','2025-07-05 01:37:29',3,NULL),
|
||||||
|
(194,'2025-06-30',6,3,2,1,NULL,2.00,'2025-07-05 01:37:29','2025-07-07 04:15:25',3,3),
|
||||||
|
(195,'2025-06-30',2,3,2,1,NULL,4.00,'2025-07-05 01:38:19','2025-07-07 04:15:40',3,3),
|
||||||
|
(196,'2025-06-30',3,3,2,1,NULL,8.00,'2025-07-05 01:38:19','2025-07-05 01:38:19',3,NULL),
|
||||||
|
(197,'2025-06-30',8,3,2,1,NULL,6.00,'2025-07-05 01:38:19','2025-07-07 04:15:02',3,3),
|
||||||
|
(198,'2025-07-01',3,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(199,'2025-07-01',2,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(200,'2025-07-01',6,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(201,'2025-07-01',8,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(202,'2025-07-01',10,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(203,'2025-07-01',9,3,2,1,NULL,10.00,'2025-07-05 01:39:21','2025-07-05 01:39:21',3,NULL),
|
||||||
|
(204,'2025-07-01',2,3,2,1,NULL,2.00,'2025-07-05 01:39:48','2025-07-05 01:42:08',3,3),
|
||||||
|
(205,'2025-07-01',3,3,2,1,NULL,2.00,'2025-07-05 01:39:48','2025-07-05 01:42:02',3,3),
|
||||||
|
(206,'2025-07-01',6,3,2,1,NULL,2.00,'2025-07-05 01:39:48','2025-07-05 01:41:56',3,3),
|
||||||
|
(207,'2025-07-01',8,3,2,1,NULL,2.00,'2025-07-05 01:39:48','2025-07-05 01:41:48',3,3),
|
||||||
|
(208,'2025-07-01',9,3,2,2,4,2.00,'2025-07-05 01:40:10','2025-07-05 01:40:10',3,NULL),
|
||||||
|
(209,'2025-07-01',10,3,2,2,4,2.00,'2025-07-05 01:40:10','2025-07-05 01:40:10',3,NULL),
|
||||||
|
(210,'2025-07-01',7,4,3,1,NULL,5.00,'2025-07-05 01:42:57','2025-07-05 01:42:57',3,NULL),
|
||||||
|
(211,'2025-07-01',7,4,3,2,2,3.00,'2025-07-05 01:42:57','2025-07-05 01:42:57',3,NULL),
|
||||||
|
(212,'2025-07-01',5,4,3,1,NULL,8.00,'2025-07-05 01:42:57','2025-07-07 04:21:24',3,3),
|
||||||
|
(213,'2025-07-01',5,4,3,2,2,4.00,'2025-07-05 01:42:57','2025-07-07 04:21:10',3,3),
|
||||||
|
(214,'2025-07-01',4,4,3,1,NULL,8.00,'2025-07-05 01:42:57','2025-07-07 04:21:41',3,3),
|
||||||
|
(215,'2025-07-01',4,4,3,2,2,4.00,'2025-07-05 01:42:57','2025-07-07 04:21:32',3,3),
|
||||||
|
(216,'2025-07-01',1,4,3,1,NULL,5.00,'2025-07-05 01:42:57','2025-07-05 01:42:57',3,NULL),
|
||||||
|
(217,'2025-07-01',1,4,3,2,2,3.00,'2025-07-05 01:42:57','2025-07-05 01:42:57',3,NULL),
|
||||||
|
(218,'2025-07-02',2,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(219,'2025-07-02',3,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(220,'2025-07-02',10,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(221,'2025-07-02',9,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(222,'2025-07-02',8,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(223,'2025-07-02',6,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(224,'2025-07-02',7,3,2,1,NULL,10.00,'2025-07-05 01:43:36','2025-07-05 01:43:36',3,NULL),
|
||||||
|
(225,'2025-07-02',5,4,3,2,2,4.00,'2025-07-05 01:44:11','2025-07-05 01:44:11',3,NULL),
|
||||||
|
(226,'2025-07-02',5,4,3,1,NULL,6.00,'2025-07-05 01:44:11','2025-07-05 01:44:54',3,3),
|
||||||
|
(227,'2025-07-02',4,4,3,2,2,4.00,'2025-07-05 01:44:11','2025-07-05 01:44:11',3,NULL),
|
||||||
|
(228,'2025-07-02',4,4,3,1,NULL,6.00,'2025-07-05 01:44:11','2025-07-05 01:44:59',3,3),
|
||||||
|
(229,'2025-07-02',1,4,3,2,2,4.00,'2025-07-05 01:44:11','2025-07-05 01:44:11',3,NULL),
|
||||||
|
(230,'2025-07-02',1,4,3,1,NULL,6.00,'2025-07-05 01:44:11','2025-07-05 01:45:05',3,3),
|
||||||
|
(231,'2025-07-03',2,3,2,1,NULL,10.00,'2025-07-05 01:45:44','2025-07-05 01:45:44',3,NULL),
|
||||||
|
(232,'2025-07-03',6,3,2,1,NULL,10.00,'2025-07-05 01:45:45','2025-07-05 01:45:45',3,NULL),
|
||||||
|
(233,'2025-07-03',9,3,2,1,NULL,10.00,'2025-07-05 01:45:45','2025-07-05 01:45:45',3,NULL),
|
||||||
|
(234,'2025-07-03',8,3,2,1,NULL,10.00,'2025-07-05 01:45:45','2025-07-05 01:45:45',3,NULL),
|
||||||
|
(235,'2025-07-03',7,4,3,1,NULL,10.00,'2025-07-05 01:46:07','2025-07-05 01:46:07',3,NULL),
|
||||||
|
(236,'2025-07-03',1,4,3,1,NULL,10.00,'2025-07-05 01:46:07','2025-07-05 01:46:07',3,NULL),
|
||||||
|
(237,'2025-07-03',3,4,3,1,NULL,10.00,'2025-07-05 01:46:08','2025-07-05 01:46:08',3,NULL),
|
||||||
|
(238,'2025-07-03',4,4,3,1,NULL,10.00,'2025-07-05 01:46:08','2025-07-05 01:46:08',3,NULL),
|
||||||
|
(239,'2025-07-03',5,4,3,1,NULL,10.00,'2025-07-05 01:46:08','2025-07-05 01:46:08',3,NULL),
|
||||||
|
(240,'2025-07-03',10,4,3,1,NULL,10.00,'2025-07-05 01:46:08','2025-07-05 01:46:08',3,NULL),
|
||||||
|
(241,'2025-07-04',10,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(242,'2025-07-04',10,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(243,'2025-07-04',5,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(244,'2025-07-04',5,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(245,'2025-07-04',4,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(246,'2025-07-04',4,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(247,'2025-07-04',9,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(248,'2025-07-04',9,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(249,'2025-07-04',8,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(250,'2025-07-04',8,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(251,'2025-07-04',3,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(252,'2025-07-04',3,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(253,'2025-07-04',2,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(254,'2025-07-04',2,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(255,'2025-07-04',7,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(256,'2025-07-04',7,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(257,'2025-07-04',6,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(258,'2025-07-04',6,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(259,'2025-07-04',1,4,3,2,2,2.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(260,'2025-07-04',1,4,3,1,NULL,6.00,'2025-07-05 01:51:47','2025-07-05 01:51:47',3,NULL),
|
||||||
|
(261,'2025-07-05',8,4,2,1,NULL,8.00,'2025-07-05 05:36:38','2025-07-05 05:36:38',5,NULL),
|
||||||
|
(262,'2025-07-05',5,4,2,1,NULL,8.00,'2025-07-05 05:36:38','2025-07-05 05:36:38',5,NULL),
|
||||||
|
(263,'2025-07-05',4,4,2,1,NULL,8.00,'2025-07-05 05:36:39','2025-07-05 05:36:39',5,NULL),
|
||||||
|
(264,'2025-07-05',3,4,2,1,NULL,8.00,'2025-07-05 05:36:39','2025-07-05 05:36:39',5,NULL),
|
||||||
|
(265,'2025-07-05',2,4,2,1,NULL,8.00,'2025-07-05 05:36:39','2025-07-05 05:36:39',5,NULL),
|
||||||
|
(266,'2025-07-05',1,4,2,1,NULL,8.00,'2025-07-05 05:36:39','2025-07-05 05:36:39',5,NULL),
|
||||||
|
(267,'2025-07-06',10,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:08',5,3),
|
||||||
|
(268,'2025-07-06',9,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:16',5,3),
|
||||||
|
(269,'2025-07-06',7,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:22',5,3),
|
||||||
|
(270,'2025-07-06',6,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:27',5,3),
|
||||||
|
(271,'2025-07-06',4,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:33',5,3),
|
||||||
|
(272,'2025-07-06',3,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:39',5,3),
|
||||||
|
(273,'2025-07-06',2,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:44',5,3),
|
||||||
|
(274,'2025-07-06',1,4,3,1,NULL,8.00,'2025-07-06 05:34:32','2025-07-06 05:46:49',5,3),
|
||||||
|
(275,'2025-07-07',10,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(276,'2025-07-07',9,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(277,'2025-07-07',8,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(278,'2025-07-07',7,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(279,'2025-07-07',3,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(280,'2025-07-07',4,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(281,'2025-07-07',5,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(282,'2025-07-07',6,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(283,'2025-07-07',2,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(284,'2025-07-07',1,4,3,1,NULL,8.00,'2025-07-07 06:49:31','2025-07-07 06:49:31',6,NULL),
|
||||||
|
(285,'2025-07-08',10,4,3,1,NULL,8.00,'2025-07-08 06:36:57','2025-07-08 06:36:57',3,NULL),
|
||||||
|
(286,'2025-07-08',9,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(287,'2025-07-08',8,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(288,'2025-07-08',7,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(289,'2025-07-08',6,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(290,'2025-07-08',1,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(291,'2025-07-08',2,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(292,'2025-07-08',3,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(293,'2025-07-08',5,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(294,'2025-07-08',4,4,3,1,NULL,8.00,'2025-07-08 06:36:58','2025-07-08 06:36:58',3,NULL),
|
||||||
|
(295,'2025-07-09',10,4,3,1,NULL,8.00,'2025-07-09 22:08:40','2025-07-09 22:08:40',5,NULL),
|
||||||
|
(296,'2025-07-09',9,4,3,1,NULL,8.00,'2025-07-09 22:08:40','2025-07-09 22:08:40',5,NULL),
|
||||||
|
(297,'2025-07-09',8,4,3,1,NULL,8.00,'2025-07-09 22:08:40','2025-07-09 22:08:40',5,NULL),
|
||||||
|
(298,'2025-07-09',7,4,3,1,NULL,8.00,'2025-07-09 22:08:41','2025-07-09 22:08:41',5,NULL),
|
||||||
|
(299,'2025-07-09',6,4,3,1,NULL,8.00,'2025-07-09 22:08:41','2025-07-09 22:08:41',5,NULL),
|
||||||
|
(300,'2025-07-09',2,4,3,1,NULL,8.00,'2025-07-09 22:08:41','2025-07-09 22:08:41',5,NULL),
|
||||||
|
(301,'2025-07-09',3,4,3,1,NULL,8.00,'2025-07-09 22:08:42','2025-07-09 22:08:42',5,NULL),
|
||||||
|
(302,'2025-07-09',4,4,3,1,NULL,8.00,'2025-07-09 22:08:42','2025-07-09 22:08:42',5,NULL),
|
||||||
|
(303,'2025-07-09',5,4,3,1,NULL,8.00,'2025-07-09 22:08:42','2025-07-09 22:08:42',5,NULL),
|
||||||
|
(304,'2025-07-09',1,4,3,1,NULL,4.00,'2025-07-09 22:09:10','2025-07-09 22:09:10',5,NULL),
|
||||||
|
(305,'2025-07-10',9,4,3,1,NULL,8.00,'2025-07-10 06:33:58','2025-07-10 06:33:58',3,NULL),
|
||||||
|
(306,'2025-07-10',8,4,3,1,NULL,8.00,'2025-07-10 06:33:58','2025-07-10 06:33:58',3,NULL),
|
||||||
|
(307,'2025-07-10',5,4,3,1,NULL,8.00,'2025-07-10 06:33:58','2025-07-10 06:33:58',3,NULL),
|
||||||
|
(308,'2025-07-10',6,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(309,'2025-07-10',2,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(310,'2025-07-10',3,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(311,'2025-07-10',4,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(312,'2025-07-10',1,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(313,'2025-07-10',7,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(314,'2025-07-10',10,4,3,1,NULL,8.00,'2025-07-10 06:33:59','2025-07-10 06:33:59',3,NULL),
|
||||||
|
(315,'2025-07-12',9,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(316,'2025-07-12',8,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(317,'2025-07-12',6,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(318,'2025-07-12',5,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(319,'2025-07-12',4,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(320,'2025-07-12',2,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(321,'2025-07-12',1,4,3,1,NULL,8.00,'2025-07-12 05:41:30','2025-07-12 05:41:30',3,NULL),
|
||||||
|
(322,'2025-07-14',8,4,3,1,NULL,6.00,'2025-07-14 06:46:30','2025-07-14 06:46:30',3,NULL),
|
||||||
|
(323,'2025-07-14',10,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(324,'2025-07-14',9,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(325,'2025-07-14',7,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(326,'2025-07-14',6,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(327,'2025-07-14',1,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(328,'2025-07-14',2,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(329,'2025-07-14',3,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(330,'2025-07-14',4,4,3,1,NULL,8.00,'2025-07-14 06:46:57','2025-07-14 06:46:57',3,NULL),
|
||||||
|
(331,'2025-07-15',3,3,2,1,NULL,8.00,'2025-07-15 05:57:06','2025-07-15 05:57:06',5,NULL),
|
||||||
|
(332,'2025-07-15',9,3,2,1,NULL,8.00,'2025-07-15 05:57:06','2025-07-15 05:57:06',5,NULL),
|
||||||
|
(333,'2025-07-15',5,3,2,2,4,4.00,'2025-07-15 05:57:47','2025-07-15 05:57:47',5,NULL),
|
||||||
|
(334,'2025-07-15',5,4,3,1,NULL,4.00,'2025-07-15 05:57:47','2025-07-15 05:57:47',5,NULL),
|
||||||
|
(335,'2025-07-15',10,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(336,'2025-07-15',8,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(337,'2025-07-15',7,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(338,'2025-07-15',6,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(339,'2025-07-15',2,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(340,'2025-07-15',1,4,3,1,NULL,8.00,'2025-07-15 05:58:19','2025-07-15 05:58:19',5,NULL),
|
||||||
|
(341,'2025-07-14',5,4,3,1,NULL,8.00,'2025-07-15 06:57:26','2025-07-15 06:57:26',3,NULL),
|
||||||
|
(342,'2025-07-16',4,4,3,1,NULL,2.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(343,'2025-07-16',4,3,2,1,NULL,4.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(344,'2025-07-16',4,3,2,1,NULL,2.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(345,'2025-07-16',5,4,3,1,NULL,2.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(346,'2025-07-16',5,3,2,1,NULL,4.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(347,'2025-07-16',5,3,2,1,NULL,2.00,'2025-07-16 06:46:46','2025-07-16 06:46:46',5,NULL),
|
||||||
|
(348,'2025-07-16',10,4,3,1,NULL,2.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(349,'2025-07-16',10,3,2,1,NULL,4.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(350,'2025-07-16',10,3,2,1,NULL,2.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(351,'2025-07-16',6,4,3,1,NULL,2.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(352,'2025-07-16',6,3,2,1,NULL,4.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(353,'2025-07-16',6,3,2,1,NULL,2.00,'2025-07-16 06:47:53','2025-07-16 06:47:53',5,NULL),
|
||||||
|
(354,'2025-07-16',9,3,2,1,NULL,8.00,'2025-07-16 06:48:32','2025-07-16 06:48:32',5,NULL),
|
||||||
|
(355,'2025-07-16',8,3,2,1,NULL,8.00,'2025-07-16 06:48:32','2025-07-16 06:48:32',5,NULL),
|
||||||
|
(356,'2025-07-16',3,3,2,1,NULL,8.00,'2025-07-16 06:48:32','2025-07-16 06:48:32',5,NULL),
|
||||||
|
(357,'2025-07-16',2,3,2,1,NULL,8.00,'2025-07-16 06:48:32','2025-07-16 06:48:32',5,NULL),
|
||||||
|
(358,'2025-07-16',1,4,3,1,NULL,8.00,'2025-07-16 06:51:31','2025-07-16 06:51:31',3,NULL),
|
||||||
|
(359,'2025-07-16',7,4,3,1,NULL,8.00,'2025-07-16 06:51:31','2025-07-16 06:51:31',3,NULL),
|
||||||
|
(360,'2025-07-17',1,3,3,1,NULL,8.00,'2025-07-17 06:45:22','2025-07-17 06:45:22',3,NULL),
|
||||||
|
(361,'2025-07-17',5,3,2,1,NULL,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(362,'2025-07-17',5,3,2,2,4,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(363,'2025-07-17',4,3,2,1,NULL,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(364,'2025-07-17',4,3,2,2,4,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(365,'2025-07-17',2,3,2,1,NULL,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(366,'2025-07-17',2,3,2,2,4,4.00,'2025-07-17 06:46:48','2025-07-17 06:46:48',5,NULL),
|
||||||
|
(367,'2025-07-17',10,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(368,'2025-07-17',9,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(369,'2025-07-17',8,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(370,'2025-07-17',7,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(371,'2025-07-17',6,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(372,'2025-07-17',3,3,2,1,NULL,8.00,'2025-07-17 06:47:19','2025-07-17 06:47:19',5,NULL),
|
||||||
|
(373,'2025-07-18',7,4,3,2,1,2.00,'2025-07-18 05:54:47','2025-07-18 05:54:47',3,NULL),
|
||||||
|
(374,'2025-07-18',1,4,3,2,1,2.00,'2025-07-18 05:54:48','2025-07-18 05:54:48',3,NULL),
|
||||||
|
(376,'2025-07-18',5,4,3,1,NULL,2.00,'2025-07-18 05:58:33','2025-07-18 05:58:33',3,NULL),
|
||||||
|
(377,'2025-07-18',5,3,2,1,NULL,6.00,'2025-07-18 05:58:33','2025-07-18 05:58:33',3,NULL),
|
||||||
|
(378,'2025-07-18',7,3,2,1,NULL,6.00,'2025-07-18 05:59:42','2025-07-18 05:59:42',3,NULL),
|
||||||
|
(379,'2025-07-18',1,3,3,1,NULL,6.00,'2025-07-18 06:00:15','2025-07-18 06:00:15',3,NULL),
|
||||||
|
(380,'2025-07-18',10,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(381,'2025-07-18',9,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(382,'2025-07-18',8,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(383,'2025-07-18',6,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(384,'2025-07-18',4,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(385,'2025-07-18',3,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(386,'2025-07-18',2,3,2,1,NULL,8.00,'2025-07-18 06:36:13','2025-07-18 06:36:13',5,NULL),
|
||||||
|
(387,'2025-07-21',5,4,3,2,1,4.00,'2025-07-21 06:40:08','2025-07-21 06:40:08',5,NULL),
|
||||||
|
(388,'2025-07-21',5,3,2,1,NULL,4.00,'2025-07-21 06:40:08','2025-07-21 06:40:08',5,NULL),
|
||||||
|
(389,'2025-07-21',4,4,3,2,1,4.00,'2025-07-21 06:40:08','2025-07-21 06:40:08',5,NULL),
|
||||||
|
(390,'2025-07-21',4,3,2,1,NULL,4.00,'2025-07-21 06:40:08','2025-07-21 06:40:08',5,NULL),
|
||||||
|
(391,'2025-07-21',10,3,2,1,NULL,6.00,'2025-07-21 06:40:32','2025-07-22 06:58:42',5,3),
|
||||||
|
(392,'2025-07-21',9,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(393,'2025-07-21',8,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(394,'2025-07-21',7,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(395,'2025-07-21',6,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(396,'2025-07-21',3,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(397,'2025-07-21',2,3,2,1,NULL,8.00,'2025-07-21 06:40:32','2025-07-21 06:40:32',5,NULL),
|
||||||
|
(398,'2025-07-21',1,3,3,1,NULL,8.00,'2025-07-21 06:53:37','2025-07-21 06:53:37',3,NULL),
|
||||||
|
(399,'2025-07-22',10,3,2,1,NULL,8.00,'2025-07-22 06:45:47','2025-07-22 06:45:47',5,NULL),
|
||||||
|
(400,'2025-07-22',9,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(401,'2025-07-22',8,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(402,'2025-07-22',7,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(403,'2025-07-22',6,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(404,'2025-07-22',4,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(405,'2025-07-22',3,3,2,1,NULL,8.00,'2025-07-22 06:45:48','2025-07-22 06:45:48',5,NULL),
|
||||||
|
(406,'2025-07-22',2,4,3,2,1,8.00,'2025-07-22 06:46:11','2025-07-22 06:46:11',5,NULL),
|
||||||
|
(407,'2025-07-22',5,3,3,1,NULL,8.00,'2025-07-22 06:46:11','2025-07-22 06:46:11',3,NULL),
|
||||||
|
(408,'2025-07-22',1,3,3,1,NULL,8.00,'2025-07-22 06:46:11','2025-07-22 06:46:11',3,NULL),
|
||||||
|
(409,'2025-07-23',4,3,3,1,NULL,8.00,'2025-07-23 06:45:06','2025-07-23 06:45:06',5,NULL),
|
||||||
|
(410,'2025-07-23',5,3,3,1,NULL,8.00,'2025-07-23 06:45:28','2025-07-23 06:45:28',3,NULL),
|
||||||
|
(411,'2025-07-23',1,3,3,1,NULL,8.00,'2025-07-23 06:45:28','2025-07-23 06:45:28',3,NULL),
|
||||||
|
(412,'2025-07-23',10,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(413,'2025-07-23',9,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(414,'2025-07-23',7,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(415,'2025-07-23',6,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(416,'2025-07-23',3,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(417,'2025-07-23',2,3,2,1,NULL,8.00,'2025-07-23 06:45:30','2025-07-23 06:45:30',5,NULL),
|
||||||
|
(418,'2025-07-24',4,3,3,1,NULL,8.00,'2025-07-24 06:36:55','2025-07-24 06:36:55',5,NULL),
|
||||||
|
(419,'2025-07-24',10,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(420,'2025-07-24',9,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(421,'2025-07-24',7,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(422,'2025-07-24',6,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(423,'2025-07-24',3,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(424,'2025-07-24',2,3,2,1,NULL,8.00,'2025-07-24 06:37:18','2025-07-24 06:37:18',5,NULL),
|
||||||
|
(425,'2025-07-24',5,3,3,1,NULL,8.00,'2025-07-24 06:47:04','2025-07-24 06:47:04',3,NULL),
|
||||||
|
(426,'2025-07-24',1,3,3,1,NULL,8.00,'2025-07-24 06:47:04','2025-07-24 06:47:04',3,NULL),
|
||||||
|
(427,'2025-07-25',4,3,3,1,NULL,8.00,'2025-07-25 06:44:23','2025-07-25 06:44:23',5,NULL),
|
||||||
|
(428,'2025-07-25',10,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(429,'2025-07-25',9,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(430,'2025-07-25',8,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(431,'2025-07-25',6,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(432,'2025-07-25',3,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(433,'2025-07-25',2,3,2,1,NULL,8.00,'2025-07-25 06:45:15','2025-07-25 06:45:15',5,NULL),
|
||||||
|
(434,'2025-07-25',5,4,3,1,NULL,8.00,'2025-07-25 06:45:18','2025-07-25 06:45:18',3,NULL),
|
||||||
|
(435,'2025-07-25',7,4,3,1,NULL,8.00,'2025-07-25 06:45:19','2025-07-25 06:45:19',3,NULL),
|
||||||
|
(436,'2025-07-25',1,4,3,1,NULL,8.00,'2025-07-25 06:45:19','2025-07-25 06:45:19',3,NULL),
|
||||||
|
(437,'2025-07-28',5,3,3,1,NULL,8.00,'2025-07-28 06:30:39','2025-07-28 06:30:39',3,NULL),
|
||||||
|
(438,'2025-07-28',4,3,3,1,NULL,8.00,'2025-07-28 06:30:39','2025-07-28 06:30:39',3,NULL),
|
||||||
|
(439,'2025-07-28',1,3,3,1,NULL,8.00,'2025-07-28 06:30:39','2025-07-28 06:30:39',3,NULL),
|
||||||
|
(440,'2025-07-28',2,5,2,1,NULL,4.00,'2025-07-28 06:33:08','2025-07-28 06:33:08',5,NULL),
|
||||||
|
(441,'2025-07-28',2,3,2,1,NULL,4.00,'2025-07-28 06:33:08','2025-07-28 06:33:08',5,NULL),
|
||||||
|
(442,'2025-07-28',10,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(443,'2025-07-28',9,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(444,'2025-07-28',8,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(445,'2025-07-28',7,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(446,'2025-07-28',6,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(447,'2025-07-28',3,3,2,1,NULL,8.00,'2025-07-28 06:33:34','2025-07-28 06:33:34',5,NULL),
|
||||||
|
(448,'2025-07-29',5,3,3,1,NULL,8.00,'2025-07-29 06:39:13','2025-07-29 06:39:13',3,NULL),
|
||||||
|
(449,'2025-07-29',4,3,3,1,NULL,8.00,'2025-07-29 06:39:13','2025-07-29 06:39:13',3,NULL),
|
||||||
|
(450,'2025-07-29',1,3,3,1,NULL,8.00,'2025-07-29 06:39:13','2025-07-29 06:39:13',3,NULL),
|
||||||
|
(451,'2025-07-30',5,3,3,1,NULL,8.00,'2025-07-30 06:50:30','2025-07-30 06:50:30',3,NULL),
|
||||||
|
(452,'2025-07-30',4,3,3,1,NULL,8.00,'2025-07-30 06:50:30','2025-07-30 06:50:30',3,NULL),
|
||||||
|
(453,'2025-07-30',1,3,3,1,NULL,8.00,'2025-07-30 06:50:30','2025-07-30 06:50:30',3,NULL),
|
||||||
|
(454,'2025-07-30',10,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(455,'2025-07-30',9,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(456,'2025-07-30',8,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(457,'2025-07-30',7,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(458,'2025-07-30',6,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(459,'2025-07-30',3,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(460,'2025-07-30',2,3,2,1,NULL,8.00,'2025-07-30 06:52:16','2025-07-30 06:52:16',5,NULL),
|
||||||
|
(461,'2025-07-31',1,3,3,1,NULL,4.00,'2025-07-31 06:42:56','2025-07-31 06:42:56',5,NULL),
|
||||||
|
(462,'2025-07-31',4,3,3,1,NULL,4.00,'2025-07-31 06:43:32','2025-07-31 06:43:32',5,NULL),
|
||||||
|
(463,'2025-07-31',4,3,2,1,NULL,4.00,'2025-07-31 06:43:32','2025-07-31 06:43:32',5,NULL),
|
||||||
|
(464,'2025-07-31',5,3,3,1,NULL,4.00,'2025-07-31 06:43:32','2025-07-31 06:43:32',5,NULL),
|
||||||
|
(465,'2025-07-31',5,3,2,1,NULL,4.00,'2025-07-31 06:43:32','2025-07-31 06:43:32',5,NULL),
|
||||||
|
(466,'2025-07-31',10,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(467,'2025-07-31',9,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(468,'2025-07-31',8,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(469,'2025-07-31',7,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(470,'2025-07-31',6,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(471,'2025-07-31',3,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(472,'2025-07-31',2,3,2,1,NULL,8.00,'2025-07-31 06:44:00','2025-07-31 06:44:00',5,NULL),
|
||||||
|
(473,'2025-07-11',10,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(474,'2025-07-11',5,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(475,'2025-07-11',4,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(476,'2025-07-11',9,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(477,'2025-07-11',8,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(478,'2025-07-11',3,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(479,'2025-07-11',2,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(480,'2025-07-11',7,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(481,'2025-07-11',6,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(482,'2025-07-11',1,3,2,1,NULL,8.00,'2025-07-31 22:24:47','2025-07-31 22:24:47',3,NULL),
|
||||||
|
(483,'2025-08-01',10,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(484,'2025-08-01',9,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(485,'2025-08-01',8,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(486,'2025-08-01',7,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(487,'2025-08-01',6,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(488,'2025-08-01',3,3,2,1,NULL,8.00,'2025-08-01 04:57:47','2025-08-01 04:57:47',5,NULL),
|
||||||
|
(489,'2025-08-01',2,3,2,1,NULL,8.00,'2025-08-01 04:57:48','2025-08-01 04:57:48',5,NULL),
|
||||||
|
(490,'2025-08-01',4,3,3,1,NULL,4.00,'2025-08-01 05:02:28','2025-08-01 05:02:28',3,NULL),
|
||||||
|
(491,'2025-08-01',4,5,1,1,NULL,4.00,'2025-08-01 05:02:28','2025-08-01 05:02:28',3,NULL),
|
||||||
|
(492,'2025-08-01',5,3,3,1,NULL,4.00,'2025-08-01 05:02:28','2025-08-01 05:02:28',3,NULL),
|
||||||
|
(493,'2025-08-01',5,5,1,1,NULL,4.00,'2025-08-01 05:02:28','2025-08-01 05:02:28',3,NULL),
|
||||||
|
(494,'2025-08-07',9,3,2,2,4,4.00,'2025-08-07 06:42:39','2025-08-07 06:42:39',5,NULL),
|
||||||
|
(495,'2025-08-07',9,3,2,1,NULL,4.00,'2025-08-07 06:42:39','2025-08-07 06:42:39',5,NULL),
|
||||||
|
(496,'2025-08-07',7,3,2,2,4,4.00,'2025-08-07 06:42:39','2025-08-07 06:42:39',5,NULL),
|
||||||
|
(497,'2025-08-07',7,3,2,1,NULL,4.00,'2025-08-07 06:42:39','2025-08-07 06:42:39',5,NULL),
|
||||||
|
(498,'2025-08-07',10,5,2,1,NULL,8.00,'2025-08-07 06:43:14','2025-08-07 06:43:14',5,NULL),
|
||||||
|
(499,'2025-08-07',4,5,2,1,NULL,8.00,'2025-08-07 06:43:15','2025-08-07 06:43:15',5,NULL),
|
||||||
|
(500,'2025-08-07',2,5,2,1,NULL,8.00,'2025-08-07 06:43:15','2025-08-07 06:43:15',5,NULL),
|
||||||
|
(501,'2025-08-07',6,3,2,1,NULL,8.00,'2025-08-07 06:43:39','2025-08-07 06:43:39',5,NULL),
|
||||||
|
(502,'2025-08-07',3,3,2,1,NULL,8.00,'2025-08-07 06:43:39','2025-08-07 06:43:39',5,NULL),
|
||||||
|
(503,'2025-08-07',8,3,2,1,NULL,8.00,'2025-08-07 06:43:39','2025-08-07 06:43:39',5,NULL),
|
||||||
|
(504,'2025-08-07',1,3,3,1,NULL,8.00,'2025-08-07 06:43:52','2025-08-07 06:43:52',3,NULL),
|
||||||
|
(505,'2025-08-08',1,3,3,1,NULL,8.00,'2025-08-08 06:45:20','2025-08-08 06:45:20',3,NULL),
|
||||||
|
(506,'2025-08-08',10,5,2,1,NULL,8.00,'2025-08-08 06:58:42','2025-08-08 06:58:42',5,NULL),
|
||||||
|
(507,'2025-08-08',2,5,2,1,NULL,8.00,'2025-08-08 06:58:42','2025-08-08 06:58:42',5,NULL),
|
||||||
|
(508,'2025-08-08',9,3,2,1,NULL,8.00,'2025-08-08 06:59:18','2025-08-08 06:59:18',5,NULL),
|
||||||
|
(509,'2025-08-08',8,3,2,1,NULL,8.00,'2025-08-08 06:59:19','2025-08-08 06:59:19',5,NULL),
|
||||||
|
(510,'2025-08-08',3,3,2,1,NULL,8.00,'2025-08-08 06:59:19','2025-08-08 06:59:19',5,NULL),
|
||||||
|
(511,'2025-08-08',4,3,2,1,NULL,8.00,'2025-08-08 06:59:19','2025-08-08 06:59:19',5,NULL),
|
||||||
|
(512,'2025-08-08',6,3,2,1,NULL,8.00,'2025-08-08 06:59:19','2025-08-08 06:59:19',5,NULL),
|
||||||
|
(513,'2025-08-11',1,3,3,1,NULL,8.00,'2025-08-11 06:27:37','2025-08-11 06:27:37',3,NULL),
|
||||||
|
(514,'2025-08-11',1,3,3,1,NULL,8.00,'2025-08-11 06:27:37','2025-08-11 06:27:37',3,NULL),
|
||||||
|
(515,'2025-08-11',10,5,2,1,NULL,8.00,'2025-08-11 06:46:23','2025-08-11 06:46:23',5,NULL),
|
||||||
|
(516,'2025-08-11',2,5,2,1,NULL,8.00,'2025-08-11 06:46:23','2025-08-11 06:46:23',5,NULL),
|
||||||
|
(517,'2025-08-11',8,3,2,1,NULL,8.00,'2025-08-11 06:46:49','2025-08-11 06:46:49',5,NULL),
|
||||||
|
(518,'2025-08-11',7,3,2,1,NULL,8.00,'2025-08-11 06:46:49','2025-08-11 06:46:49',5,NULL),
|
||||||
|
(519,'2025-08-11',6,3,2,1,NULL,8.00,'2025-08-11 06:46:50','2025-08-11 06:46:50',5,NULL),
|
||||||
|
(520,'2025-08-11',5,3,2,1,NULL,8.00,'2025-08-11 06:46:50','2025-08-11 06:46:50',5,NULL),
|
||||||
|
(521,'2025-08-11',4,3,2,1,NULL,8.00,'2025-08-11 06:46:50','2025-08-11 06:46:50',5,NULL),
|
||||||
|
(522,'2025-08-11',3,3,2,1,NULL,8.00,'2025-08-11 06:46:50','2025-08-11 06:46:50',5,NULL),
|
||||||
|
(523,'2025-08-12',10,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(524,'2025-08-12',9,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(525,'2025-08-12',8,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(526,'2025-08-12',7,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(527,'2025-08-12',5,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(528,'2025-08-12',4,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(529,'2025-08-12',3,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(530,'2025-08-12',1,3,2,1,NULL,8.00,'2025-08-12 06:47:24','2025-08-12 06:47:24',3,NULL),
|
||||||
|
(531,'2025-08-13',1,3,3,1,NULL,8.00,'2025-08-13 06:31:32','2025-08-13 06:31:32',3,NULL),
|
||||||
|
(532,'2025-08-13',2,3,2,1,NULL,4.00,'2025-08-13 06:36:13','2025-08-13 06:36:13',5,NULL),
|
||||||
|
(533,'2025-08-13',2,5,2,1,NULL,4.00,'2025-08-13 06:36:13','2025-08-13 06:36:13',5,NULL),
|
||||||
|
(534,'2025-08-13',9,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(535,'2025-08-13',8,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(536,'2025-08-13',7,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(537,'2025-08-13',6,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(538,'2025-08-13',5,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(539,'2025-08-13',4,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(540,'2025-08-13',3,3,2,1,NULL,8.00,'2025-08-13 06:36:48','2025-08-13 06:36:48',5,NULL),
|
||||||
|
(541,'2025-08-13',10,5,2,1,NULL,8.00,'2025-08-13 06:37:19','2025-08-13 06:37:19',5,NULL),
|
||||||
|
(542,'2025-08-14',1,3,3,2,1,4.00,'2025-08-14 06:35:27','2025-08-14 06:35:27',3,NULL),
|
||||||
|
(543,'2025-08-14',1,3,3,1,NULL,4.00,'2025-08-14 06:35:27','2025-08-14 06:35:27',3,NULL),
|
||||||
|
(544,'2025-08-14',10,5,2,1,NULL,4.00,'2025-08-14 06:39:03','2025-08-14 06:39:03',5,NULL),
|
||||||
|
(545,'2025-08-14',10,5,3,1,NULL,4.00,'2025-08-14 06:39:03','2025-08-14 06:39:03',5,NULL),
|
||||||
|
(546,'2025-08-14',2,5,2,1,NULL,2.00,'2025-08-14 06:39:44','2025-08-14 06:39:44',5,NULL),
|
||||||
|
(547,'2025-08-14',2,3,2,1,NULL,6.00,'2025-08-14 06:39:44','2025-08-14 06:39:44',5,NULL),
|
||||||
|
(548,'2025-08-14',9,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(549,'2025-08-14',8,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(550,'2025-08-14',7,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(551,'2025-08-14',6,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(552,'2025-08-14',5,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(553,'2025-08-14',4,3,2,1,NULL,8.00,'2025-08-14 06:40:10','2025-08-14 06:40:10',5,NULL),
|
||||||
|
(554,'2025-08-18',2,3,2,1,NULL,8.00,'2025-08-18 06:21:36','2025-08-18 06:21:36',5,NULL),
|
||||||
|
(555,'2025-08-18',8,3,2,1,NULL,8.00,'2025-08-18 06:21:36','2025-08-18 06:21:36',5,NULL),
|
||||||
|
(556,'2025-08-18',4,3,2,1,NULL,8.00,'2025-08-18 06:22:01','2025-08-18 06:22:01',5,NULL),
|
||||||
|
(557,'2025-08-18',10,5,3,1,NULL,6.00,'2025-08-18 06:22:53','2025-08-18 06:22:53',5,NULL),
|
||||||
|
(558,'2025-08-18',10,3,2,1,NULL,2.00,'2025-08-18 06:22:53','2025-08-18 06:22:53',5,NULL),
|
||||||
|
(559,'2025-08-18',9,3,2,1,NULL,4.00,'2025-08-18 06:23:34','2025-08-18 06:23:34',5,NULL),
|
||||||
|
(560,'2025-08-18',9,3,3,1,NULL,4.00,'2025-08-18 06:23:34','2025-08-18 06:23:34',5,NULL),
|
||||||
|
(561,'2025-08-18',5,3,3,2,1,4.00,'2025-08-18 06:41:24','2025-08-18 06:41:24',3,NULL),
|
||||||
|
(562,'2025-08-18',1,3,3,2,1,4.00,'2025-08-18 06:41:24','2025-08-18 06:41:24',3,NULL),
|
||||||
|
(563,'2025-08-18',7,3,3,2,1,4.00,'2025-08-18 06:41:24','2025-08-18 06:41:24',3,NULL),
|
||||||
|
(564,'2025-08-18',7,3,3,1,NULL,4.00,'2025-08-18 06:43:10','2025-08-18 06:43:10',3,NULL),
|
||||||
|
(565,'2025-08-18',5,3,3,1,NULL,4.00,'2025-08-18 06:43:10','2025-08-18 06:43:10',3,NULL),
|
||||||
|
(566,'2025-08-18',1,3,3,1,NULL,4.00,'2025-08-18 06:43:10','2025-08-18 06:43:10',3,NULL),
|
||||||
|
(567,'2025-08-18',6,3,3,1,NULL,8.00,'2025-08-18 06:43:35','2025-08-18 06:43:35',6,NULL),
|
||||||
|
(568,'2025-08-18',3,3,3,1,NULL,8.00,'2025-08-18 06:43:35','2025-08-18 06:43:35',6,NULL),
|
||||||
|
(569,'2025-08-19',1,3,3,1,NULL,6.00,'2025-08-19 08:02:49','2025-08-19 08:02:49',5,NULL),
|
||||||
|
(570,'2025-08-19',3,3,3,1,NULL,10.00,'2025-08-19 08:03:30','2025-08-19 08:03:30',5,NULL),
|
||||||
|
(571,'2025-08-19',6,3,3,1,NULL,10.00,'2025-08-19 08:03:30','2025-08-19 08:03:30',5,NULL),
|
||||||
|
(572,'2025-08-19',7,3,3,1,NULL,10.00,'2025-08-19 08:03:30','2025-08-19 08:03:30',5,NULL),
|
||||||
|
(573,'2025-08-19',9,3,3,1,NULL,10.00,'2025-08-19 08:03:30','2025-08-19 08:03:30',5,NULL),
|
||||||
|
(574,'2025-08-19',10,3,2,1,NULL,10.00,'2025-08-19 08:04:05','2025-08-19 08:04:05',5,NULL),
|
||||||
|
(575,'2025-08-19',8,3,2,1,NULL,10.00,'2025-08-19 08:04:05','2025-08-19 08:04:05',5,NULL),
|
||||||
|
(576,'2025-08-19',5,3,2,1,NULL,10.00,'2025-08-19 08:04:05','2025-08-19 08:04:05',5,NULL),
|
||||||
|
(577,'2025-08-19',4,3,2,1,NULL,10.00,'2025-08-19 08:04:05','2025-08-19 08:04:05',5,NULL),
|
||||||
|
(578,'2025-08-19',2,3,2,1,NULL,10.00,'2025-08-19 08:04:05','2025-08-19 08:04:05',5,NULL),
|
||||||
|
(579,'2025-08-19',3,3,3,1,NULL,10.00,'2025-08-19 08:36:51','2025-08-19 08:36:51',6,NULL),
|
||||||
|
(580,'2025-08-19',7,3,3,1,NULL,10.00,'2025-08-19 08:36:51','2025-08-19 08:36:51',6,NULL),
|
||||||
|
(581,'2025-08-19',6,3,3,1,NULL,10.00,'2025-08-19 08:36:51','2025-08-19 08:36:51',6,NULL),
|
||||||
|
(582,'2025-08-20',2,3,2,1,NULL,8.00,'2025-08-20 06:19:36','2025-08-20 06:19:36',5,NULL),
|
||||||
|
(583,'2025-08-20',5,3,1,1,NULL,2.00,'2025-08-20 06:21:28','2025-08-20 06:21:28',5,NULL),
|
||||||
|
(584,'2025-08-20',5,3,2,1,NULL,6.00,'2025-08-20 06:21:28','2025-08-20 06:21:28',5,NULL),
|
||||||
|
(585,'2025-08-20',4,3,1,1,NULL,2.00,'2025-08-20 06:21:28','2025-08-20 06:21:28',5,NULL),
|
||||||
|
(586,'2025-08-20',4,3,2,1,NULL,6.00,'2025-08-20 06:21:28','2025-08-20 06:21:28',5,NULL),
|
||||||
|
(587,'2025-08-20',6,3,3,1,NULL,4.00,'2025-08-20 06:43:46','2025-08-20 06:43:46',3,NULL),
|
||||||
|
(588,'2025-08-20',10,3,3,1,NULL,8.00,'2025-08-20 06:44:23','2025-08-20 06:44:23',3,NULL),
|
||||||
|
(589,'2025-08-20',9,3,3,1,NULL,8.00,'2025-08-20 06:44:23','2025-08-20 06:44:23',3,NULL),
|
||||||
|
(590,'2025-08-20',8,3,3,1,NULL,8.00,'2025-08-20 06:44:23','2025-08-20 06:44:23',3,NULL),
|
||||||
|
(591,'2025-08-20',7,3,3,1,NULL,8.00,'2025-08-20 06:44:24','2025-08-20 06:44:24',3,NULL),
|
||||||
|
(592,'2025-08-20',3,3,3,1,NULL,8.00,'2025-08-20 06:44:24','2025-08-20 06:44:24',3,NULL),
|
||||||
|
(593,'2025-08-20',1,3,3,1,NULL,8.00,'2025-08-20 06:44:24','2025-08-20 06:44:24',3,NULL),
|
||||||
|
(594,'2025-08-20',10,3,3,1,NULL,8.00,'2025-08-20 06:44:26','2025-08-20 06:44:26',6,NULL),
|
||||||
|
(595,'2025-08-20',3,3,3,1,NULL,8.00,'2025-08-20 06:44:26','2025-08-20 06:44:26',6,NULL),
|
||||||
|
(596,'2025-08-21',7,3,3,1,NULL,8.00,'2025-08-21 06:30:36','2025-08-21 06:30:36',3,NULL),
|
||||||
|
(597,'2025-08-21',1,3,3,1,NULL,8.00,'2025-08-21 06:30:36','2025-08-21 06:30:36',3,NULL),
|
||||||
|
(598,'2025-08-21',1,3,3,1,NULL,8.00,'2025-08-21 07:50:38','2025-08-21 07:50:38',5,NULL),
|
||||||
|
(599,'2025-08-21',7,3,3,1,NULL,8.00,'2025-08-21 07:50:38','2025-08-21 07:50:38',5,NULL),
|
||||||
|
(600,'2025-08-21',10,3,3,1,NULL,8.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(601,'2025-08-21',10,3,3,1,NULL,2.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(602,'2025-08-21',9,3,3,1,NULL,8.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(603,'2025-08-21',9,3,3,1,NULL,2.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(604,'2025-08-21',6,3,3,1,NULL,8.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(605,'2025-08-21',6,3,3,1,NULL,2.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(606,'2025-08-21',3,3,3,1,NULL,8.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(607,'2025-08-21',3,3,3,1,NULL,2.00,'2025-08-21 07:51:23','2025-08-21 07:51:23',5,NULL),
|
||||||
|
(608,'2025-08-21',2,3,2,1,NULL,8.00,'2025-08-21 07:54:46','2025-08-21 07:54:46',5,NULL),
|
||||||
|
(609,'2025-08-21',2,5,2,1,NULL,2.00,'2025-08-21 07:54:46','2025-08-21 07:54:46',5,NULL),
|
||||||
|
(610,'2025-08-21',8,3,3,1,NULL,4.00,'2025-08-21 07:55:25','2025-08-21 07:55:25',5,NULL),
|
||||||
|
(611,'2025-08-21',8,3,2,1,NULL,6.00,'2025-08-21 07:55:25','2025-08-21 07:55:25',5,NULL),
|
||||||
|
(612,'2025-08-21',6,3,3,1,NULL,10.00,'2025-08-21 08:24:50','2025-08-21 08:24:50',6,NULL),
|
||||||
|
(613,'2025-08-21',3,3,3,1,NULL,10.00,'2025-08-21 08:24:50','2025-08-21 08:24:50',6,NULL),
|
||||||
|
(614,'2025-08-22',2,3,2,1,NULL,8.00,'2025-08-22 06:21:15','2025-08-22 06:21:15',5,NULL),
|
||||||
|
(615,'2025-08-22',8,3,2,1,NULL,4.00,'2025-08-22 06:23:12','2025-08-22 06:23:12',5,NULL),
|
||||||
|
(616,'2025-08-22',8,3,3,1,NULL,4.00,'2025-08-22 06:23:12','2025-08-22 06:23:12',5,NULL),
|
||||||
|
(617,'2025-08-22',5,3,3,1,NULL,8.00,'2025-08-22 06:23:55','2025-08-22 06:23:55',5,NULL),
|
||||||
|
(618,'2025-08-22',6,3,2,1,NULL,4.00,'2025-08-22 06:27:43','2025-08-22 06:27:43',3,NULL),
|
||||||
|
(619,'2025-08-22',10,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(620,'2025-08-22',9,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(621,'2025-08-22',7,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(622,'2025-08-22',4,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(623,'2025-08-22',3,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(624,'2025-08-22',1,3,3,1,NULL,8.00,'2025-08-22 06:28:15','2025-08-22 06:28:15',3,NULL),
|
||||||
|
(625,'2025-08-23',4,3,2,1,NULL,2.00,'2025-08-23 04:57:02','2025-08-23 04:57:02',5,NULL),
|
||||||
|
(626,'2025-08-23',4,3,3,1,NULL,6.00,'2025-08-23 04:57:02','2025-08-23 04:57:02',5,NULL),
|
||||||
|
(627,'2025-08-23',2,3,2,1,NULL,8.00,'2025-08-23 04:57:25','2025-08-23 04:57:25',5,NULL),
|
||||||
|
(628,'2025-08-23',10,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(629,'2025-08-23',9,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(630,'2025-08-23',8,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(631,'2025-08-23',6,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(632,'2025-08-23',5,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(633,'2025-08-23',3,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(634,'2025-08-23',1,3,3,1,NULL,8.00,'2025-08-23 04:57:54','2025-08-23 04:57:54',5,NULL),
|
||||||
|
(635,'2025-08-25',10,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(636,'2025-08-25',9,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(637,'2025-08-25',8,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(638,'2025-08-25',7,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(639,'2025-08-25',6,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(640,'2025-08-25',5,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(641,'2025-08-25',4,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(642,'2025-08-25',3,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(643,'2025-08-25',2,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(644,'2025-08-25',1,3,3,1,NULL,8.00,'2025-08-25 06:48:34','2025-08-25 06:48:34',3,NULL),
|
||||||
|
(645,'2025-08-25',6,3,3,1,NULL,8.00,'2025-08-25 06:49:16','2025-08-25 06:49:16',6,NULL),
|
||||||
|
(646,'2025-08-25',3,3,3,1,NULL,8.00,'2025-08-25 06:49:17','2025-08-25 06:49:17',6,NULL),
|
||||||
|
(647,'2025-08-26',4,8,3,1,NULL,8.00,'2025-08-26 07:28:03','2025-08-26 07:28:03',5,NULL),
|
||||||
|
(648,'2025-08-26',4,3,3,1,NULL,2.00,'2025-08-26 07:28:03','2025-08-26 07:28:03',5,NULL),
|
||||||
|
(649,'2025-08-26',2,8,3,1,NULL,10.00,'2025-08-26 07:28:35','2025-08-26 07:28:35',5,NULL),
|
||||||
|
(650,'2025-08-26',10,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(651,'2025-08-26',9,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(652,'2025-08-26',8,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(653,'2025-08-26',7,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(654,'2025-08-26',6,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(655,'2025-08-26',5,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(656,'2025-08-26',3,3,3,1,NULL,10.00,'2025-08-26 07:29:02','2025-08-26 07:29:02',5,NULL),
|
||||||
|
(657,'2025-08-26',1,3,3,1,NULL,10.00,'2025-08-26 07:29:03','2025-08-26 07:29:03',5,NULL),
|
||||||
|
(658,'2025-08-26',6,3,3,1,NULL,10.00,'2025-08-26 08:22:12','2025-08-26 08:22:12',6,NULL),
|
||||||
|
(659,'2025-08-26',10,3,3,1,NULL,10.00,'2025-08-26 08:22:12','2025-08-26 08:22:12',6,NULL),
|
||||||
|
(660,'2025-08-26',3,3,3,1,NULL,10.00,'2025-08-26 08:22:12','2025-08-26 08:22:12',6,NULL),
|
||||||
|
(661,'2025-08-27',10,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(662,'2025-08-27',9,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(663,'2025-08-27',7,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(664,'2025-08-27',6,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(665,'2025-08-27',5,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(666,'2025-08-27',4,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(667,'2025-08-27',3,3,3,2,5,8.00,'2025-08-27 06:44:47','2025-08-27 06:44:47',3,NULL),
|
||||||
|
(668,'2025-08-27',1,3,3,2,5,8.00,'2025-08-27 06:44:48','2025-08-27 06:44:48',3,NULL),
|
||||||
|
(669,'2025-08-27',2,3,3,2,1,2.00,'2025-08-27 06:45:32','2025-08-27 06:45:32',5,NULL),
|
||||||
|
(670,'2025-08-27',2,8,2,1,NULL,6.00,'2025-08-27 06:45:32','2025-08-27 06:45:32',5,NULL),
|
||||||
|
(671,'2025-08-27',8,3,3,2,1,2.00,'2025-08-27 06:45:32','2025-08-27 06:45:32',5,NULL),
|
||||||
|
(672,'2025-08-27',8,8,2,1,NULL,6.00,'2025-08-27 06:45:32','2025-08-27 06:45:32',5,NULL),
|
||||||
|
(673,'2025-08-28',10,3,3,1,NULL,6.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(674,'2025-08-28',10,3,3,2,1,4.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(675,'2025-08-28',5,3,3,1,NULL,6.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(676,'2025-08-28',5,3,3,2,1,4.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(677,'2025-08-28',6,3,3,1,NULL,6.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(678,'2025-08-28',6,3,3,2,1,4.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(679,'2025-08-28',3,3,3,1,NULL,6.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(680,'2025-08-28',3,3,3,2,1,4.00,'2025-08-28 08:31:42','2025-08-28 08:31:42',6,NULL),
|
||||||
|
(681,'2025-08-28',4,3,3,1,NULL,4.00,'2025-08-28 08:37:46','2025-08-28 08:37:46',5,NULL),
|
||||||
|
(682,'2025-08-28',4,5,3,1,NULL,4.00,'2025-08-28 08:37:46','2025-08-28 08:37:46',5,NULL),
|
||||||
|
(683,'2025-08-28',8,8,2,1,NULL,4.00,'2025-08-28 08:38:15','2025-08-28 08:38:15',5,NULL),
|
||||||
|
(684,'2025-08-28',8,5,3,1,NULL,4.00,'2025-08-28 08:38:15','2025-08-28 08:38:15',5,NULL),
|
||||||
|
(685,'2025-08-28',2,3,3,2,1,2.00,'2025-08-28 08:38:50','2025-08-28 08:38:50',5,NULL),
|
||||||
|
(686,'2025-08-28',2,5,3,1,NULL,6.00,'2025-08-28 08:38:50','2025-08-28 08:38:50',5,NULL),
|
||||||
|
(687,'2025-08-28',1,3,3,2,1,8.00,'2025-08-28 08:39:24','2025-08-28 08:39:24',5,NULL),
|
||||||
|
(689,'2025-08-28',9,3,3,2,4,8.00,'2025-08-28 08:40:00','2025-08-28 08:40:00',5,NULL),
|
||||||
|
(690,'2025-08-28',7,3,3,2,4,8.00,'2025-08-28 08:40:00','2025-08-28 08:40:00',5,NULL),
|
||||||
|
(694,'2025-08-28',4,5,3,1,NULL,2.00,'2025-08-28 08:44:56','2025-08-28 08:44:56',5,NULL),
|
||||||
|
(695,'2025-08-28',8,5,3,1,NULL,2.00,'2025-08-28 08:44:56','2025-08-28 08:44:56',5,NULL),
|
||||||
|
(696,'2025-08-28',2,5,3,1,NULL,2.00,'2025-08-28 08:44:56','2025-08-28 08:44:56',5,NULL),
|
||||||
|
(698,'2025-08-28',9,3,3,1,NULL,2.00,'2025-08-28 08:45:19','2025-08-28 08:45:19',5,NULL),
|
||||||
|
(699,'2025-08-28',7,3,3,1,NULL,2.00,'2025-08-28 08:45:19','2025-08-28 08:45:19',5,NULL),
|
||||||
|
(703,'2025-08-29',10,3,3,2,5,8.00,'2025-08-29 06:47:02','2025-08-29 06:47:02',3,NULL),
|
||||||
|
(704,'2025-08-29',9,3,3,2,5,8.00,'2025-08-29 06:47:02','2025-08-29 06:47:02',3,NULL),
|
||||||
|
(706,'2025-08-29',7,3,3,2,5,8.00,'2025-08-29 06:47:02','2025-08-29 06:47:02',3,NULL),
|
||||||
|
(710,'2025-08-29',1,3,3,2,5,8.00,'2025-08-29 06:47:02','2025-08-29 06:47:02',3,NULL),
|
||||||
|
(713,'2025-08-29',5,3,3,1,NULL,6.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(714,'2025-08-29',5,3,3,2,1,2.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(715,'2025-08-29',3,3,3,1,NULL,6.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(716,'2025-08-29',3,3,3,2,1,2.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(717,'2025-08-29',6,3,3,1,NULL,6.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(718,'2025-08-29',6,3,3,2,1,2.00,'2025-08-29 06:47:35','2025-08-29 06:47:35',6,NULL),
|
||||||
|
(719,'2025-08-29',8,5,3,1,NULL,8.00,'2025-08-29 21:55:56','2025-08-29 21:55:56',5,NULL),
|
||||||
|
(720,'2025-08-29',4,5,3,1,NULL,8.00,'2025-08-29 21:55:56','2025-08-29 21:55:56',5,NULL),
|
||||||
|
(721,'2025-08-29',2,5,3,1,NULL,8.00,'2025-08-29 21:55:56','2025-08-29 21:55:56',5,NULL),
|
||||||
|
(722,'2025-08-30',2,5,3,1,NULL,8.00,'2025-08-30 05:12:03','2025-08-30 05:12:03',5,NULL),
|
||||||
|
(723,'2025-08-30',8,5,3,1,NULL,8.00,'2025-08-30 05:12:03','2025-08-30 05:12:03',5,NULL),
|
||||||
|
(724,'2025-08-30',4,5,3,1,NULL,8.00,'2025-08-30 05:12:03','2025-08-30 05:12:03',5,NULL),
|
||||||
|
(725,'2025-08-30',10,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(726,'2025-08-30',9,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(727,'2025-08-30',7,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(728,'2025-08-30',6,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(729,'2025-08-30',5,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(730,'2025-08-30',3,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(731,'2025-08-30',1,3,3,2,1,8.00,'2025-08-30 05:36:49','2025-08-30 05:36:49',3,NULL),
|
||||||
|
(732,'2025-09-01',7,3,3,1,NULL,8.00,'2025-09-01 06:18:28','2025-09-01 06:18:28',3,NULL),
|
||||||
|
(733,'2025-09-01',9,3,3,1,NULL,8.00,'2025-09-01 06:18:28','2025-09-01 06:18:28',3,NULL),
|
||||||
|
(734,'2025-09-01',10,3,3,2,5,4.00,'2025-09-01 06:19:11','2025-09-01 06:19:11',3,NULL),
|
||||||
|
(735,'2025-09-01',3,3,3,2,5,4.00,'2025-09-01 06:19:11','2025-09-01 06:19:11',3,NULL),
|
||||||
|
(736,'2025-09-01',1,3,3,2,5,4.00,'2025-09-01 06:19:11','2025-09-01 06:19:11',3,NULL),
|
||||||
|
(737,'2025-09-01',10,3,3,1,NULL,4.00,'2025-09-01 06:19:35','2025-09-01 06:19:35',3,NULL),
|
||||||
|
(738,'2025-09-01',3,3,3,1,NULL,4.00,'2025-09-01 06:19:35','2025-09-01 06:19:35',3,NULL),
|
||||||
|
(739,'2025-09-01',1,3,3,1,NULL,4.00,'2025-09-01 06:19:35','2025-09-01 06:19:35',3,NULL),
|
||||||
|
(740,'2025-09-01',5,3,3,2,1,8.00,'2025-09-01 06:20:03','2025-09-01 06:20:03',3,NULL);
|
||||||
|
/*!40000 ALTER TABLE `daily_work_reports` ENABLE KEYS */;
|
||||||
|
UNLOCK TABLES;
|
||||||
|
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||||
|
|
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||||
|
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||||
|
|
||||||
|
-- Dump completed on 2025-09-01 23:19:44
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- phpMyAdmin SQL Dump
|
작-- phpMyAdmin SQL Dump
|
||||||
-- version 5.2.2
|
-- version 5.2.2
|
||||||
-- https://www.phpmyadmin.net/
|
-- https://www.phpmyadmin.net/
|
||||||
--
|
--
|
||||||
|
|||||||
2563
api.hyungi.net/hyungi_fixed.sql
Normal file
2563
api.hyungi.net/hyungi_fixed.sql
Normal file
File diff suppressed because it is too large
Load Diff
@@ -178,18 +178,13 @@ const authRoutes = require('./routes/authRoutes');
|
|||||||
const projectRoutes = require('./routes/projectRoutes');
|
const projectRoutes = require('./routes/projectRoutes');
|
||||||
const workerRoutes = require('./routes/workerRoutes');
|
const workerRoutes = require('./routes/workerRoutes');
|
||||||
const taskRoutes = require('./routes/taskRoutes');
|
const taskRoutes = require('./routes/taskRoutes');
|
||||||
const processRoutes = require('./routes/processRoutes');
|
|
||||||
const workReportRoutes = require('./routes/workReportRoutes');
|
const workReportRoutes = require('./routes/workReportRoutes');
|
||||||
const cuttingPlanRoutes = require('./routes/cuttingPlanRoutes');
|
|
||||||
const factoryInfoRoutes = require('./routes/factoryInfoRoutes');
|
|
||||||
const equipmentListRoutes = require('./routes/equipmentListRoutes');
|
|
||||||
const toolsRoute = require('./routes/toolsRoute');
|
const toolsRoute = require('./routes/toolsRoute');
|
||||||
const uploadRoutes = require('./routes/uploadRoutes');
|
const uploadRoutes = require('./routes/uploadRoutes');
|
||||||
const uploadBgRoutes = require('./routes/uploadBgRoutes');
|
const uploadBgRoutes = require('./routes/uploadBgRoutes');
|
||||||
const dailyIssueReportRoutes = require('./routes/dailyIssueReportRoutes');
|
const dailyIssueReportRoutes = require('./routes/dailyIssueReportRoutes');
|
||||||
const issueTypeRoutes = require('./routes/issueTypeRoutes');
|
const issueTypeRoutes = require('./routes/issueTypeRoutes');
|
||||||
const healthRoutes = require('./routes/healthRoutes');
|
const healthRoutes = require('./routes/healthRoutes');
|
||||||
const pipeSpecRoutes = require('./routes/pipeSpecRoutes');
|
|
||||||
const dailyWorkReportRoutes = require('./routes/dailyWorkReportRoutes');
|
const dailyWorkReportRoutes = require('./routes/dailyWorkReportRoutes');
|
||||||
const workAnalysisRoutes = require('./routes/workAnalysisRoutes');
|
const workAnalysisRoutes = require('./routes/workAnalysisRoutes');
|
||||||
const analysisRoutes = require('./routes/analysisRoutes');
|
const analysisRoutes = require('./routes/analysisRoutes');
|
||||||
@@ -305,6 +300,7 @@ app.use('/api/workers', workerRoutes);
|
|||||||
app.use('/api/daily-work-reports', dailyWorkReportRoutes);
|
app.use('/api/daily-work-reports', dailyWorkReportRoutes);
|
||||||
app.use('/api/work-analysis', workAnalysisRoutes);
|
app.use('/api/work-analysis', workAnalysisRoutes);
|
||||||
app.use('/api/analysis', analysisRoutes); // 새로운 분석 라우트 등록
|
app.use('/api/analysis', analysisRoutes); // 새로운 분석 라우트 등록
|
||||||
|
app.use('/api/daily-work-reports-analysis', require('./routes/workReportAnalysisRoutes')); // 데일리 워크 레포트 분석 라우트
|
||||||
|
|
||||||
// 📊 리포트 및 분석
|
// 📊 리포트 및 분석
|
||||||
app.use('/api/workreports', workReportRoutes);
|
app.use('/api/workreports', workReportRoutes);
|
||||||
@@ -316,12 +312,7 @@ app.use('/api/uploads', uploadRoutes);
|
|||||||
// ⚙️ 시스템 데이터들 (모든 인증된 사용자)
|
// ⚙️ 시스템 데이터들 (모든 인증된 사용자)
|
||||||
app.use('/api/projects', projectRoutes);
|
app.use('/api/projects', projectRoutes);
|
||||||
app.use('/api/tasks', taskRoutes);
|
app.use('/api/tasks', taskRoutes);
|
||||||
app.use('/api/processes', processRoutes);
|
|
||||||
app.use('/api/cuttingplans', cuttingPlanRoutes);
|
|
||||||
app.use('/api/factoryinfo', factoryInfoRoutes);
|
|
||||||
app.use('/api/equipment', equipmentListRoutes);
|
|
||||||
app.use('/api/tools', toolsRoute);
|
app.use('/api/tools', toolsRoute);
|
||||||
app.use('/api/pipespecs', pipeSpecRoutes);
|
|
||||||
|
|
||||||
// 📤 파일 업로드
|
// 📤 파일 업로드
|
||||||
app.use('/api', uploadBgRoutes);
|
app.use('/api', uploadBgRoutes);
|
||||||
|
|||||||
@@ -19,4 +19,71 @@ exports.verifyToken = (req, res, next) => {
|
|||||||
console.error('[verifyToken 오류]', err.message);
|
console.error('[verifyToken 오류]', err.message);
|
||||||
return res.status(403).json({ error: '토큰 검증 실패', detail: err.message });
|
return res.status(403).json({ error: '토큰 검증 실패', detail: err.message });
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin 등급 이상 권한 체크 미들웨어
|
||||||
|
*/
|
||||||
|
exports.requireAdmin = (req, res, next) => {
|
||||||
|
try {
|
||||||
|
if (!req.user) {
|
||||||
|
return res.status(401).json({
|
||||||
|
error: '인증 필요',
|
||||||
|
message: '먼저 로그인해주세요.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const userRole = req.user.role;
|
||||||
|
const adminRoles = ['admin', 'system'];
|
||||||
|
|
||||||
|
if (!adminRoles.includes(userRole)) {
|
||||||
|
return res.status(403).json({
|
||||||
|
error: '권한 부족',
|
||||||
|
message: '관리자 권한이 필요합니다.',
|
||||||
|
required: 'admin 또는 system',
|
||||||
|
current: userRole
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ Admin 권한 확인: ${req.user.username} (${userRole})`);
|
||||||
|
next();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[requireAdmin 오류]', err.message);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: '권한 확인 중 오류 발생',
|
||||||
|
detail: err.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System 등급 권한 체크 미들웨어
|
||||||
|
*/
|
||||||
|
exports.requireSystem = (req, res, next) => {
|
||||||
|
try {
|
||||||
|
if (!req.user) {
|
||||||
|
return res.status(401).json({
|
||||||
|
error: '인증 필요',
|
||||||
|
message: '먼저 로그인해주세요.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.user.role !== 'system') {
|
||||||
|
return res.status(403).json({
|
||||||
|
error: '권한 부족',
|
||||||
|
message: '시스템 관리자 권한이 필요합니다.',
|
||||||
|
required: 'system',
|
||||||
|
current: req.user.role
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`✅ System 권한 확인: ${req.user.username}`);
|
||||||
|
next();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[requireSystem 오류]', err.message);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: '권한 확인 중 오류 발생',
|
||||||
|
detail: err.message
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
@@ -201,12 +201,12 @@ class WorkAnalysis {
|
|||||||
u.name as created_by_name,
|
u.name as created_by_name,
|
||||||
dwr.created_at
|
dwr.created_at
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||||
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||||
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
WHERE dwr.report_date BETWEEN ? AND ?
|
WHERE dwr.report_date BETWEEN ? AND ?
|
||||||
ORDER BY dwr.created_at DESC
|
ORDER BY dwr.created_at DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
const create = async (plan, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
project_id, drawing_name,
|
|
||||||
pipe_spec, area_number,
|
|
||||||
spool_number, length
|
|
||||||
} = plan;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`INSERT INTO CuttingPlan
|
|
||||||
(project_id, drawing_name, pipe_spec, area_number, spool_number, length)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
||||||
[project_id, drawing_name, pipe_spec, area_number, spool_number, length]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.insertId);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAll = async (callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM CuttingPlan ORDER BY cutting_plan_id DESC`
|
|
||||||
);
|
|
||||||
callback(null, rows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(new Error(err.message || String(err)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getById = async (cutting_plan_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM CuttingPlan WHERE cutting_plan_id = ?`,
|
|
||||||
[cutting_plan_id]
|
|
||||||
);
|
|
||||||
callback(null, rows[0]);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const update = async (plan, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
cutting_plan_id, project_id, drawing_name,
|
|
||||||
pipe_spec, area_number, spool_number, length
|
|
||||||
} = plan;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`UPDATE CuttingPlan
|
|
||||||
SET project_id = ?,
|
|
||||||
drawing_name = ?,
|
|
||||||
pipe_spec = ?,
|
|
||||||
area_number = ?,
|
|
||||||
spool_number = ?,
|
|
||||||
length = ?
|
|
||||||
WHERE cutting_plan_id = ?`,
|
|
||||||
[project_id, drawing_name, pipe_spec, area_number, spool_number, length, cutting_plan_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (cutting_plan_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM CuttingPlan WHERE cutting_plan_id = ?`,
|
|
||||||
[cutting_plan_id]
|
|
||||||
);
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = { create, getAll, getById, update, remove };
|
|
||||||
@@ -54,7 +54,7 @@ const createDailyReport = async (reportData, callback) => {
|
|||||||
const [existingReports] = await conn.query(
|
const [existingReports] = await conn.query(
|
||||||
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||||
GROUP BY dwr.created_by`,
|
GROUP BY dwr.created_by`,
|
||||||
[report_date, worker_id]
|
[report_date, worker_id]
|
||||||
@@ -82,7 +82,7 @@ const [existingReports] = await conn.query(
|
|||||||
const [finalReports] = await conn.query(
|
const [finalReports] = await conn.query(
|
||||||
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
`SELECT dwr.created_by, u.name as created_by_name, COUNT(*) as count, SUM(dwr.work_hours) as total_hours
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||||
GROUP BY dwr.created_by`,
|
GROUP BY dwr.created_by`,
|
||||||
[report_date, worker_id]
|
[report_date, worker_id]
|
||||||
@@ -164,7 +164,7 @@ const getMyAccumulatedHours = async (date, worker_id, created_by, callback) => {
|
|||||||
ORDER BY created_at
|
ORDER BY created_at
|
||||||
) as my_entries
|
) as my_entries
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
WHERE dwr.report_date = ? AND dwr.worker_id = ? AND dwr.created_by = ?
|
WHERE dwr.report_date = ? AND dwr.worker_id = ? AND dwr.created_by = ?
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -216,8 +216,8 @@ const getContributorsByDate = async (date, worker_id, callback) => {
|
|||||||
ORDER BY dwr.created_at SEPARATOR ', '
|
ORDER BY dwr.created_at SEPARATOR ', '
|
||||||
) as entry_details
|
) as entry_details
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
WHERE dwr.report_date = ? AND dwr.worker_id = ?
|
||||||
GROUP BY dwr.created_by
|
GROUP BY dwr.created_by
|
||||||
ORDER BY total_hours DESC, first_entry ASC
|
ORDER BY total_hours DESC, first_entry ASC
|
||||||
@@ -245,9 +245,9 @@ const removeSpecificEntry = async (entry_id, deleted_by, callback) => {
|
|||||||
const [entryInfo] = await conn.query(
|
const [entryInfo] = await conn.query(
|
||||||
`SELECT dwr.*, w.worker_name, p.project_name, u.name as created_by_name
|
`SELECT dwr.*, w.worker_name, p.project_name, u.name as created_by_name
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
WHERE dwr.id = ?`,
|
WHERE dwr.id = ?`,
|
||||||
[entry_id]
|
[entry_id]
|
||||||
);
|
);
|
||||||
@@ -333,12 +333,12 @@ const getSelectQuery = () => `
|
|||||||
dwr.created_at,
|
dwr.created_at,
|
||||||
dwr.updated_at
|
dwr.updated_at
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||||
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||||
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
||||||
LEFT JOIN Users u ON dwr.created_by = u.user_id
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -524,7 +524,7 @@ const getSummaryByDate = async (date, callback) => {
|
|||||||
COUNT(*) as work_entries_count,
|
COUNT(*) as work_entries_count,
|
||||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
WHERE dwr.report_date = ?
|
WHERE dwr.report_date = ?
|
||||||
GROUP BY dwr.worker_id, dwr.report_date
|
GROUP BY dwr.worker_id, dwr.report_date
|
||||||
ORDER BY w.worker_name ASC
|
ORDER BY w.worker_name ASC
|
||||||
@@ -553,7 +553,7 @@ const getSummaryByWorker = async (worker_id, callback) => {
|
|||||||
COUNT(*) as work_entries_count,
|
COUNT(*) as work_entries_count,
|
||||||
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
SUM(CASE WHEN dwr.work_status_id = 2 THEN 1 ELSE 0 END) as error_count
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
WHERE dwr.worker_id = ?
|
WHERE dwr.worker_id = ?
|
||||||
GROUP BY dwr.report_date, dwr.worker_id
|
GROUP BY dwr.report_date, dwr.worker_id
|
||||||
ORDER BY dwr.report_date DESC
|
ORDER BY dwr.report_date DESC
|
||||||
@@ -587,8 +587,8 @@ const getMonthlySummary = async (year, month, callback) => {
|
|||||||
GROUP_CONCAT(DISTINCT p.project_name ORDER BY p.project_name) as projects,
|
GROUP_CONCAT(DISTINCT p.project_name ORDER BY p.project_name) as projects,
|
||||||
GROUP_CONCAT(DISTINCT wt.name ORDER BY wt.name) as work_types
|
GROUP_CONCAT(DISTINCT wt.name ORDER BY wt.name) as work_types
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN Workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
LEFT JOIN Projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||||
WHERE dwr.report_date BETWEEN ? AND ?
|
WHERE dwr.report_date BETWEEN ? AND ?
|
||||||
GROUP BY dwr.report_date, dwr.worker_id
|
GROUP BY dwr.report_date, dwr.worker_id
|
||||||
@@ -798,21 +798,21 @@ const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
|||||||
const insertedIds = [];
|
const insertedIds = [];
|
||||||
const sql = `
|
const sql = `
|
||||||
INSERT INTO daily_work_reports
|
INSERT INTO daily_work_reports
|
||||||
(report_date, worker_id, project_id, task_id, work_hours, is_error, error_type_code_id, created_by_user_id)
|
(report_date, worker_id, project_id, work_type_id, work_hours, work_status_id, error_type_id, created_by)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
`;
|
`;
|
||||||
|
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
const { project_id, task_id, work_hours, is_error, error_type_code_id, created_by_user_id } = entry;
|
const { project_id, work_type_id, work_hours, work_status_id, error_type_id, created_by } = entry;
|
||||||
const [result] = await conn.query(sql, [
|
const [result] = await conn.query(sql, [
|
||||||
report_date,
|
report_date,
|
||||||
worker_id,
|
worker_id,
|
||||||
project_id,
|
project_id,
|
||||||
task_id,
|
work_type_id,
|
||||||
work_hours,
|
work_hours,
|
||||||
is_error,
|
work_status_id || 1,
|
||||||
error_type_code_id,
|
error_type_id,
|
||||||
created_by_user_id
|
created_by
|
||||||
]);
|
]);
|
||||||
insertedIds.push(result.insertId);
|
insertedIds.push(result.insertId);
|
||||||
}
|
}
|
||||||
@@ -840,27 +840,29 @@ const createReportEntries = async ({ report_date, worker_id, entries }) => {
|
|||||||
*/
|
*/
|
||||||
const getSelectQueryV2 = () => `
|
const getSelectQueryV2 = () => `
|
||||||
SELECT
|
SELECT
|
||||||
dwr.report_id,
|
dwr.id,
|
||||||
dwr.report_date,
|
dwr.report_date,
|
||||||
dwr.worker_id,
|
dwr.worker_id,
|
||||||
dwr.project_id,
|
dwr.project_id,
|
||||||
dwr.task_id,
|
dwr.work_type_id,
|
||||||
|
dwr.work_status_id,
|
||||||
|
dwr.error_type_id,
|
||||||
dwr.work_hours,
|
dwr.work_hours,
|
||||||
dwr.is_error,
|
dwr.created_by,
|
||||||
dwr.error_type_code_id,
|
|
||||||
dwr.created_by_user_id,
|
|
||||||
w.worker_name,
|
w.worker_name,
|
||||||
p.project_name,
|
p.project_name,
|
||||||
t.task_name,
|
wt.name as work_type_name,
|
||||||
c.code_name as error_type_name,
|
wst.name as work_status_name,
|
||||||
|
et.name as error_type_name,
|
||||||
u.name as created_by_name,
|
u.name as created_by_name,
|
||||||
dwr.created_at
|
dwr.created_at
|
||||||
FROM daily_work_reports dwr
|
FROM daily_work_reports dwr
|
||||||
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
LEFT JOIN workers w ON dwr.worker_id = w.worker_id
|
||||||
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
LEFT JOIN projects p ON dwr.project_id = p.project_id
|
||||||
LEFT JOIN tasks t ON dwr.task_id = t.task_id
|
LEFT JOIN work_types wt ON dwr.work_type_id = wt.id
|
||||||
LEFT JOIN users u ON dwr.created_by_user_id = u.user_id
|
LEFT JOIN work_status_types wst ON dwr.work_status_id = wst.id
|
||||||
LEFT JOIN codes c ON dwr.error_type_code_id = c.code_id AND c.code_type_id = 'ERROR_TYPE'
|
LEFT JOIN error_types et ON dwr.error_type_id = et.id
|
||||||
|
LEFT JOIN users u ON dwr.created_by = u.user_id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -881,9 +883,9 @@ const getReportsWithOptions = async (options) => {
|
|||||||
whereConditions.push('dwr.worker_id = ?');
|
whereConditions.push('dwr.worker_id = ?');
|
||||||
queryParams.push(options.worker_id);
|
queryParams.push(options.worker_id);
|
||||||
}
|
}
|
||||||
if (options.created_by_user_id) {
|
if (options.created_by) {
|
||||||
whereConditions.push('dwr.created_by_user_id = ?');
|
whereConditions.push('dwr.created_by = ?');
|
||||||
queryParams.push(options.created_by_user_id);
|
queryParams.push(options.created_by);
|
||||||
}
|
}
|
||||||
// 필요에 따라 다른 조건 추가 가능 (project_id 등)
|
// 필요에 따라 다른 조건 추가 가능 (project_id 등)
|
||||||
|
|
||||||
|
|||||||
@@ -1,94 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
const create = async (equipment, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
factory_id, equipment_name,
|
|
||||||
model, status, purchase_date, description
|
|
||||||
} = equipment;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`INSERT INTO EquipmentList
|
|
||||||
(factory_id, equipment_name, model, status, purchase_date, description)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
||||||
[factory_id, equipment_name, model, status, purchase_date, description]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.insertId);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAll = async (callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM EquipmentList ORDER BY equipment_id DESC`
|
|
||||||
);
|
|
||||||
callback(null, rows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getById = async (equipment_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM EquipmentList WHERE equipment_id = ?`,
|
|
||||||
[equipment_id]
|
|
||||||
);
|
|
||||||
callback(null, rows[0]);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const update = async (equipment, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
equipment_id, factory_id, equipment_name,
|
|
||||||
model, status, purchase_date, description
|
|
||||||
} = equipment;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`UPDATE EquipmentList
|
|
||||||
SET factory_id = ?,
|
|
||||||
equipment_name = ?,
|
|
||||||
model = ?,
|
|
||||||
status = ?,
|
|
||||||
purchase_date = ?,
|
|
||||||
description = ?
|
|
||||||
WHERE equipment_id = ?`,
|
|
||||||
[factory_id, equipment_name, model, status, purchase_date, description, equipment_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(new Error(err.message || String(err)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (equipment_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM EquipmentList WHERE equipment_id = ?`,
|
|
||||||
[equipment_id]
|
|
||||||
);
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
create,
|
|
||||||
getAll,
|
|
||||||
getById,
|
|
||||||
update,
|
|
||||||
remove
|
|
||||||
};
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
const create = async (factory, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const { factory_name, address, description, map_image_url } = factory;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`INSERT INTO FactoryInfo
|
|
||||||
(factory_name, address, description, map_image_url)
|
|
||||||
VALUES (?, ?, ?, ?)`,
|
|
||||||
[factory_name, address, description, map_image_url]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.insertId);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAll = async (callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM FactoryInfo ORDER BY factory_id DESC`
|
|
||||||
);
|
|
||||||
callback(null, rows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getById = async (factory_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM FactoryInfo WHERE factory_id = ?`,
|
|
||||||
[factory_id]
|
|
||||||
);
|
|
||||||
callback(null, rows[0]);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const update = async (factory, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const { factory_id, factory_name, address, description, map_image_url } = factory;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`UPDATE FactoryInfo
|
|
||||||
SET factory_name = ?,
|
|
||||||
address = ?,
|
|
||||||
description = ?,
|
|
||||||
map_image_url = ?
|
|
||||||
WHERE factory_id = ?`,
|
|
||||||
[factory_name, address, description, map_image_url, factory_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(new Error(err.message || String(err)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (factory_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM FactoryInfo WHERE factory_id = ?`,
|
|
||||||
[factory_id]
|
|
||||||
);
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
create,
|
|
||||||
getAll,
|
|
||||||
getById,
|
|
||||||
update,
|
|
||||||
remove
|
|
||||||
};
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
// models/pingModel.js
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 단순 ping 비즈니스 로직 레이어
|
|
||||||
* 필요하다면 여기서 더 복잡한 처리나 다른 서비스 호출 등을 관리
|
|
||||||
*/
|
|
||||||
exports.ping = () => {
|
|
||||||
return {
|
|
||||||
message: 'pong',
|
|
||||||
timestamp: new Date().toISOString()
|
|
||||||
};
|
|
||||||
};
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
// 전체 조회
|
|
||||||
const getAll = async () => {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(`SELECT * FROM PipeSpecs ORDER BY material, diameter_in`);
|
|
||||||
return rows;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 등록
|
|
||||||
const create = async ({ material, diameter_in, schedule }) => {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`INSERT INTO PipeSpecs (material, diameter_in, schedule)
|
|
||||||
VALUES (?, ?, ?)`,
|
|
||||||
[material, diameter_in, schedule]
|
|
||||||
);
|
|
||||||
return result.insertId;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 삭제
|
|
||||||
const remove = async (spec_id) => {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM PipeSpecs WHERE spec_id = ?`,
|
|
||||||
[spec_id]
|
|
||||||
);
|
|
||||||
return result.affectedRows;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = { getAll, create, remove };
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
const { getDb } = require('../dbPool');
|
|
||||||
|
|
||||||
const create = async (processData, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
project_id, process_name,
|
|
||||||
process_start, process_end,
|
|
||||||
planned_worker_count, process_description, note
|
|
||||||
} = processData;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`INSERT INTO Processes
|
|
||||||
(project_id, process_name, process_start, process_end,
|
|
||||||
planned_worker_count, process_description, note)
|
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
||||||
[project_id, process_name, process_start, process_end,
|
|
||||||
planned_worker_count, process_description, note]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.insertId);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getAll = async (callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM Processes ORDER BY process_id DESC`
|
|
||||||
);
|
|
||||||
callback(null, rows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getById = async (process_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [rows] = await db.query(
|
|
||||||
`SELECT * FROM Processes WHERE process_id = ?`,
|
|
||||||
[process_id]
|
|
||||||
);
|
|
||||||
callback(null, rows[0]);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const update = async (processData, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const {
|
|
||||||
process_id, project_id,
|
|
||||||
process_name, process_start, process_end,
|
|
||||||
planned_worker_count, process_description, note
|
|
||||||
} = processData;
|
|
||||||
|
|
||||||
const [result] = await db.query(
|
|
||||||
`UPDATE Processes
|
|
||||||
SET project_id = ?,
|
|
||||||
process_name = ?,
|
|
||||||
process_start = ?,
|
|
||||||
process_end = ?,
|
|
||||||
planned_worker_count = ?,
|
|
||||||
process_description = ?,
|
|
||||||
note = ?
|
|
||||||
WHERE process_id = ?`,
|
|
||||||
[project_id, process_name, process_start, process_end,
|
|
||||||
planned_worker_count, process_description, note, process_id]
|
|
||||||
);
|
|
||||||
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(new Error(err.message || String(err)));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const remove = async (process_id, callback) => {
|
|
||||||
try {
|
|
||||||
const db = await getDb();
|
|
||||||
const [result] = await db.query(
|
|
||||||
`DELETE FROM Processes WHERE process_id = ?`,
|
|
||||||
[process_id]
|
|
||||||
);
|
|
||||||
callback(null, result.affectedRows);
|
|
||||||
} catch (err) {
|
|
||||||
callback(err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
create,
|
|
||||||
getAll,
|
|
||||||
getById,
|
|
||||||
update,
|
|
||||||
remove
|
|
||||||
};
|
|
||||||
@@ -7,7 +7,7 @@ const create = async (worker, callback) => {
|
|||||||
const { worker_name, join_date, job_type, salary, annual_leave, status } = worker;
|
const { worker_name, join_date, job_type, salary, annual_leave, status } = worker;
|
||||||
|
|
||||||
const [result] = await db.query(
|
const [result] = await db.query(
|
||||||
`INSERT INTO Workers
|
`INSERT INTO workers
|
||||||
(worker_name, join_date, job_type, salary, annual_leave, status)
|
(worker_name, join_date, job_type, salary, annual_leave, status)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)`,
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
||||||
[worker_name, join_date, job_type, salary, annual_leave, status]
|
[worker_name, join_date, job_type, salary, annual_leave, status]
|
||||||
@@ -23,7 +23,7 @@ const create = async (worker, callback) => {
|
|||||||
const getAll = async (callback) => {
|
const getAll = async (callback) => {
|
||||||
try {
|
try {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
const [rows] = await db.query(`SELECT * FROM Workers ORDER BY worker_id DESC`);
|
const [rows] = await db.query(`SELECT * FROM workers ORDER BY worker_id DESC`);
|
||||||
callback(null, rows);
|
callback(null, rows);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
@@ -34,7 +34,7 @@ const getAll = async (callback) => {
|
|||||||
const getById = async (worker_id, callback) => {
|
const getById = async (worker_id, callback) => {
|
||||||
try {
|
try {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
const [rows] = await db.query(`SELECT * FROM Workers WHERE worker_id = ?`, [worker_id]);
|
const [rows] = await db.query(`SELECT * FROM workers WHERE worker_id = ?`, [worker_id]);
|
||||||
callback(null, rows[0]);
|
callback(null, rows[0]);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
callback(err);
|
callback(err);
|
||||||
@@ -48,7 +48,7 @@ const update = async (worker, callback) => {
|
|||||||
const { worker_id, worker_name, join_date, job_type, salary, annual_leave, status } = worker;
|
const { worker_id, worker_name, join_date, job_type, salary, annual_leave, status } = worker;
|
||||||
|
|
||||||
const [result] = await db.query(
|
const [result] = await db.query(
|
||||||
`UPDATE Workers
|
`UPDATE workers
|
||||||
SET worker_name = ?,
|
SET worker_name = ?,
|
||||||
join_date = ?,
|
join_date = ?,
|
||||||
job_type = ?,
|
job_type = ?,
|
||||||
@@ -70,7 +70,7 @@ const remove = async (worker_id, callback) => {
|
|||||||
try {
|
try {
|
||||||
const db = await getDb();
|
const db = await getDb();
|
||||||
const [result] = await db.query(
|
const [result] = await db.query(
|
||||||
`DELETE FROM Workers WHERE worker_id = ?`,
|
`DELETE FROM workers WHERE worker_id = ?`,
|
||||||
[worker_id]
|
[worker_id]
|
||||||
);
|
);
|
||||||
callback(null, result.affectedRows);
|
callback(null, result.affectedRows);
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
// routes/cuttingPlanRoutes.js
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const cuttingPlanController = require('../controllers/cuttingPlanController');
|
|
||||||
|
|
||||||
// CREATE
|
|
||||||
router.post('/', cuttingPlanController.createCuttingPlan);
|
|
||||||
|
|
||||||
// READ ALL
|
|
||||||
router.get('/', cuttingPlanController.getAllCuttingPlans);
|
|
||||||
|
|
||||||
// READ ONE
|
|
||||||
router.get('/:cutting_plan_id', cuttingPlanController.getCuttingPlanById);
|
|
||||||
|
|
||||||
// UPDATE
|
|
||||||
router.put('/:cutting_plan_id', cuttingPlanController.updateCuttingPlan);
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
router.delete('/:cutting_plan_id', cuttingPlanController.removeCuttingPlan);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// routes/equipmentListRoutes.js
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const equipmentListController = require('../controllers/equipmentListController');
|
|
||||||
|
|
||||||
// CREATE
|
|
||||||
router.post('/', equipmentListController.createEquipment);
|
|
||||||
|
|
||||||
// READ ALL
|
|
||||||
router.get('/', equipmentListController.getAllEquipment);
|
|
||||||
|
|
||||||
// READ ONE
|
|
||||||
router.get('/:equipment_id', equipmentListController.getEquipmentById);
|
|
||||||
|
|
||||||
// UPDATE
|
|
||||||
router.put('/:equipment_id', equipmentListController.updateEquipment);
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
router.delete('/:equipment_id', equipmentListController.removeEquipment);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const multer = require('multer');
|
|
||||||
const path = require('path');
|
|
||||||
|
|
||||||
const factoryInfoController = require('../controllers/factoryInfoController');
|
|
||||||
const { verifyToken } = require('../middlewares/authMiddleware'); // ← 수정
|
|
||||||
const { requireAccess } = require('../middlewares/accessMiddleware'); // ← 수정
|
|
||||||
|
|
||||||
// 📦 파일 저장 설정
|
|
||||||
const storage = multer.diskStorage({
|
|
||||||
destination: (req, file, cb) => {
|
|
||||||
cb(null, 'public/uploads/');
|
|
||||||
},
|
|
||||||
filename: (req, file, cb) => {
|
|
||||||
const uniqueName = `map_image-${Date.now()}${path.extname(file.originalname)}`;
|
|
||||||
cb(null, uniqueName);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const upload = multer({ storage });
|
|
||||||
|
|
||||||
// CREATE
|
|
||||||
router.post(
|
|
||||||
'/',
|
|
||||||
verifyToken, // ← 수정
|
|
||||||
upload.single('map_image'),
|
|
||||||
factoryInfoController.createFactoryInfo
|
|
||||||
);
|
|
||||||
|
|
||||||
// READ ALL
|
|
||||||
router.get('/', verifyToken, factoryInfoController.getAllFactoryInfo); // ← 수정
|
|
||||||
|
|
||||||
// READ ONE
|
|
||||||
router.get('/:factory_id', verifyToken, factoryInfoController.getFactoryInfoById); // ← 수정
|
|
||||||
|
|
||||||
// UPDATE
|
|
||||||
router.put('/:factory_id', verifyToken, factoryInfoController.updateFactoryInfo); // ← 수정
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
router.delete('/:factory_id', verifyToken, factoryInfoController.removeFactoryInfo); // ← 수정
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
// routes/pingRoutes.js
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const pingController = require('../controllers/pingController');
|
|
||||||
|
|
||||||
router.get('/', pingController.ping);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const pipeSpecController = require('../controllers/pipeSpecController');
|
|
||||||
const auth = require('../middlewares/auth');
|
|
||||||
const { requireAccess } = require('../middlewares/access');
|
|
||||||
|
|
||||||
// ✅ 전체 조회 (모든 사용자 가능)
|
|
||||||
router.get(
|
|
||||||
'/',
|
|
||||||
auth,
|
|
||||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
|
||||||
pipeSpecController.getAll
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 재질 목록
|
|
||||||
router.get(
|
|
||||||
'/materials',
|
|
||||||
auth,
|
|
||||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
|
||||||
pipeSpecController.getMaterials
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 직경 목록
|
|
||||||
router.get(
|
|
||||||
'/diameters',
|
|
||||||
auth,
|
|
||||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
|
||||||
pipeSpecController.getDiameters
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 스케줄 목록
|
|
||||||
router.get(
|
|
||||||
'/schedules',
|
|
||||||
auth,
|
|
||||||
requireAccess('worker', 'group_leader', 'support_team', 'admin', 'system'),
|
|
||||||
pipeSpecController.getSchedules
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 등록 (시스템 또는 관리자만)
|
|
||||||
router.post(
|
|
||||||
'/',
|
|
||||||
auth,
|
|
||||||
requireAccess('system', 'admin'),
|
|
||||||
pipeSpecController.create
|
|
||||||
);
|
|
||||||
|
|
||||||
// ✅ 삭제 (시스템 또는 관리자만)
|
|
||||||
router.delete(
|
|
||||||
'/:spec_id',
|
|
||||||
auth,
|
|
||||||
requireAccess('system', 'admin'),
|
|
||||||
pipeSpecController.remove
|
|
||||||
);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
// routes/processRoutes.js
|
|
||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
const processController = require('../controllers/processController');
|
|
||||||
|
|
||||||
// CREATE
|
|
||||||
router.post('/', processController.createProcess);
|
|
||||||
|
|
||||||
// READ ALL
|
|
||||||
router.get('/', processController.getAllProcesses);
|
|
||||||
|
|
||||||
// READ ONE
|
|
||||||
router.get('/:process_id', processController.getProcessById);
|
|
||||||
|
|
||||||
// UPDATE
|
|
||||||
router.put('/:process_id', processController.updateProcess);
|
|
||||||
|
|
||||||
// DELETE
|
|
||||||
router.delete('/:process_id', processController.removeProcess);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
||||||
@@ -36,6 +36,9 @@ router.get('/monthly-comparison', workAnalysisController.getMonthlyComparison);
|
|||||||
// 🎯 작업자별 전문분야 분석
|
// 🎯 작업자별 전문분야 분석
|
||||||
router.get('/worker-specialization', workAnalysisController.getWorkerSpecialization);
|
router.get('/worker-specialization', workAnalysisController.getWorkerSpecialization);
|
||||||
|
|
||||||
|
// 🏗️ 프로젝트별-작업별 시간 분석 (총시간, 정규시간, 에러시간)
|
||||||
|
router.get('/project-worktype-analysis', workAnalysisController.getProjectWorkTypeAnalysis);
|
||||||
|
|
||||||
// 📋 헬스체크 및 API 정보
|
// 📋 헬스체크 및 API 정보
|
||||||
router.get('/health', (req, res) => {
|
router.get('/health', (req, res) => {
|
||||||
res.json({
|
res.json({
|
||||||
@@ -52,7 +55,8 @@ router.get('/health', (req, res) => {
|
|||||||
'GET /work-analysis/weekday-pattern - 요일별 패턴',
|
'GET /work-analysis/weekday-pattern - 요일별 패턴',
|
||||||
'GET /work-analysis/error-analysis - 에러 분석',
|
'GET /work-analysis/error-analysis - 에러 분석',
|
||||||
'GET /work-analysis/monthly-comparison - 월별 비교',
|
'GET /work-analysis/monthly-comparison - 월별 비교',
|
||||||
'GET /work-analysis/worker-specialization - 작업자 전문분야'
|
'GET /work-analysis/worker-specialization - 작업자 전문분야',
|
||||||
|
'GET /work-analysis/project-worktype-analysis - 프로젝트별-작업별 시간 분석'
|
||||||
],
|
],
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
|
|||||||
23
api.hyungi.net/routes/workReportAnalysisRoutes.js
Normal file
23
api.hyungi.net/routes/workReportAnalysisRoutes.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// routes/workReportAnalysisRoutes.js - 데일리 워크 레포트 분석 라우트
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const workReportAnalysisController = require('../controllers/workReportAnalysisController');
|
||||||
|
const { verifyToken, requireAdmin } = require('../middlewares/authMiddleware');
|
||||||
|
|
||||||
|
// 🔒 모든 분석 라우트에 인증 + Admin 권한 필요
|
||||||
|
router.use(verifyToken);
|
||||||
|
router.use(requireAdmin);
|
||||||
|
|
||||||
|
// 📋 분석용 필터 데이터 조회 (프로젝트, 작업자, 작업유형 목록)
|
||||||
|
router.get('/filters', workReportAnalysisController.getAnalysisFilters);
|
||||||
|
|
||||||
|
// 📊 기간별 종합 분석
|
||||||
|
router.get('/period', workReportAnalysisController.getAnalyticsByPeriod);
|
||||||
|
|
||||||
|
// 📈 프로젝트별 상세 분석
|
||||||
|
router.get('/project', workReportAnalysisController.getProjectAnalysis);
|
||||||
|
|
||||||
|
// 👤 작업자별 상세 분석
|
||||||
|
router.get('/worker', workReportAnalysisController.getWorkerAnalysis);
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
1134
daily_work_reports.sql
Normal file
1134
daily_work_reports.sql
Normal file
File diff suppressed because it is too large
Load Diff
120
docker-compose.yml.new
Normal file
120
docker-compose.yml.new
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
version: "3.8"
|
||||||
|
|
||||||
|
services:
|
||||||
|
# MariaDB 데이터베이스
|
||||||
|
db:
|
||||||
|
image: mariadb:10.9
|
||||||
|
container_name: tkfb_db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=tkfb2024!
|
||||||
|
- MYSQL_DATABASE=hyungi
|
||||||
|
- MYSQL_USER=hyungi_user
|
||||||
|
- MYSQL_PASSWORD=hyungi2024!
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
- ./api.hyungi.net/migrations:/docker-entrypoint-initdb.d
|
||||||
|
ports:
|
||||||
|
- "20306:3306"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
|
timeout: 20s
|
||||||
|
retries: 10
|
||||||
|
networks:
|
||||||
|
- tkfb_network
|
||||||
|
|
||||||
|
# Node.js API 서버
|
||||||
|
api:
|
||||||
|
build:
|
||||||
|
context: ./api.hyungi.net
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: tkfb_api
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "20005:3005"
|
||||||
|
environment:
|
||||||
|
- NODE_ENV=production
|
||||||
|
- PORT=3005
|
||||||
|
- DB_HOST=db
|
||||||
|
- DB_PORT=3306
|
||||||
|
- DB_USER=hyungi_user
|
||||||
|
- DB_PASSWORD=hyungi2024!
|
||||||
|
- DB_NAME=hyungi
|
||||||
|
- DB_ROOT_PASSWORD=tkfb2024!
|
||||||
|
- JWT_SECRET=tkfb_jwt_secret_2024_hyungi_secure_key
|
||||||
|
volumes:
|
||||||
|
- ./api.hyungi.net/public/img:/usr/src/app/public/img:ro
|
||||||
|
- ./api.hyungi.net/uploads:/usr/src/app/uploads
|
||||||
|
- ./api.hyungi.net/logs:/usr/src/app/logs
|
||||||
|
- ./api.hyungi.net/routes:/usr/src/app/routes
|
||||||
|
- ./api.hyungi.net/controllers:/usr/src/app/controllers
|
||||||
|
- ./api.hyungi.net/models:/usr/src/app/models
|
||||||
|
- ./api.hyungi.net/index.js:/usr/src/app/index.js
|
||||||
|
logging:
|
||||||
|
driver: "json-file"
|
||||||
|
options:
|
||||||
|
max-size: "10m"
|
||||||
|
max-file: "3"
|
||||||
|
networks:
|
||||||
|
- tkfb_network
|
||||||
|
|
||||||
|
# Web UI (Nginx)
|
||||||
|
web:
|
||||||
|
build:
|
||||||
|
context: ./web-ui
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: tkfb_web
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "20000:80"
|
||||||
|
volumes:
|
||||||
|
- ./web-ui:/usr/share/nginx/html:ro
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- tkfb_network
|
||||||
|
|
||||||
|
# FastAPI Bridge
|
||||||
|
fastapi:
|
||||||
|
build:
|
||||||
|
context: ./fastapi-bridge
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
container_name: tkfb_fastapi
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "20008:8000"
|
||||||
|
environment:
|
||||||
|
- API_BASE_URL=http://api:3005
|
||||||
|
depends_on:
|
||||||
|
- api
|
||||||
|
networks:
|
||||||
|
- tkfb_network
|
||||||
|
|
||||||
|
# phpMyAdmin
|
||||||
|
phpmyadmin:
|
||||||
|
image: phpmyadmin/phpmyadmin:latest
|
||||||
|
container_name: tkfb_phpmyadmin
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "20080:80"
|
||||||
|
environment:
|
||||||
|
- PMA_HOST=db
|
||||||
|
- PMA_USER=root
|
||||||
|
- PMA_PASSWORD=tkfb2024!
|
||||||
|
- UPLOAD_LIMIT=50M
|
||||||
|
networks:
|
||||||
|
- tkfb_network
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
|
driver: local
|
||||||
|
|
||||||
|
networks:
|
||||||
|
tkfb_network:
|
||||||
|
driver: bridge
|
||||||
|
name: tkfb_network
|
||||||
@@ -1,26 +1,21 @@
|
|||||||
FROM python:3.11-slim
|
FROM python:3.9-slim
|
||||||
|
|
||||||
# 작업 디렉토리 설정
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# 시스템 패키지 업데이트
|
# 시스템 패키지 업데이트 및 필요한 패키지 설치
|
||||||
RUN apt-get update && apt-get install -y \
|
RUN apt-get update && apt-get install -y \
|
||||||
curl \
|
gcc \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
# Python 의존성 설치
|
# Python 의존성 설치
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# 소스 코드 복사
|
# 애플리케이션 코드 복사
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# 포트 노출
|
# 포트 노출
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
# 헬스체크
|
# 애플리케이션 실행
|
||||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
|
||||||
CMD curl -f http://localhost:8000/health || exit 1
|
|
||||||
|
|
||||||
# 앱 실행
|
|
||||||
CMD ["python", "main.py"]
|
|
||||||
Binary file not shown.
4902
hyungi.sql.backup
Normal file
4902
hyungi.sql.backup
Normal file
File diff suppressed because it is too large
Load Diff
14
json(백업)/IssueTypes.json
Normal file
14
json(백업)/IssueTypes.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"IssueTypes","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"issue_type_id":"1","category":"구매팀","subcategory":"자재입고지연"},
|
||||||
|
{"issue_type_id":"2","category":"구매팀","subcategory":"자재전달 미흡"},
|
||||||
|
{"issue_type_id":"3","category":"품질","subcategory":"검사 내용 전달 미흡"},
|
||||||
|
{"issue_type_id":"4","category":"품질","subcategory":"검사오류"},
|
||||||
|
{"issue_type_id":"5","category":"설계","subcategory":"설계미스(치수)"},
|
||||||
|
{"issue_type_id":"6","category":"설계","subcategory":"설계미스(작업불가)"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
20
json(백업)/Projects.json
Normal file
20
json(백업)/Projects.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"Projects","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"project_id":"1","job_no":"TKO-24008P","project_name":"YHP Project","contract_date":"2024-05-16","due_date":"2025-05-16","delivery_method":"FOB","site":"Quang Ninh(Vietnam)","pm":"장형태","created_at":"2025-04-15 22:40:28","updated_at":"2025-04-15 22:40:28"},
|
||||||
|
{"project_id":"2","job_no":"TKG-24009P","project_name":"한화에어로스페이스 순천","contract_date":"2024-06-05","due_date":"2025-05-31","delivery_method":".","site":"순천","pm":"장형태","created_at":"2025-04-15 22:42:41","updated_at":"2025-04-15 22:42:41"},
|
||||||
|
{"project_id":"3","job_no":"TKG-24011P","project_name":"효성화학 에틸렌 탱크 건설공사","contract_date":"2024-06-22","due_date":"2025-12-25","delivery_method":".","site":"울산","pm":"김길종","created_at":"2025-04-15 22:43:53","updated_at":"2025-04-15 22:43:53"},
|
||||||
|
{"project_id":"4","job_no":"TKG-24013P","project_name":"김천 솔라 파워 그린 수소 Project","contract_date":"2024-10-08","due_date":"2025-07-25","delivery_method":".","site":"김천","pm":"김길종","created_at":"2025-04-15 22:44:57","updated_at":"2025-04-15 22:44:57"},
|
||||||
|
{"project_id":"5","job_no":"TKG-24016P","project_name":"LG Chem P3RE Project","contract_date":"2024-11-27","due_date":"2025-09-30","delivery_method":".","site":".","pm":"장형태","created_at":"2025-04-15 22:46:36","updated_at":"2025-04-15 22:46:36"},
|
||||||
|
{"project_id":"7","job_no":"TKO-25003F","project_name":"25년 안전보건시설설비","contract_date":"2025-01-03","due_date":"2025-12-31","delivery_method":".","site":".","pm":".","created_at":"2025-04-15 22:47:32","updated_at":"2025-04-15 22:47:32"},
|
||||||
|
{"project_id":"8","job_no":"TKG-25007P","project_name":"P Project","contract_date":"2025-01-16","due_date":"2025-10-31","delivery_method":".","site":"오창읍","pm":"장형태","created_at":"2025-04-15 22:48:50","updated_at":"2025-04-15 22:48:50"},
|
||||||
|
{"project_id":"10","job_no":"TKR-25008P","project_name":"DIG Airgas LG CHEM","contract_date":"2025-01-23","due_date":"2025-10-15","delivery_method":".","site":"여수","pm":"서태원","created_at":"2025-04-15 22:50:05","updated_at":"2025-04-15 22:50:05"},
|
||||||
|
{"project_id":"11","job_no":"TKR-25010P","project_name":"FK FISCHER Project","contract_date":"2025-03-12","due_date":"2025-11-30","delivery_method":".","site":"울산","pm":"전상신","created_at":"2025-04-15 22:51:12","updated_at":"2025-04-15 22:51:12"},
|
||||||
|
{"project_id":"12","job_no":"TKO-24007P","project_name":"MP7 Project","contract_date":"2024-07-03","due_date":"2025-01-05","delivery_method":".","site":".","pm":"윤지민","created_at":"2025-04-15 23:56:26","updated_at":"2025-04-15 23:56:26"},
|
||||||
|
{"project_id":"13","job_no":"연차\/휴무","project_name":"연차\/휴무","contract_date":"2025-01-01","due_date":"2025-12-31","delivery_method":".","site":".","pm":".","created_at":"2025-04-16 01:58:23","updated_at":"2025-04-16 01:58:23"},
|
||||||
|
{"project_id":"14","job_no":"TKO-25009R","project_name":"M Project","contract_date":"2025-08-01","due_date":"2025-12-31","delivery_method":"","site":"","pm":"이민후","created_at":"2025-09-28 22:13:33","updated_at":"2025-09-28 22:13:33"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
20
json(백업)/Tasks.json
Normal file
20
json(백업)/Tasks.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"Tasks","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"task_id":"1","category":"Base","subcategory":"Fabrication","task_name":"용접","description":"...","created_at":"2025-04-15 10:41:43","updated_at":"2025-04-15 10:41:43"},
|
||||||
|
{"task_id":"3","category":"Vessel","subcategory":"MI and Marking","task_name":"Marking","description":"..","created_at":"2025-04-15 22:25:58","updated_at":"2025-04-15 22:25:58"},
|
||||||
|
{"task_id":"4","category":"Vessel","subcategory":"Cutting","task_name":"자재 커팅","description":"..","created_at":"2025-04-15 22:26:17","updated_at":"2025-04-15 22:26:17"},
|
||||||
|
{"task_id":"5","category":"Vessel","subcategory":"Fabrication","task_name":"용접","description":"..","created_at":"2025-04-15 22:26:43","updated_at":"2025-04-15 22:26:43"},
|
||||||
|
{"task_id":"7","category":"PKG","subcategory":"Pipe Pre-Fabrication","task_name":"취부&용접","description":"배관사 1명\n용접사 1명","created_at":"2025-04-15 22:37:14","updated_at":"2025-04-15 22:37:14"},
|
||||||
|
{"task_id":"8","category":"PKG","subcategory":"1st Piping Assembly","task_name":"1차 조립","description":".","created_at":"2025-04-15 22:38:49","updated_at":"2025-04-15 22:38:49"},
|
||||||
|
{"task_id":"9","category":"PKG","subcategory":"Re-Assembly","task_name":"재조립","description":".","created_at":"2025-04-15 22:39:18","updated_at":"2025-04-15 22:39:18"},
|
||||||
|
{"task_id":"13","category":"작업지원","subcategory":"구매팀","task_name":".","description":".","created_at":"2025-04-16 03:03:40","updated_at":"2025-04-16 03:03:40"},
|
||||||
|
{"task_id":"14","category":"기타","subcategory":"시설설비제작","task_name":".","description":".","created_at":"2025-04-16 03:30:53","updated_at":"2025-04-16 03:30:53"},
|
||||||
|
{"task_id":"15","category":"기타","subcategory":"휴가\/연차\/휴무","task_name":".","description":".","created_at":"2025-04-16 05:18:13","updated_at":"2025-04-16 05:18:13"},
|
||||||
|
{"task_id":"16","category":"PKG","subcategory":"제품설치","task_name":"설치작업","description":"Skid, 용기 등 설치","created_at":"2025-04-29 04:39:36","updated_at":"2025-04-29 04:39:36"},
|
||||||
|
{"task_id":"18","category":"작업지원","subcategory":"품질팀","task_name":"test지원","description":".","created_at":"2025-06-25 07:07:08","updated_at":"2025-06-25 07:07:08"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
13
json(백업)/Users.json
Normal file
13
json(백업)/Users.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"Users","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"user_id":"1","username":"hyungi","password":"$2b$10$lwSfKipx0fQ.9nfMUBmzt.WXzerdxuT5MVX4b3YhFeHxyYlUjM7bi","role":"admin","created_at":"2025-05-06 05:03:02","access_level":"system","worker_id":null,"is_active":"1","last_login_at":"2025-10-24 23:00:25","password_changed_at":"2025-05-06 05:03:02","failed_login_attempts":"0","locked_until":null,"name":null,"email":null,"updated_at":"2025-10-24 23:00:25"},
|
||||||
|
{"user_id":"3","username":"김두수","password":"$2a$10$z3i2EVOotRFBj.KHzx5LQOKlXD0QHLNFEvJcd6FlO6\/1TCYGk6SSu","role":"leader","created_at":"2025-06-07 23:48:35","access_level":"group_leader","worker_id":"1","is_active":"1","last_login_at":"2025-10-29 06:50:43","password_changed_at":"2025-06-15 07:40:39","failed_login_attempts":"0","locked_until":null,"name":"김두수","email":null,"updated_at":"2025-10-29 06:50:43"},
|
||||||
|
{"user_id":"4","username":"김아무개","password":"$2a$10$QAJIoPyi.apz91exp8GsiO\/prAD5Xwanht6XImP1jvKsy\/7Ba\/b8.","role":"user","created_at":"2025-06-11 08:03:59","access_level":"worker","worker_id":null,"is_active":"1","last_login_at":"2025-06-15 23:28:04","password_changed_at":"2025-06-15 06:03:42","failed_login_attempts":"0","locked_until":null,"name":"김아무개","email":null,"updated_at":"2025-06-15 23:28:04"},
|
||||||
|
{"user_id":"5","username":"임영규","password":"$2a$10$66ps\/MEEi4BVABfJc5P0y.yCap09NhTMyd1A\/7rFVxESytQGlB3wC","role":null,"created_at":"2025-06-15 07:41:02","access_level":"group_leader","worker_id":"3","is_active":"1","last_login_at":"2025-11-01 05:54:49","password_changed_at":"2025-06-15 07:41:02","failed_login_attempts":"0","locked_until":null,"name":"임영규","email":null,"updated_at":"2025-11-01 05:54:49"},
|
||||||
|
{"user_id":"6","username":"반치원","password":"$2a$10$jcn6f7flRLZlr5yKQcXDIePodRK0rsM4deNnNGjuOlredeTVsRYZ6","role":null,"created_at":"2025-06-15 07:41:32","access_level":"group_leader","worker_id":"3","is_active":"1","last_login_at":"2025-10-21 08:46:40","password_changed_at":"2025-06-15 07:41:32","failed_login_attempts":"0","locked_until":null,"name":"반치원","email":null,"updated_at":"2025-10-21 08:46:40"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
1451
json(백업)/WorkReports.json
Normal file
1451
json(백업)/WorkReports.json
Normal file
File diff suppressed because it is too large
Load Diff
18
json(백업)/Workers.json
Normal file
18
json(백업)/Workers.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"Workers","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"worker_id":"1","worker_name":"김두수","join_date":"2025-04-01","job_type":"배관","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:08","updated_at":"2025-04-15 22:23:08"},
|
||||||
|
{"worker_id":"2","worker_name":"임영규","join_date":"2025-04-01","job_type":"배관","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:17","updated_at":"2025-04-15 22:23:17"},
|
||||||
|
{"worker_id":"3","worker_name":"반치원","join_date":"2025-04-01","job_type":"배관","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:22","updated_at":"2025-04-15 22:23:22"},
|
||||||
|
{"worker_id":"4","worker_name":"황인용","join_date":"2025-04-01","job_type":"가공,조공","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:33","updated_at":"2025-04-15 22:23:33"},
|
||||||
|
{"worker_id":"5","worker_name":"표영진","join_date":"2025-04-01","job_type":"가공,조공","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:38","updated_at":"2025-04-15 22:23:38"},
|
||||||
|
{"worker_id":"6","worker_name":"김윤섭","join_date":"2025-04-01","job_type":"용접","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:46","updated_at":"2025-04-15 22:23:46"},
|
||||||
|
{"worker_id":"7","worker_name":"이창호","join_date":"2025-04-01","job_type":"용접,배관","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:51","updated_at":"2025-04-15 22:23:51"},
|
||||||
|
{"worker_id":"8","worker_name":"최광욱","join_date":"2025-04-01","job_type":"용접","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:23:57","updated_at":"2025-04-15 22:23:57"},
|
||||||
|
{"worker_id":"9","worker_name":"박현수","join_date":"2025-04-01","job_type":"용접","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:24:01","updated_at":"2025-04-15 22:24:01"},
|
||||||
|
{"worker_id":"10","worker_name":"조윤호","join_date":"2025-04-01","job_type":"용접","salary":"220000.00","annual_leave":"15","status":"..","created_at":"2025-04-15 22:24:07","updated_at":"2025-04-15 22:24:07"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
1058
json(백업)/daily_work_reports.json
Normal file
1058
json(백업)/daily_work_reports.json
Normal file
File diff suppressed because it is too large
Load Diff
14
json(백업)/error_types.json
Normal file
14
json(백업)/error_types.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"error_types","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"id":"1","name":"설계미스","description":"설계미스","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-16 03:02:03"},
|
||||||
|
{"id":"2","name":"외주작업 불량","description":"입고 자재 불량","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-16 03:02:05"},
|
||||||
|
{"id":"3","name":"입고지연","description":"자재 미입고","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-16 03:02:11"},
|
||||||
|
{"id":"4","name":"작업불량","description":"작업자 실수","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-16 03:02:13"},
|
||||||
|
{"id":"5","name":"설비고장","description":"장비없음","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-16 03:02:16"},
|
||||||
|
{"id":"6","name":"검사불량","description":"검사불량","severity":"medium","solution_guide":null,"created_at":"2025-06-16 02:21:32","updated_at":"2025-06-24 04:36:18"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
378
json(백업)/login_logs.json
Normal file
378
json(백업)/login_logs.json
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"login_logs","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"log_id":"1","user_id":"3","login_time":"2025-06-15 05:58:39","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"3","user_id":"4","login_time":"2025-06-15 06:04:06","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"4","user_id":"3","login_time":"2025-06-15 06:24:53","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"5","user_id":"3","login_time":"2025-06-15 06:24:55","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"6","user_id":"3","login_time":"2025-06-15 06:32:41","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"7","user_id":"3","login_time":"2025-06-15 07:03:19","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"8","user_id":"3","login_time":"2025-06-15 07:03:21","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"9","user_id":"3","login_time":"2025-06-15 07:03:25","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"10","user_id":"1","login_time":"2025-06-15 07:40:16","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"11","user_id":"6","login_time":"2025-06-15 07:42:02","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"12","user_id":"3","login_time":"2025-06-15 07:43:30","logout_time":null,"ip_address":"118.235.6.135","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"13","user_id":"3","login_time":"2025-06-15 22:02:59","logout_time":null,"ip_address":"118.235.6.29","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"14","user_id":"4","login_time":"2025-06-15 22:15:25","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"15","user_id":"3","login_time":"2025-06-15 22:15:34","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"16","user_id":"6","login_time":"2025-06-15 22:15:35","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"17","user_id":"6","login_time":"2025-06-15 22:15:52","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"18","user_id":"3","login_time":"2025-06-15 22:16:39","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"19","user_id":"3","login_time":"2025-06-15 22:17:14","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"20","user_id":"6","login_time":"2025-06-15 22:21:44","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"21","user_id":"1","login_time":"2025-06-15 22:21:52","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"22","user_id":"6","login_time":"2025-06-15 22:22:06","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"23","user_id":"5","login_time":"2025-06-15 22:22:44","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"24","user_id":"6","login_time":"2025-06-15 22:23:58","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"25","user_id":"3","login_time":"2025-06-15 22:24:49","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"26","user_id":"3","login_time":"2025-06-15 22:30:18","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"27","user_id":"3","login_time":"2025-06-15 22:31:21","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"28","user_id":"5","login_time":"2025-06-15 22:44:31","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"29","user_id":"4","login_time":"2025-06-15 22:57:51","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"30","user_id":"4","login_time":"2025-06-15 22:57:52","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"31","user_id":"4","login_time":"2025-06-15 22:57:54","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"32","user_id":"4","login_time":"2025-06-15 22:57:55","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"33","user_id":"4","login_time":"2025-06-15 23:11:30","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"34","user_id":"4","login_time":"2025-06-15 23:28:04","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"35","user_id":"3","login_time":"2025-06-15 23:33:35","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"36","user_id":"3","login_time":"2025-06-16 00:58:53","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"37","user_id":"3","login_time":"2025-06-16 01:15:46","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"38","user_id":"5","login_time":"2025-06-16 01:16:43","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"39","user_id":"1","login_time":"2025-06-16 01:25:57","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"40","user_id":"1","login_time":"2025-06-16 01:26:08","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"41","user_id":"3","login_time":"2025-06-16 02:27:20","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"42","user_id":"3","login_time":"2025-06-16 02:45:59","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"43","user_id":"3","login_time":"2025-06-16 03:04:13","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"44","user_id":"3","login_time":"2025-06-16 03:17:28","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"45","user_id":"5","login_time":"2025-06-16 03:17:55","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"46","user_id":"3","login_time":"2025-06-16 03:18:56","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"47","user_id":"5","login_time":"2025-06-16 03:19:13","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"48","user_id":"1","login_time":"2025-06-16 03:55:56","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"49","user_id":"1","login_time":"2025-06-16 04:24:37","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"50","user_id":"1","login_time":"2025-06-16 04:51:36","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"51","user_id":"1","login_time":"2025-06-16 05:07:05","logout_time":null,"ip_address":"118.235.7.233","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"52","user_id":"1","login_time":"2025-06-16 05:07:59","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"53","user_id":"1","login_time":"2025-06-16 05:43:14","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"54","user_id":"5","login_time":"2025-06-16 06:11:09","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"55","user_id":"1","login_time":"2025-06-16 06:19:46","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"56","user_id":"1","login_time":"2025-06-16 06:23:35","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"57","user_id":"1","login_time":"2025-06-16 06:39:12","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"58","user_id":"3","login_time":"2025-06-16 06:45:26","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"59","user_id":"6","login_time":"2025-06-16 06:46:11","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"60","user_id":"1","login_time":"2025-06-16 21:18:09","logout_time":null,"ip_address":"118.235.7.45","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"61","user_id":"1","login_time":"2025-06-17 08:15:45","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"62","user_id":"5","login_time":"2025-06-17 08:22:58","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"63","user_id":"3","login_time":"2025-06-17 08:23:05","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"64","user_id":"3","login_time":"2025-06-17 08:23:21","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"65","user_id":"3","login_time":"2025-06-17 08:28:02","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"66","user_id":"3","login_time":"2025-06-17 08:32:25","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"67","user_id":"6","login_time":"2025-06-17 08:33:07","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"68","user_id":"1","login_time":"2025-06-17 08:36:01","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"69","user_id":"5","login_time":"2025-06-17 09:00:56","logout_time":null,"ip_address":"118.235.7.173","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"70","user_id":"3","login_time":"2025-06-18 02:30:13","logout_time":null,"ip_address":"118.235.6.77","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"71","user_id":"1","login_time":"2025-06-18 08:07:27","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"72","user_id":"1","login_time":"2025-06-18 08:07:47","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"73","user_id":"5","login_time":"2025-06-18 08:39:59","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"74","user_id":"6","login_time":"2025-06-18 08:46:53","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"75","user_id":"3","login_time":"2025-06-18 08:47:03","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"76","user_id":"6","login_time":"2025-06-18 08:57:48","logout_time":null,"ip_address":"118.235.7.5","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"77","user_id":"5","login_time":"2025-06-18 08:58:14","logout_time":null,"ip_address":"118.235.7.5","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"78","user_id":"3","login_time":"2025-06-18 08:59:12","logout_time":null,"ip_address":"118.235.7.5","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"79","user_id":"5","login_time":"2025-06-19 06:37:35","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"80","user_id":"3","login_time":"2025-06-19 06:57:01","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"81","user_id":"6","login_time":"2025-06-19 06:57:22","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"82","user_id":"5","login_time":"2025-06-19 06:57:56","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"83","user_id":"6","login_time":"2025-06-19 06:58:58","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"84","user_id":"3","login_time":"2025-06-19 06:59:30","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"85","user_id":"3","login_time":"2025-06-20 06:42:26","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"86","user_id":"6","login_time":"2025-06-20 06:45:06","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"87","user_id":"5","login_time":"2025-06-20 06:49:26","logout_time":null,"ip_address":"118.235.7.134","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"88","user_id":"3","login_time":"2025-06-20 06:49:47","logout_time":null,"ip_address":"118.235.7.134","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"89","user_id":"6","login_time":"2025-06-20 06:50:17","logout_time":null,"ip_address":"118.235.7.134","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"90","user_id":"3","login_time":"2025-06-20 22:46:20","logout_time":null,"ip_address":"192.168.1.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"91","user_id":"1","login_time":"2025-06-23 05:03:09","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"92","user_id":"6","login_time":"2025-06-23 06:41:16","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"93","user_id":"3","login_time":"2025-06-23 06:49:11","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"94","user_id":"6","login_time":"2025-06-23 06:50:01","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"95","user_id":"5","login_time":"2025-06-23 06:50:28","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"96","user_id":"1","login_time":"2025-06-24 05:24:17","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"97","user_id":"3","login_time":"2025-06-24 05:25:52","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"98","user_id":"1","login_time":"2025-06-24 09:22:29","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"99","user_id":"3","login_time":"2025-06-24 11:09:38","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"100","user_id":"6","login_time":"2025-06-24 11:09:48","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"101","user_id":"5","login_time":"2025-06-24 11:10:23","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"102","user_id":"3","login_time":"2025-06-24 11:11:29","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"103","user_id":"5","login_time":"2025-06-24 11:12:06","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"104","user_id":"6","login_time":"2025-06-24 11:12:31","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"105","user_id":"3","login_time":"2025-06-24 21:41:01","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"106","user_id":"3","login_time":"2025-06-25 04:40:44","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"107","user_id":"3","login_time":"2025-06-25 05:24:57","logout_time":null,"ip_address":"118.235.6.179","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"108","user_id":"1","login_time":"2025-06-25 07:05:20","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"109","user_id":"1","login_time":"2025-06-25 07:06:41","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"110","user_id":"3","login_time":"2025-06-25 07:09:27","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"111","user_id":"3","login_time":"2025-06-25 08:49:02","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"112","user_id":"3","login_time":"2025-06-25 09:20:05","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"113","user_id":"3","login_time":"2025-06-25 09:40:11","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"114","user_id":"3","login_time":"2025-06-25 09:57:27","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"115","user_id":"1","login_time":"2025-06-25 10:11:03","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"116","user_id":"1","login_time":"2025-06-25 10:26:30","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"117","user_id":"1","login_time":"2025-06-25 10:49:29","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"118","user_id":"5","login_time":"2025-06-25 11:07:16","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"119","user_id":"6","login_time":"2025-06-25 11:10:41","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"120","user_id":"6","login_time":"2025-06-25 11:13:55","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"121","user_id":"5","login_time":"2025-06-25 11:14:25","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"122","user_id":"6","login_time":"2025-06-25 11:20:16","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"123","user_id":"1","login_time":"2025-06-25 11:24:57","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"124","user_id":"3","login_time":"2025-06-26 10:27:57","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"125","user_id":"5","login_time":"2025-06-26 11:10:47","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"126","user_id":"6","login_time":"2025-06-26 11:15:57","logout_time":null,"ip_address":"118.235.6.58","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"127","user_id":"3","login_time":"2025-06-26 11:17:07","logout_time":null,"ip_address":"118.235.6.58","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"128","user_id":"5","login_time":"2025-06-26 11:17:40","logout_time":null,"ip_address":"118.235.6.58","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"129","user_id":"6","login_time":"2025-06-26 11:19:00","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"130","user_id":"1","login_time":"2025-06-26 22:15:30","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"131","user_id":"1","login_time":"2025-06-26 22:31:02","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"132","user_id":"1","login_time":"2025-06-26 22:47:22","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"133","user_id":"5","login_time":"2025-06-27 01:52:48","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"134","user_id":"5","login_time":"2025-06-27 01:53:58","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"135","user_id":"3","login_time":"2025-06-27 06:47:09","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"136","user_id":"6","login_time":"2025-06-27 06:48:39","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/137.0.0.0 Safari\/537.36 Edg\/137.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"137","user_id":"3","login_time":"2025-06-27 06:57:15","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"138","user_id":"5","login_time":"2025-06-27 06:57:34","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"139","user_id":"6","login_time":"2025-06-27 06:57:59","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"140","user_id":"3","login_time":"2025-06-27 06:59:04","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"141","user_id":"5","login_time":"2025-06-27 06:59:29","logout_time":null,"ip_address":"123.142.67.74","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"142","user_id":"3","login_time":"2025-07-05 01:25:41","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"143","user_id":"3","login_time":"2025-07-05 01:26:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"144","user_id":"3","login_time":"2025-07-05 01:41:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"145","user_id":"3","login_time":"2025-07-05 01:46:29","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"146","user_id":"3","login_time":"2025-07-05 01:46:57","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"147","user_id":"3","login_time":"2025-07-05 01:47:17","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"148","user_id":"5","login_time":"2025-07-05 01:48:23","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"149","user_id":"3","login_time":"2025-07-05 01:49:42","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"150","user_id":"3","login_time":"2025-07-05 01:50:41","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"151","user_id":"1","login_time":"2025-07-05 01:52:14","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"152","user_id":"3","login_time":"2025-07-05 02:12:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"153","user_id":"3","login_time":"2025-07-05 04:48:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"154","user_id":"5","login_time":"2025-07-05 05:36:08","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"155","user_id":"3","login_time":"2025-07-05 05:52:08","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"156","user_id":"5","login_time":"2025-07-06 05:33:53","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"157","user_id":"3","login_time":"2025-07-06 05:45:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"158","user_id":"1","login_time":"2025-07-07 01:40:15","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"159","user_id":"1","login_time":"2025-07-07 01:40:39","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"160","user_id":"3","login_time":"2025-07-07 01:54:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"161","user_id":"3","login_time":"2025-07-07 02:13:32","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"162","user_id":"1","login_time":"2025-07-07 02:28:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"163","user_id":"3","login_time":"2025-07-07 02:45:15","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"164","user_id":"1","login_time":"2025-07-07 03:33:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"165","user_id":"1","login_time":"2025-07-07 03:51:07","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"166","user_id":"1","login_time":"2025-07-07 03:56:23","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"167","user_id":"1","login_time":"2025-07-07 03:57:20","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"168","user_id":"1","login_time":"2025-07-07 03:58:02","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"169","user_id":"1","login_time":"2025-07-07 03:58:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"170","user_id":"3","login_time":"2025-07-07 04:00:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"171","user_id":"1","login_time":"2025-07-07 04:03:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"172","user_id":"1","login_time":"2025-07-07 04:10:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"173","user_id":"3","login_time":"2025-07-07 04:13:46","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"174","user_id":"1","login_time":"2025-07-07 04:23:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"175","user_id":"3","login_time":"2025-07-07 04:25:09","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"176","user_id":"6","login_time":"2025-07-07 06:48:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"177","user_id":"3","login_time":"2025-07-07 06:51:59","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"178","user_id":"1","login_time":"2025-07-07 23:33:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"179","user_id":"1","login_time":"2025-07-07 23:37:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"180","user_id":"3","login_time":"2025-07-08 06:36:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"181","user_id":"3","login_time":"2025-07-08 06:59:17","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"182","user_id":"3","login_time":"2025-07-09 06:59:29","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"183","user_id":"5","login_time":"2025-07-09 22:07:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"184","user_id":"3","login_time":"2025-07-10 02:09:48","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"185","user_id":"1","login_time":"2025-07-10 02:11:20","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"186","user_id":"3","login_time":"2025-07-10 06:28:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"187","user_id":"3","login_time":"2025-07-10 06:57:12","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"188","user_id":"3","login_time":"2025-07-11 06:59:42","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"189","user_id":"3","login_time":"2025-07-12 05:39:34","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"190","user_id":"3","login_time":"2025-07-12 05:41:00","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"191","user_id":"3","login_time":"2025-07-12 05:58:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"192","user_id":"3","login_time":"2025-07-14 06:45:52","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"193","user_id":"3","login_time":"2025-07-15 00:09:52","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"194","user_id":"5","login_time":"2025-07-15 05:56:33","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"195","user_id":"3","login_time":"2025-07-15 06:56:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"196","user_id":"5","login_time":"2025-07-16 06:45:52","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"197","user_id":"3","login_time":"2025-07-16 06:51:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"198","user_id":"3","login_time":"2025-07-17 06:44:45","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"199","user_id":"5","login_time":"2025-07-17 06:45:54","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"200","user_id":"3","login_time":"2025-07-17 06:58:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"201","user_id":"3","login_time":"2025-07-18 05:54:03","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"202","user_id":"5","login_time":"2025-07-18 06:35:45","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"203","user_id":"5","login_time":"2025-07-21 06:39:22","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"204","user_id":"3","login_time":"2025-07-21 06:53:15","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"205","user_id":"5","login_time":"2025-07-22 06:45:21","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"206","user_id":"3","login_time":"2025-07-22 06:45:41","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"207","user_id":"3","login_time":"2025-07-22 06:46:38","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"208","user_id":"3","login_time":"2025-07-22 06:57:45","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"209","user_id":"5","login_time":"2025-07-23 06:44:46","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"210","user_id":"3","login_time":"2025-07-23 06:44:59","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"211","user_id":"3","login_time":"2025-07-23 06:59:50","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"212","user_id":"5","login_time":"2025-07-24 06:36:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"213","user_id":"3","login_time":"2025-07-24 06:46:42","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"214","user_id":"5","login_time":"2025-07-25 06:44:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"215","user_id":"3","login_time":"2025-07-25 06:44:45","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"216","user_id":"5","login_time":"2025-07-27 21:28:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"217","user_id":"3","login_time":"2025-07-28 06:30:12","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"218","user_id":"3","login_time":"2025-07-28 06:31:32","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"219","user_id":"5","login_time":"2025-07-28 06:32:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"220","user_id":"3","login_time":"2025-07-28 06:54:43","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"221","user_id":"3","login_time":"2025-07-29 06:38:49","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"222","user_id":"1","login_time":"2025-07-30 01:57:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"223","user_id":"1","login_time":"2025-07-30 02:03:46","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"224","user_id":"3","login_time":"2025-07-30 02:04:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"225","user_id":"1","login_time":"2025-07-30 02:20:29","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"226","user_id":"1","login_time":"2025-07-30 02:24:55","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"227","user_id":"3","login_time":"2025-07-30 05:01:07","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"228","user_id":"3","login_time":"2025-07-30 06:50:12","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"229","user_id":"5","login_time":"2025-07-30 06:51:38","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"230","user_id":"1","login_time":"2025-07-30 22:38:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"231","user_id":"5","login_time":"2025-07-31 06:42:33","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"232","user_id":"3","login_time":"2025-07-31 22:23:54","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"233","user_id":"5","login_time":"2025-08-01 04:56:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"234","user_id":"5","login_time":"2025-08-01 04:57:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"235","user_id":"3","login_time":"2025-08-01 05:01:42","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"236","user_id":"5","login_time":"2025-08-07 06:41:51","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"237","user_id":"3","login_time":"2025-08-07 06:43:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"238","user_id":"3","login_time":"2025-08-08 06:44:56","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"239","user_id":"3","login_time":"2025-08-08 06:55:18","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"240","user_id":"5","login_time":"2025-08-08 06:58:09","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"241","user_id":"3","login_time":"2025-08-11 02:06:53","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"242","user_id":"1","login_time":"2025-08-11 04:16:44","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"failed","failure_reason":"invalid_password"},
|
||||||
|
{"log_id":"243","user_id":"1","login_time":"2025-08-11 04:17:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"244","user_id":"3","login_time":"2025-08-11 06:27:03","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"245","user_id":"5","login_time":"2025-08-11 06:45:58","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"246","user_id":"3","login_time":"2025-08-12 06:46:57","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"247","user_id":"6","login_time":"2025-08-13 05:14:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"248","user_id":"3","login_time":"2025-08-13 06:30:59","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"249","user_id":"5","login_time":"2025-08-13 06:35:40","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"250","user_id":"5","login_time":"2025-08-14 02:02:04","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/138.0.0.0 Safari\/537.36 Edg\/138.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"251","user_id":"3","login_time":"2025-08-14 06:34:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"252","user_id":"5","login_time":"2025-08-14 06:38:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"253","user_id":"5","login_time":"2025-08-18 06:21:07","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"254","user_id":"3","login_time":"2025-08-18 06:40:43","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"255","user_id":"6","login_time":"2025-08-18 06:42:10","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"256","user_id":"3","login_time":"2025-08-18 06:47:57","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"257","user_id":"5","login_time":"2025-08-19 08:02:10","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"258","user_id":"6","login_time":"2025-08-19 08:35:46","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"259","user_id":"5","login_time":"2025-08-20 06:19:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"260","user_id":"3","login_time":"2025-08-20 06:42:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"261","user_id":"6","login_time":"2025-08-20 06:43:54","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"262","user_id":"3","login_time":"2025-08-21 06:29:56","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"263","user_id":"5","login_time":"2025-08-21 07:50:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"264","user_id":"6","login_time":"2025-08-21 08:23:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"265","user_id":"5","login_time":"2025-08-22 06:20:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"266","user_id":"5","login_time":"2025-08-22 06:22:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"267","user_id":"3","login_time":"2025-08-22 06:27:17","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"268","user_id":"5","login_time":"2025-08-23 04:56:25","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"269","user_id":"3","login_time":"2025-08-25 06:48:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"270","user_id":"6","login_time":"2025-08-25 06:48:48","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"271","user_id":"5","login_time":"2025-08-26 07:07:36","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"272","user_id":"1","login_time":"2025-08-26 07:11:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"273","user_id":"5","login_time":"2025-08-26 07:27:16","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"274","user_id":"6","login_time":"2025-08-26 08:21:22","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"275","user_id":"3","login_time":"2025-08-27 00:51:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.5 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"276","user_id":"3","login_time":"2025-08-27 06:43:38","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"277","user_id":"5","login_time":"2025-08-27 06:44:44","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"278","user_id":"1","login_time":"2025-08-28 01:48:08","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"279","user_id":"3","login_time":"2025-08-28 01:49:21","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"280","user_id":"3","login_time":"2025-08-28 03:28:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"281","user_id":"6","login_time":"2025-08-28 08:29:27","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"282","user_id":"5","login_time":"2025-08-28 08:37:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"283","user_id":"5","login_time":"2025-08-28 08:44:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"284","user_id":"3","login_time":"2025-08-29 06:45:33","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"285","user_id":"6","login_time":"2025-08-29 06:46:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"286","user_id":"5","login_time":"2025-08-29 21:54:56","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"287","user_id":"3","login_time":"2025-08-30 02:57:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"288","user_id":"5","login_time":"2025-08-30 05:11:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"289","user_id":"3","login_time":"2025-08-30 05:35:51","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"290","user_id":"3","login_time":"2025-09-01 06:17:50","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"291","user_id":"3","login_time":"2025-09-01 23:13:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"292","user_id":"3","login_time":"2025-09-02 03:59:38","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"293","user_id":"3","login_time":"2025-09-02 07:33:36","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"294","user_id":"5","login_time":"2025-09-02 08:15:36","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"295","user_id":"3","login_time":"2025-09-02 23:36:25","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"296","user_id":"3","login_time":"2025-09-03 01:32:24","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"297","user_id":"3","login_time":"2025-09-03 06:32:44","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"298","user_id":"5","login_time":"2025-09-03 06:43:58","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"299","user_id":"6","login_time":"2025-09-04 06:40:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"300","user_id":"5","login_time":"2025-09-04 06:48:15","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"301","user_id":"3","login_time":"2025-09-05 06:39:03","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"302","user_id":"5","login_time":"2025-09-05 22:09:08","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"303","user_id":"5","login_time":"2025-09-06 04:20:51","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"304","user_id":"3","login_time":"2025-09-06 05:27:55","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"305","user_id":"3","login_time":"2025-09-08 06:15:03","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"306","user_id":"5","login_time":"2025-09-08 06:47:15","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"307","user_id":"3","login_time":"2025-09-09 06:02:53","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"308","user_id":"5","login_time":"2025-09-09 06:44:09","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"309","user_id":"3","login_time":"2025-09-10 06:27:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"310","user_id":"5","login_time":"2025-09-10 06:48:23","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"311","user_id":"5","login_time":"2025-09-11 06:36:20","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"312","user_id":"6","login_time":"2025-09-11 06:40:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"313","user_id":"3","login_time":"2025-09-12 06:43:55","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"314","user_id":"3","login_time":"2025-09-13 06:37:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"315","user_id":"5","login_time":"2025-09-13 23:16:18","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"316","user_id":"3","login_time":"2025-09-14 04:47:13","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"317","user_id":"3","login_time":"2025-09-15 06:49:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"318","user_id":"5","login_time":"2025-09-16 06:50:55","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"319","user_id":"5","login_time":"2025-09-17 06:42:49","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"320","user_id":"3","login_time":"2025-09-17 06:44:41","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"321","user_id":"1","login_time":"2025-09-17 23:51:39","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"322","user_id":"3","login_time":"2025-09-18 06:43:14","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"323","user_id":"3","login_time":"2025-09-18 06:46:17","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"324","user_id":"5","login_time":"2025-09-18 06:54:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"325","user_id":"5","login_time":"2025-09-19 06:51:14","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"326","user_id":"5","login_time":"2025-09-20 05:30:00","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"327","user_id":"3","login_time":"2025-09-22 06:46:29","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"328","user_id":"5","login_time":"2025-09-22 06:50:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"329","user_id":"5","login_time":"2025-09-23 05:46:19","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"330","user_id":"3","login_time":"2025-09-23 06:46:57","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"331","user_id":"3","login_time":"2025-09-23 06:47:27","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"332","user_id":"5","login_time":"2025-09-25 01:14:07","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"333","user_id":"3","login_time":"2025-09-25 06:56:18","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (iPhone; CPU iPhone OS 18_6 like Mac OS X) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/26.0 Mobile\/15E148 Safari\/604.1","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"334","user_id":"1","login_time":"2025-09-28 22:11:51","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"335","user_id":"3","login_time":"2025-09-29 06:35:29","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"336","user_id":"3","login_time":"2025-09-30 06:52:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"337","user_id":"5","login_time":"2025-09-30 06:56:12","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"338","user_id":"5","login_time":"2025-10-01 06:55:37","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"339","user_id":"1","login_time":"2025-10-01 23:48:39","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"340","user_id":"3","login_time":"2025-10-02 05:25:11","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"341","user_id":"3","login_time":"2025-10-02 06:21:56","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/140.0.0.0 Safari\/537.36 Edg\/140.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"342","user_id":"1","login_time":"2025-10-06 01:01:56","logout_time":null,"ip_address":"::ffff:172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"343","user_id":"1","login_time":"2025-10-10 23:13:57","logout_time":null,"ip_address":"::ffff:172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"344","user_id":"3","login_time":"2025-10-10 23:32:38","logout_time":null,"ip_address":"::ffff:172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"345","user_id":"3","login_time":"2025-10-12 20:17:04","logout_time":null,"ip_address":"::ffff:172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"346","user_id":"5","login_time":"2025-10-13 06:52:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"347","user_id":"3","login_time":"2025-10-14 06:55:30","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"348","user_id":"5","login_time":"2025-10-14 06:55:31","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"349","user_id":"3","login_time":"2025-10-14 06:56:21","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"350","user_id":"3","login_time":"2025-10-15 06:58:08","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"351","user_id":"3","login_time":"2025-10-16 06:51:22","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"352","user_id":"3","login_time":"2025-10-20 06:48:49","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"353","user_id":"5","login_time":"2025-10-20 06:50:35","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"354","user_id":"3","login_time":"2025-10-20 06:54:32","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"355","user_id":"5","login_time":"2025-10-21 08:42:06","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"356","user_id":"6","login_time":"2025-10-21 08:46:40","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"357","user_id":"5","login_time":"2025-10-22 06:46:43","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"358","user_id":"3","login_time":"2025-10-22 06:47:02","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"359","user_id":"3","login_time":"2025-10-22 06:48:33","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"360","user_id":"3","login_time":"2025-10-24 06:46:33","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"361","user_id":"1","login_time":"2025-10-24 23:00:25","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"362","user_id":"3","login_time":"2025-10-25 05:32:17","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"363","user_id":"3","login_time":"2025-10-27 06:41:27","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"364","user_id":"5","login_time":"2025-10-28 08:44:01","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"365","user_id":"3","login_time":"2025-10-28 08:46:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"366","user_id":"3","login_time":"2025-10-28 22:53:04","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit\/605.1.15 (KHTML, like Gecko) Version\/18.6 Safari\/605.1.15","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"367","user_id":"3","login_time":"2025-10-29 06:50:43","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/141.0.0.0 Safari\/537.36 Edg\/141.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"368","user_id":"5","login_time":"2025-10-29 06:51:26","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"369","user_id":"5","login_time":"2025-10-30 08:47:32","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"370","user_id":"5","login_time":"2025-10-31 06:52:28","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null},
|
||||||
|
{"log_id":"371","user_id":"5","login_time":"2025-11-01 05:54:49","logout_time":null,"ip_address":"172.18.0.1","user_agent":"Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/139.0.0.0 Safari\/537.36 Edg\/139.0.0.0","login_status":"success","failure_reason":null}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
14
json(백업)/password_change_logs.json
Normal file
14
json(백업)/password_change_logs.json
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"password_change_logs","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"log_id":"1","user_id":"4","changed_by_user_id":null,"changed_at":"2025-06-15 06:03:42","change_type":"admin","ip_address":null},
|
||||||
|
{"log_id":"2","user_id":"3","changed_by_user_id":null,"changed_at":"2025-06-15 06:03:52","change_type":"admin","ip_address":null},
|
||||||
|
{"log_id":"3","user_id":"3","changed_by_user_id":"3","changed_at":"2025-06-15 06:32:30","change_type":"self","ip_address":null},
|
||||||
|
{"log_id":"4","user_id":"3","changed_by_user_id":"1","changed_at":"2025-06-15 07:40:39","change_type":"admin","ip_address":null},
|
||||||
|
{"log_id":"5","user_id":"5","changed_by_user_id":"1","changed_at":"2025-06-15 07:41:02","change_type":"initial","ip_address":null},
|
||||||
|
{"log_id":"6","user_id":"6","changed_by_user_id":"1","changed_at":"2025-06-15 07:41:32","change_type":"initial","ip_address":null}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
10
json(백업)/work_status_types.json
Normal file
10
json(백업)/work_status_types.json
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[
|
||||||
|
{"type":"header","version":"5.2.2","comment":"Export to JSON plugin for PHPMyAdmin"},
|
||||||
|
{"type":"database","name":"hyungi"},
|
||||||
|
{"type":"table","name":"work_status_types","database":"hyungi","data":
|
||||||
|
[
|
||||||
|
{"id":"1","name":"정규","description":"정상적으로 완료된 작업","is_error":"0","created_at":"2025-06-16 02:21:16"},
|
||||||
|
{"id":"2","name":"에러","description":"오류가 발생한 작업","is_error":"1","created_at":"2025-06-16 02:21:16"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -56,6 +56,12 @@
|
|||||||
<button class="nav-btn dashboard-btn" title="대시보드">
|
<button class="nav-btn dashboard-btn" title="대시보드">
|
||||||
🏠 대시보드
|
🏠 대시보드
|
||||||
</button>
|
</button>
|
||||||
|
<button class="nav-btn admin-btn" title="관리자 페이지" id="adminBtn" style="display: none;">
|
||||||
|
⚙️ 관리자
|
||||||
|
</button>
|
||||||
|
<button class="nav-btn system-btn" title="시스템 관리자" id="systemBtn" style="display: none;">
|
||||||
|
🔧 시스템
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
@@ -306,6 +312,32 @@
|
|||||||
transform: translateY(-1px);
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-btn {
|
||||||
|
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
||||||
|
color: white;
|
||||||
|
border: 1px solid rgba(255,255,255,0.3);
|
||||||
|
box-shadow: 0 2px 8px rgba(255,107,53,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #ff5722 0%, #ff9800 100%);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(255,107,53,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-btn {
|
||||||
|
background: linear-gradient(135deg, #9c27b0 0%, #673ab7 100%);
|
||||||
|
color: white;
|
||||||
|
border: 1px solid rgba(255,255,255,0.3);
|
||||||
|
box-shadow: 0 2px 8px rgba(156,39,176,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-btn:hover {
|
||||||
|
background: linear-gradient(135deg, #8e24aa 0%, #5e35b1 100%);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 12px rgba(156,39,176,0.4);
|
||||||
|
}
|
||||||
|
|
||||||
/* 반응형 */
|
/* 반응형 */
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
.navbar {
|
.navbar {
|
||||||
@@ -336,7 +368,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.dashboard-btn {
|
.dashboard-btn, .admin-btn, .system-btn {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,5 +44,6 @@
|
|||||||
<li><a href="/pages/issue-reports/daily-issue-report.html">일일 이슈 보고</a></li>
|
<li><a href="/pages/issue-reports/daily-issue-report.html">일일 이슈 보고</a></li>
|
||||||
<li><a href="/pages/issue-reports/issue-summary.html">이슈 현황 요약</a></li>
|
<li><a href="/pages/issue-reports/issue-summary.html">이슈 현황 요약</a></li>
|
||||||
<li><a href="/pages/analysis/daily_work_analysis.html">작업 정보 페이지</a></li>
|
<li><a href="/pages/analysis/daily_work_analysis.html">작업 정보 페이지</a></li>
|
||||||
|
<li><a href="/pages/analysis/work-report-analytics.html" class="admin-only-link">📊 작업보고서 종합분석 <span class="admin-badge">ADMIN</span></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
@@ -22,4 +22,29 @@ h1, h2 {
|
|||||||
a {
|
a {
|
||||||
color: #1976d2;
|
color: #1976d2;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Admin 권한 배지 스타일 */
|
||||||
|
.admin-badge {
|
||||||
|
background: linear-gradient(135deg, #ff6b35 0%, #f7931e 100%);
|
||||||
|
color: white;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 2px 6px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-left: 8px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
|
box-shadow: 0 2px 4px rgba(255,107,53,0.3);
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-only-link {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.admin-only-link:hover .admin-badge {
|
||||||
|
background: linear-gradient(135deg, #ff5722 0%, #ff9800 100%);
|
||||||
|
box-shadow: 0 3px 6px rgba(255,107,53,0.4);
|
||||||
}
|
}
|
||||||
@@ -4,10 +4,174 @@
|
|||||||
.main-layout .content-wrapper {
|
.main-layout .content-wrapper {
|
||||||
background: #ffffff;
|
background: #ffffff;
|
||||||
min-height: calc(100vh - 80px);
|
min-height: calc(100vh - 80px);
|
||||||
padding: 2rem;
|
padding: 0;
|
||||||
border-left: 1px solid #e0e0e0;
|
border-left: 1px solid #e0e0e0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 시스템 관리자 배너 */
|
||||||
|
.system-banner {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 2rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-banner::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="grid" width="10" height="10" patternUnits="userSpaceOnUse"><path d="M 10 0 L 0 0 0 10" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/></pattern></defs><rect width="100" height="100" fill="url(%23grid)"/></svg>');
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 50%;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 2px solid rgba(255,255,255,0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-text h1 {
|
||||||
|
margin: 0 0 0.5rem 0;
|
||||||
|
font-size: 2.2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
text-shadow: 0 2px 4px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-text p {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.1rem;
|
||||||
|
opacity: 0.9;
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-right {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.5rem;
|
||||||
|
background: rgba(255,255,255,0.15);
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
border-radius: 20px;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border: 1px solid rgba(255,255,255,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-btn {
|
||||||
|
background: rgba(255,255,255,0.2);
|
||||||
|
border: 1px solid rgba(255,255,255,0.3);
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.quick-btn:hover {
|
||||||
|
background: rgba(255,255,255,0.3);
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-dot.online {
|
||||||
|
background: #2ecc71;
|
||||||
|
box-shadow: 0 0 10px rgba(46,204,113,0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
50% { opacity: 0.5; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 메인 컨텐츠 패딩 조정 */
|
||||||
|
.main-content {
|
||||||
|
padding: 0 2rem 2rem 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 반응형 배너 */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.system-banner {
|
||||||
|
padding: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-content {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1.5rem;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-left {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.system-icon {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
padding: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-text h1 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-text p {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.banner-right {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
padding: 0 1rem 2rem 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.page-header {
|
.page-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -55,6 +55,18 @@ function populateUserInfo(doc, user) {
|
|||||||
// 드롭다운 메뉴 사용자 아이디
|
// 드롭다운 메뉴 사용자 아이디
|
||||||
const dropdownIdEl = doc.getElementById('dropdown-user-id');
|
const dropdownIdEl = doc.getElementById('dropdown-user-id');
|
||||||
if (dropdownIdEl) dropdownIdEl.textContent = `@${user.username}`;
|
if (dropdownIdEl) dropdownIdEl.textContent = `@${user.username}`;
|
||||||
|
|
||||||
|
// Admin 버튼 표시 여부 결정 (admin 권한만)
|
||||||
|
const adminBtn = doc.getElementById('adminBtn');
|
||||||
|
if (adminBtn && user.role === 'admin') {
|
||||||
|
adminBtn.style.display = 'flex';
|
||||||
|
}
|
||||||
|
|
||||||
|
// System 버튼 표시 여부 결정 (system 권한만)
|
||||||
|
const systemBtn = doc.getElementById('systemBtn');
|
||||||
|
if (systemBtn && user.role === 'system') {
|
||||||
|
systemBtn.style.display = 'flex';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,6 +95,22 @@ function setupNavbarEvents() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Admin 버튼 클릭 이벤트
|
||||||
|
const adminButton = document.getElementById('adminBtn');
|
||||||
|
if (adminButton) {
|
||||||
|
adminButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/pages/dashboard/admin.html';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// System 버튼 클릭 이벤트
|
||||||
|
const systemButton = document.getElementById('systemBtn');
|
||||||
|
if (systemButton) {
|
||||||
|
systemButton.addEventListener('click', () => {
|
||||||
|
window.location.href = '/pages/dashboard/system.html';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// 외부 클릭 시 드롭다운 닫기
|
// 외부 클릭 시 드롭다운 닫기
|
||||||
document.addEventListener('click', (e) => {
|
document.addEventListener('click', (e) => {
|
||||||
|
|||||||
@@ -1,181 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>근태 검증 관리 시스템 | (주)테크니컬코리아</title>
|
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
|
||||||
<link rel="stylesheet" href="/css/attendance-validation.css">
|
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body class="bg-gray-50 min-h-screen">
|
|
||||||
<!-- 네비게이션 바 -->
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="max-w-7xl mx-auto p-6">
|
|
||||||
<!-- 뒤로가기 버튼 -->
|
|
||||||
<a href="javascript:history.back()" class="back-btn">
|
|
||||||
← 뒤로가기
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- 헤더 -->
|
|
||||||
<div class="page-header">
|
|
||||||
<div class="flex items-center justify-between">
|
|
||||||
<div class="flex items-center space-x-3">
|
|
||||||
<span class="text-4xl">👥</span>
|
|
||||||
<div>
|
|
||||||
<h1 class="text-3xl font-bold text-white">근태 검증 관리</h1>
|
|
||||||
<p class="text-lg text-white/90 mt-2">작업자별 근무시간을 검증하고 관리합니다</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-sm text-white/80 bg-white/20 px-4 py-2 rounded-lg">
|
|
||||||
🔒 Admin 전용
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 메시지 영역 -->
|
|
||||||
<div id="message-container"></div>
|
|
||||||
|
|
||||||
<!-- 로딩 화면 -->
|
|
||||||
<div id="loadingScreen" class="hidden">
|
|
||||||
<div class="loading-card">
|
|
||||||
<div class="flex items-center justify-center">
|
|
||||||
<div class="loading-spinner"></div>
|
|
||||||
<span class="ml-3 text-gray-600">데이터를 불러오는 중...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 메인 콘텐츠 -->
|
|
||||||
<div id="mainContent">
|
|
||||||
<!-- 캘린더 섹션 -->
|
|
||||||
<div class="main-card">
|
|
||||||
<!-- 캘린더 헤더 -->
|
|
||||||
<div class="calendar-header">
|
|
||||||
<button id="prevMonth" class="nav-btn">
|
|
||||||
<span class="text-xl">◀</span>
|
|
||||||
</button>
|
|
||||||
<h2 id="currentMonthYear" class="text-2xl font-bold text-gray-800">
|
|
||||||
2025년 6월
|
|
||||||
</h2>
|
|
||||||
<button id="nextMonth" class="nav-btn">
|
|
||||||
<span class="text-xl">▶</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 월간 요약 정보 -->
|
|
||||||
<div class="summary-section">
|
|
||||||
<h3 class="summary-title">이번 달 요약</h3>
|
|
||||||
<div class="summary-grid">
|
|
||||||
<div class="summary-card normal">
|
|
||||||
<div id="normalCount" class="summary-number">0</div>
|
|
||||||
<div class="summary-label">✅ 정상</div>
|
|
||||||
</div>
|
|
||||||
<div class="summary-card warning">
|
|
||||||
<div id="reviewCount" class="summary-number">0</div>
|
|
||||||
<div class="summary-label">⚠️ 검토필요</div>
|
|
||||||
</div>
|
|
||||||
<div class="summary-card error">
|
|
||||||
<div id="missingCount" class="summary-number">0</div>
|
|
||||||
<div class="summary-label">❌ 미입력</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 요일 헤더 -->
|
|
||||||
<div class="weekday-header">
|
|
||||||
<div class="weekday sunday">일</div>
|
|
||||||
<div class="weekday">월</div>
|
|
||||||
<div class="weekday">화</div>
|
|
||||||
<div class="weekday">수</div>
|
|
||||||
<div class="weekday">목</div>
|
|
||||||
<div class="weekday">금</div>
|
|
||||||
<div class="weekday saturday">토</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 캘린더 본체 -->
|
|
||||||
<div id="calendarGrid" class="calendar-grid">
|
|
||||||
<!-- 동적으로 생성됨 -->
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 범례 -->
|
|
||||||
<div class="legend">
|
|
||||||
<div class="legend-item">
|
|
||||||
<div class="legend-dot normal"></div>
|
|
||||||
<span>정상</span>
|
|
||||||
</div>
|
|
||||||
<div class="legend-item">
|
|
||||||
<div class="legend-dot warning"></div>
|
|
||||||
<span>검토필요</span>
|
|
||||||
</div>
|
|
||||||
<div class="legend-item">
|
|
||||||
<div class="legend-dot error"></div>
|
|
||||||
<span>미입력</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 성능 상태 표시 (개발용) -->
|
|
||||||
<div id="performanceStatus" class="text-xs text-gray-500 text-center mt-4 hidden">
|
|
||||||
<div class="bg-gray-100 rounded-lg p-2">
|
|
||||||
🔄 순차 호출: <span id="activeReq">0</span>개 처리 중 |
|
|
||||||
📦 캐시: <span id="cacheCount">0</span>개 저장됨 |
|
|
||||||
⏳ 대기: <span id="queueCount">0</span>개 |
|
|
||||||
🚫 429 에러 방지 (2초 딜레이)
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 작업자 리스트 섹션 -->
|
|
||||||
<div id="workersList" class="main-card">
|
|
||||||
<div class="empty-state">
|
|
||||||
<div class="empty-icon">🔄</div>
|
|
||||||
<h3 class="empty-title">날짜를 클릭해주세요</h3>
|
|
||||||
<p class="empty-description">
|
|
||||||
캘린더에서 날짜를 클릭하면 해당 날짜의 작업자 검증 내역을 확인할 수 있습니다.<br>
|
|
||||||
<strong>순차 호출 방식</strong>으로 안정적이지만 약 5초의 로딩 시간이 있습니다.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 수정 모달 -->
|
|
||||||
<div id="editModal" class="modal hidden">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h3>✏️ 근무시간 수정</h3>
|
|
||||||
<button class="close-btn" onclick="closeEditModal()">×</button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group">
|
|
||||||
<label>👤 작업자</label>
|
|
||||||
<input type="text" id="editWorkerName" class="form-input" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>📊 현재 상태</label>
|
|
||||||
<input type="text" id="editWorkerStatus" class="form-input" readonly>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>⏰ 근무시간 (시간)</label>
|
|
||||||
<input type="number" id="editWorkHours" class="form-input"
|
|
||||||
min="0" max="24" step="0.5" placeholder="근무시간을 입력하세요">
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label>📝 수정 사유</label>
|
|
||||||
<textarea id="editReason" class="form-textarea"
|
|
||||||
placeholder="수정 사유를 입력하세요 (선택사항)"></textarea>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button class="btn-secondary" onclick="closeEditModal()">취소</button>
|
|
||||||
<button class="btn-primary" onclick="saveEditedWork()">💾 저장</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script src="/js/attendance-validation.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>공장 지도 등록</title>
|
|
||||||
<link rel="stylesheet" href="/css/admin.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="navbar-placeholder"></div>
|
|
||||||
<div class="container">
|
|
||||||
<h2>공장 지도 등록</h2>
|
|
||||||
<form id="uploadForm">
|
|
||||||
<input type="text" name="factory_name" placeholder="공장명" required>
|
|
||||||
<input type="text" name="address" placeholder="주소" required>
|
|
||||||
<textarea name="description" placeholder="설명" required></textarea>
|
|
||||||
<input type="file" name="map_image" accept="image/*" required>
|
|
||||||
<button type="submit">등록</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<script src="/js/load-navbar.js"></script>
|
|
||||||
<script src="/js/admin/factory-upload.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>파이프 스펙 관리 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/admin.css" />
|
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout">
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div id="sidebar-container"></div>
|
|
||||||
|
|
||||||
<div id="content-container">
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>🧪 파이프 스펙 관리</h1>
|
|
||||||
<p class="subtitle">배관 사양 정보를 등록하고 관리합니다.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<h3>새 파이프 스펙 등록</h3>
|
|
||||||
<form id="specForm" class="form-horizontal">
|
|
||||||
<div class="form-row">
|
|
||||||
<input type="text" id="material" placeholder="재질 (예: STS304)" required />
|
|
||||||
<input type="text" id="diameter_in" placeholder="직경 (예: 1, 1/2)" required />
|
|
||||||
<input type="text" id="schedule" placeholder="스케줄 (예: SCH40)" required />
|
|
||||||
<button type="submit" class="btn btn-primary">등록</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<h3>등록된 파이프 스펙</h3>
|
|
||||||
<div class="table-responsive">
|
|
||||||
<table class="data-table">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>ID</th>
|
|
||||||
<th>스펙</th>
|
|
||||||
<th>작업</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody id="specTableBody">
|
|
||||||
<tr><td colspan="3" class="text-center">불러오는 중...</td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script type="module" src="/js/load-sidebar.js"></script>
|
|
||||||
<script type="module" src="/js/manage-pipespec.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>작업 검토 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/work-review.css">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout-with-navbar">
|
|
||||||
<!-- 네비게이션 바 -->
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div class="review-container">
|
|
||||||
<!-- 뒤로가기 버튼 -->
|
|
||||||
<a href="javascript:history.back()" class="back-btn">
|
|
||||||
← 뒤로가기
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- 페이지 헤더 -->
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>📋 작업 검토 대시보드</h1>
|
|
||||||
<p class="subtitle">캘린더에서 날짜를 클릭하여 해당 날짜의 작업 현황을 확인하고 검토하세요</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 메시지 영역 -->
|
|
||||||
<div id="message-container"></div>
|
|
||||||
|
|
||||||
<!-- 컨트롤 패널 -->
|
|
||||||
<div class="control-panel">
|
|
||||||
<div class="month-navigation">
|
|
||||||
<button class="nav-btn" id="prevMonth">‹ 이전</button>
|
|
||||||
<div class="current-month" id="currentMonth">2025년 6월</div>
|
|
||||||
<button class="nav-btn" id="nextMonth">다음 ›</button>
|
|
||||||
</div>
|
|
||||||
<div class="control-actions">
|
|
||||||
<button class="today-btn" id="goToday">📅 오늘</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 사용법 안내 -->
|
|
||||||
<div class="usage-guide">
|
|
||||||
<h3>📖 사용법</h3>
|
|
||||||
<div class="guide-grid">
|
|
||||||
<div class="guide-item">
|
|
||||||
<div class="guide-icon">👆</div>
|
|
||||||
<div class="guide-text">
|
|
||||||
<strong>날짜 클릭</strong><br>
|
|
||||||
캘린더에서 날짜를 클릭하면 해당 날짜의 작업 정보를 확인할 수 있습니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="guide-item">
|
|
||||||
<div class="guide-icon">✏️</div>
|
|
||||||
<div class="guide-text">
|
|
||||||
<strong>작업 수정</strong><br>
|
|
||||||
각 작업 항목의 수정 버튼을 클릭하여 프로젝트, 작업 유형, 시간 등을 수정할 수 있습니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="guide-item">
|
|
||||||
<div class="guide-icon">🗑️</div>
|
|
||||||
<div class="guide-text">
|
|
||||||
<strong>작업 삭제</strong><br>
|
|
||||||
개별 작업 또는 작업자의 모든 작업을 삭제할 수 있습니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="guide-item">
|
|
||||||
<div class="guide-icon">✅</div>
|
|
||||||
<div class="guide-text">
|
|
||||||
<strong>검토 완료</strong><br>
|
|
||||||
작업 검토가 완료되면 검토 완료 버튼을 클릭하여 상태를 변경할 수 있습니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 캘린더 -->
|
|
||||||
<div class="calendar-container">
|
|
||||||
<h3 style="margin-bottom: 1rem;">📅 캘린더</h3>
|
|
||||||
<div class="calendar-grid" id="calendar">
|
|
||||||
<!-- 요일 헤더 -->
|
|
||||||
<div class="day-header">일</div>
|
|
||||||
<div class="day-header">월</div>
|
|
||||||
<div class="day-header">화</div>
|
|
||||||
<div class="day-header">수</div>
|
|
||||||
<div class="day-header">목</div>
|
|
||||||
<div class="day-header">금</div>
|
|
||||||
<div class="day-header">토</div>
|
|
||||||
<!-- 날짜 셀들이 여기에 동적으로 추가됩니다 -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 선택된 날짜 정보 -->
|
|
||||||
<div class="day-info-panel">
|
|
||||||
<div id="day-info-container">
|
|
||||||
<!-- 날짜별 정보가 여기에 동적으로 추가됩니다 -->
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 스크립트 -->
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script src="/js/work-review.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
672
web-ui/pages/analysis/project-worktype-analysis.html
Normal file
672
web-ui/pages/analysis/project-worktype-analysis.html
Normal file
@@ -0,0 +1,672 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="ko">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>프로젝트별 작업 시간 분석</title>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<style>
|
||||||
|
.project-card {
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
border-left: 4px solid #3B82F6;
|
||||||
|
}
|
||||||
|
.project-card:hover {
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 10px 25px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
.work-type-row {
|
||||||
|
transition: background-color 0.2s ease;
|
||||||
|
}
|
||||||
|
.work-type-row:hover {
|
||||||
|
background-color: #f8fafc;
|
||||||
|
}
|
||||||
|
.error-high { border-left-color: #EF4444; }
|
||||||
|
.error-medium { border-left-color: #F59E0B; }
|
||||||
|
.error-low { border-left-color: #10B981; }
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
transition: width 0.8s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-spinner {
|
||||||
|
border: 3px solid #f3f3f3;
|
||||||
|
border-top: 3px solid #3498db;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.error {
|
||||||
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.regular {
|
||||||
|
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-card.total {
|
||||||
|
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="bg-gray-50 min-h-screen">
|
||||||
|
<!-- 헤더 -->
|
||||||
|
<header class="bg-white shadow-lg border-b">
|
||||||
|
<div class="container mx-auto px-6 py-4">
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div>
|
||||||
|
<h1 class="text-3xl font-bold text-gray-800">🏗️ 프로젝트별 작업 시간 분석</h1>
|
||||||
|
<p class="text-gray-600 mt-1">총시간 · 정규시간 · 에러시간 상세 분석</p>
|
||||||
|
<div class="mt-2">
|
||||||
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800">
|
||||||
|
🔧 시스템 관리자 전용
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-4">
|
||||||
|
<div class="text-sm text-gray-500">
|
||||||
|
<span id="last-updated">마지막 업데이트: -</span>
|
||||||
|
</div>
|
||||||
|
<button id="refresh-btn" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg transition-colors">
|
||||||
|
🔄 새로고침
|
||||||
|
</button>
|
||||||
|
<button onclick="history.back()" class="bg-gray-500 hover:bg-gray-600 text-white px-4 py-2 rounded-lg transition-colors">
|
||||||
|
← 뒤로가기
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<!-- 날짜 선택 -->
|
||||||
|
<div class="container mx-auto px-6 py-6">
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6 mb-6">
|
||||||
|
<div class="flex flex-wrap items-center gap-4">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<label for="start-date" class="text-sm font-medium text-gray-700">시작일:</label>
|
||||||
|
<input type="date" id="start-date" class="border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<label for="end-date" class="text-sm font-medium text-gray-700">종료일:</label>
|
||||||
|
<input type="date" id="end-date" class="border border-gray-300 rounded-md px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:border-transparent">
|
||||||
|
</div>
|
||||||
|
<button id="analyze-btn" class="bg-green-500 hover:bg-green-600 text-white px-6 py-2 rounded-md text-sm font-medium transition-colors">
|
||||||
|
📊 분석 실행
|
||||||
|
</button>
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<button id="preset-week" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-3 py-1 rounded text-xs">최근 1주일</button>
|
||||||
|
<button id="preset-month" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-3 py-1 rounded text-xs">최근 1개월</button>
|
||||||
|
<button id="preset-august" class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-3 py-1 rounded text-xs">8월 전체</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 로딩 화면 -->
|
||||||
|
<div id="loading" class="hidden fixed inset-0 bg-white bg-opacity-90 flex items-center justify-center z-50">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="loading-spinner mx-auto mb-4"></div>
|
||||||
|
<p class="text-gray-600">데이터를 분석하는 중...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 메인 컨테이너 -->
|
||||||
|
<div class="container mx-auto px-6 pb-8" id="main-content">
|
||||||
|
|
||||||
|
<!-- 전체 요약 통계 -->
|
||||||
|
<div id="summary-stats" class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8 hidden">
|
||||||
|
<div class="stat-card total rounded-lg shadow-md p-6 text-center">
|
||||||
|
<div class="text-3xl font-bold" id="total-hours">-</div>
|
||||||
|
<div class="text-sm opacity-90">총 작업시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card regular rounded-lg shadow-md p-6 text-center">
|
||||||
|
<div class="text-3xl font-bold" id="regular-hours">-</div>
|
||||||
|
<div class="text-sm opacity-90">정규 시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card error rounded-lg shadow-md p-6 text-center">
|
||||||
|
<div class="text-3xl font-bold" id="error-hours">-</div>
|
||||||
|
<div class="text-sm opacity-90">에러 시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="stat-card rounded-lg shadow-md p-6 text-center">
|
||||||
|
<div class="text-3xl font-bold" id="error-rate">-</div>
|
||||||
|
<div class="text-sm opacity-90">전체 에러율</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 차트 섹션 -->
|
||||||
|
<div id="charts-section" class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8 hidden">
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">프로젝트별 시간 분포</h3>
|
||||||
|
<canvas id="project-chart"></canvas>
|
||||||
|
</div>
|
||||||
|
<div class="bg-white rounded-lg shadow-md p-6">
|
||||||
|
<h3 class="text-lg font-semibold mb-4">에러율 분석</h3>
|
||||||
|
<canvas id="error-chart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 프로젝트별 상세 데이터 -->
|
||||||
|
<div id="projects-container" class="space-y-6">
|
||||||
|
<!-- 프로젝트 카드들이 여기에 동적으로 생성됩니다 -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 데이터 없음 메시지 -->
|
||||||
|
<div id="no-data" class="hidden text-center py-12">
|
||||||
|
<div class="text-gray-400 text-6xl mb-4">📊</div>
|
||||||
|
<h3 class="text-xl font-semibold text-gray-600 mb-2">분석할 데이터가 없습니다</h3>
|
||||||
|
<p class="text-gray-500">날짜 범위를 선택하고 분석을 실행해주세요.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 기존 인증 시스템 사용 -->
|
||||||
|
<script>
|
||||||
|
// 전역 변수
|
||||||
|
let analysisData = null;
|
||||||
|
let charts = {};
|
||||||
|
|
||||||
|
// API 호출 함수 (토큰 포함)
|
||||||
|
async function apiCall(endpoint, options = {}) {
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token) {
|
||||||
|
throw new Error('인증 토큰이 없습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultHeaders = {
|
||||||
|
'Authorization': `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await fetch(`http://localhost:20005/api${endpoint}`, {
|
||||||
|
...options,
|
||||||
|
headers: {
|
||||||
|
...defaultHeaders,
|
||||||
|
...options.headers
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
// DOM 요소들
|
||||||
|
const elements = {
|
||||||
|
startDate: document.getElementById('start-date'),
|
||||||
|
endDate: document.getElementById('end-date'),
|
||||||
|
analyzeBtn: document.getElementById('analyze-btn'),
|
||||||
|
refreshBtn: document.getElementById('refresh-btn'),
|
||||||
|
loading: document.getElementById('loading'),
|
||||||
|
mainContent: document.getElementById('main-content'),
|
||||||
|
summaryStats: document.getElementById('summary-stats'),
|
||||||
|
chartsSection: document.getElementById('charts-section'),
|
||||||
|
projectsContainer: document.getElementById('projects-container'),
|
||||||
|
noData: document.getElementById('no-data'),
|
||||||
|
lastUpdated: document.getElementById('last-updated'),
|
||||||
|
presetWeek: document.getElementById('preset-week'),
|
||||||
|
presetMonth: document.getElementById('preset-month'),
|
||||||
|
presetAugust: document.getElementById('preset-august')
|
||||||
|
};
|
||||||
|
|
||||||
|
// 초기화
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// 로그인 확인
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token) {
|
||||||
|
alert('로그인이 필요합니다.');
|
||||||
|
window.location.href = '/index.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 사용자 정보 및 권한 확인
|
||||||
|
const userStr = localStorage.getItem('user');
|
||||||
|
if (!userStr) {
|
||||||
|
alert('사용자 정보를 찾을 수 없습니다.');
|
||||||
|
window.location.href = '/index.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = JSON.parse(userStr);
|
||||||
|
|
||||||
|
// 시스템 권한 확인 (system 역할만 접근 가능)
|
||||||
|
if (user.role !== 'system') {
|
||||||
|
alert('시스템 관리자 권한이 필요합니다.');
|
||||||
|
window.location.href = '/pages/dashboard/user.html'; // 일반 사용자 대시보드로 리디렉션
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('시스템 관리자 인증 완료:', user.name || user.username);
|
||||||
|
|
||||||
|
initializeDateInputs();
|
||||||
|
bindEventListeners();
|
||||||
|
|
||||||
|
// 8월 전체를 기본값으로 설정
|
||||||
|
setDatePreset('august');
|
||||||
|
});
|
||||||
|
|
||||||
|
// 날짜 입력 초기화
|
||||||
|
function initializeDateInputs() {
|
||||||
|
const today = new Date();
|
||||||
|
const oneMonthAgo = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
|
||||||
|
|
||||||
|
elements.endDate.value = today.toISOString().split('T')[0];
|
||||||
|
elements.startDate.value = oneMonthAgo.toISOString().split('T')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 이벤트 리스너 바인딩
|
||||||
|
function bindEventListeners() {
|
||||||
|
elements.analyzeBtn.addEventListener('click', performAnalysis);
|
||||||
|
elements.refreshBtn.addEventListener('click', performAnalysis);
|
||||||
|
|
||||||
|
// 날짜 프리셋 버튼들
|
||||||
|
elements.presetWeek.addEventListener('click', () => setDatePreset('week'));
|
||||||
|
elements.presetMonth.addEventListener('click', () => setDatePreset('month'));
|
||||||
|
elements.presetAugust.addEventListener('click', () => setDatePreset('august'));
|
||||||
|
|
||||||
|
// Enter 키로 분석 실행
|
||||||
|
elements.startDate.addEventListener('keypress', handleEnterKey);
|
||||||
|
elements.endDate.addEventListener('keypress', handleEnterKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enter 키 처리
|
||||||
|
function handleEnterKey(event) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
performAnalysis();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 날짜 프리셋 설정
|
||||||
|
function setDatePreset(preset) {
|
||||||
|
const today = new Date();
|
||||||
|
let startDate, endDate;
|
||||||
|
|
||||||
|
switch (preset) {
|
||||||
|
case 'week':
|
||||||
|
startDate = new Date(today.getFullYear(), today.getMonth(), today.getDate() - 7);
|
||||||
|
endDate = today;
|
||||||
|
break;
|
||||||
|
case 'month':
|
||||||
|
startDate = new Date(today.getFullYear(), today.getMonth() - 1, today.getDate());
|
||||||
|
endDate = today;
|
||||||
|
break;
|
||||||
|
case 'august':
|
||||||
|
startDate = new Date(2025, 7, 1); // 2025년 8월 1일
|
||||||
|
endDate = new Date(2025, 7, 31); // 2025년 8월 31일
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.startDate.value = startDate.toISOString().split('T')[0];
|
||||||
|
elements.endDate.value = endDate.toISOString().split('T')[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 분석 실행
|
||||||
|
async function performAnalysis() {
|
||||||
|
const startDate = elements.startDate.value;
|
||||||
|
const endDate = elements.endDate.value;
|
||||||
|
|
||||||
|
if (!startDate || !endDate) {
|
||||||
|
alert('시작일과 종료일을 모두 선택해주세요.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new Date(startDate) > new Date(endDate)) {
|
||||||
|
alert('시작일이 종료일보다 늦을 수 없습니다.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로그인 확인
|
||||||
|
const token = localStorage.getItem('token');
|
||||||
|
if (!token) {
|
||||||
|
alert('로그인이 필요합니다.');
|
||||||
|
window.location.href = '/index.html';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
showLoading(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await apiCall(`/work-analysis/project-worktype-analysis?start=${startDate}&end=${endDate}`);
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
analysisData = result.data;
|
||||||
|
renderAnalysisResults();
|
||||||
|
updateLastUpdated();
|
||||||
|
} else {
|
||||||
|
throw new Error(result.error || '데이터 조회에 실패했습니다.');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('분석 실패:', error);
|
||||||
|
showError(`분석 실패: ${error.message}`);
|
||||||
|
} finally {
|
||||||
|
showLoading(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로딩 표시/숨김
|
||||||
|
function showLoading(show) {
|
||||||
|
elements.loading.classList.toggle('hidden', !show);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 에러 표시
|
||||||
|
function showError(message) {
|
||||||
|
alert(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 분석 결과 렌더링
|
||||||
|
function renderAnalysisResults() {
|
||||||
|
if (!analysisData || !analysisData.projects || analysisData.projects.length === 0) {
|
||||||
|
showNoData();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hideNoData();
|
||||||
|
renderSummaryStats();
|
||||||
|
renderCharts();
|
||||||
|
renderProjectCards();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 데이터 없음 표시
|
||||||
|
function showNoData() {
|
||||||
|
elements.summaryStats.classList.add('hidden');
|
||||||
|
elements.chartsSection.classList.add('hidden');
|
||||||
|
elements.projectsContainer.innerHTML = '';
|
||||||
|
elements.noData.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 데이터 없음 숨김
|
||||||
|
function hideNoData() {
|
||||||
|
elements.noData.classList.add('hidden');
|
||||||
|
elements.summaryStats.classList.remove('hidden');
|
||||||
|
elements.chartsSection.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 요약 통계 렌더링
|
||||||
|
function renderSummaryStats() {
|
||||||
|
const summary = analysisData.summary;
|
||||||
|
|
||||||
|
document.getElementById('total-hours').textContent = `${(summary.grand_total_hours || 0).toFixed(1)}h`;
|
||||||
|
document.getElementById('regular-hours').textContent = `${(summary.grand_regular_hours || 0).toFixed(1)}h`;
|
||||||
|
document.getElementById('error-hours').textContent = `${(summary.grand_error_hours || 0).toFixed(1)}h`;
|
||||||
|
document.getElementById('error-rate').textContent = `${summary.grand_error_rate || 0}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 차트 렌더링
|
||||||
|
function renderCharts() {
|
||||||
|
renderProjectChart();
|
||||||
|
renderErrorChart();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 프로젝트별 시간 분포 차트
|
||||||
|
function renderProjectChart() {
|
||||||
|
const ctx = document.getElementById('project-chart').getContext('2d');
|
||||||
|
|
||||||
|
// 기존 차트 삭제
|
||||||
|
if (charts.project) {
|
||||||
|
charts.project.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = analysisData.projects;
|
||||||
|
const labels = projects.map(p => p.project_name || 'Unknown Project');
|
||||||
|
const totalHours = projects.map(p => p.total_project_hours || 0);
|
||||||
|
const regularHours = projects.map(p => p.total_regular_hours || 0);
|
||||||
|
const errorHours = projects.map(p => p.total_error_hours || 0);
|
||||||
|
|
||||||
|
charts.project = new Chart(ctx, {
|
||||||
|
type: 'bar',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: '정규 시간',
|
||||||
|
data: regularHours,
|
||||||
|
backgroundColor: '#10B981',
|
||||||
|
borderColor: '#059669',
|
||||||
|
borderWidth: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '에러 시간',
|
||||||
|
data: errorHours,
|
||||||
|
backgroundColor: '#EF4444',
|
||||||
|
borderColor: '#DC2626',
|
||||||
|
borderWidth: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
x: {
|
||||||
|
stacked: true,
|
||||||
|
ticks: {
|
||||||
|
maxRotation: 45
|
||||||
|
}
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
stacked: true,
|
||||||
|
beginAtZero: true,
|
||||||
|
title: {
|
||||||
|
display: true,
|
||||||
|
text: '시간 (h)'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'top'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
footer: function(tooltipItems) {
|
||||||
|
const index = tooltipItems[0].dataIndex;
|
||||||
|
const total = totalHours[index];
|
||||||
|
return `총 시간: ${total.toFixed(1)}h`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 에러율 분석 차트
|
||||||
|
function renderErrorChart() {
|
||||||
|
const ctx = document.getElementById('error-chart').getContext('2d');
|
||||||
|
|
||||||
|
// 기존 차트 삭제
|
||||||
|
if (charts.error) {
|
||||||
|
charts.error.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
const projects = analysisData.projects;
|
||||||
|
const labels = projects.map(p => p.project_name || 'Unknown Project');
|
||||||
|
const errorRates = projects.map(p => p.project_error_rate || 0);
|
||||||
|
|
||||||
|
// 에러율에 따른 색상 결정
|
||||||
|
const colors = errorRates.map(rate => {
|
||||||
|
if (rate >= 10) return '#EF4444'; // 높음 (빨강)
|
||||||
|
if (rate >= 5) return '#F59E0B'; // 중간 (주황)
|
||||||
|
return '#10B981'; // 낮음 (초록)
|
||||||
|
});
|
||||||
|
|
||||||
|
charts.error = new Chart(ctx, {
|
||||||
|
type: 'doughnut',
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [{
|
||||||
|
data: errorRates,
|
||||||
|
backgroundColor: colors,
|
||||||
|
borderColor: '#ffffff',
|
||||||
|
borderWidth: 2
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
plugins: {
|
||||||
|
legend: {
|
||||||
|
position: 'bottom'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
callbacks: {
|
||||||
|
label: function(context) {
|
||||||
|
return `${context.label}: ${context.parsed}%`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 프로젝트 카드 렌더링
|
||||||
|
function renderProjectCards() {
|
||||||
|
const container = elements.projectsContainer;
|
||||||
|
container.innerHTML = '';
|
||||||
|
|
||||||
|
analysisData.projects.forEach(project => {
|
||||||
|
const card = createProjectCard(project);
|
||||||
|
container.appendChild(card);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 프로젝트 카드 생성
|
||||||
|
function createProjectCard(project) {
|
||||||
|
const card = document.createElement('div');
|
||||||
|
|
||||||
|
// 에러율에 따른 카드 스타일 결정
|
||||||
|
let errorClass = 'error-low';
|
||||||
|
const errorRate = project.project_error_rate || 0;
|
||||||
|
if (errorRate >= 10) errorClass = 'error-high';
|
||||||
|
else if (errorRate >= 5) errorClass = 'error-medium';
|
||||||
|
|
||||||
|
card.className = `project-card ${errorClass} bg-white rounded-lg shadow-md p-6`;
|
||||||
|
|
||||||
|
// 프로젝트 헤더
|
||||||
|
const header = `
|
||||||
|
<div class="flex justify-between items-start mb-4">
|
||||||
|
<div>
|
||||||
|
<h3 class="text-xl font-bold text-gray-800">${project.project_name || 'Unknown Project'}</h3>
|
||||||
|
<p class="text-sm text-gray-600">Job No: ${project.job_no || 'N/A'}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<div class="text-2xl font-bold text-blue-600">${(project.total_project_hours || 0).toFixed(1)}h</div>
|
||||||
|
<div class="text-sm text-gray-500">총 시간</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 프로젝트 요약 통계
|
||||||
|
const summary = `
|
||||||
|
<div class="grid grid-cols-3 gap-4 mb-6 p-4 bg-gray-50 rounded-lg">
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-lg font-semibold text-green-600">${(project.total_regular_hours || 0).toFixed(1)}h</div>
|
||||||
|
<div class="text-xs text-gray-600">정규 시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-lg font-semibold text-red-600">${(project.total_error_hours || 0).toFixed(1)}h</div>
|
||||||
|
<div class="text-xs text-gray-600">에러 시간</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center">
|
||||||
|
<div class="text-lg font-semibold text-purple-600">${errorRate}%</div>
|
||||||
|
<div class="text-xs text-gray-600">에러율</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// 작업 유형별 테이블
|
||||||
|
let workTypesTable = `
|
||||||
|
<div class="overflow-x-auto">
|
||||||
|
<table class="min-w-full">
|
||||||
|
<thead class="bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th class="px-4 py-2 text-left text-xs font-medium text-gray-500 uppercase">작업 유형</th>
|
||||||
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">총 시간</th>
|
||||||
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">정규 시간</th>
|
||||||
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">에러 시간</th>
|
||||||
|
<th class="px-4 py-2 text-right text-xs font-medium text-gray-500 uppercase">에러율</th>
|
||||||
|
<th class="px-4 py-2 text-center text-xs font-medium text-gray-500 uppercase">진행률</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="divide-y divide-gray-200">
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (project.work_types && project.work_types.length > 0) {
|
||||||
|
project.work_types.forEach(workType => {
|
||||||
|
const totalHours = workType.total_hours || 0;
|
||||||
|
const regularHours = workType.regular_hours || 0;
|
||||||
|
const errorHours = workType.error_hours || 0;
|
||||||
|
const errorRatePercent = workType.error_rate_percent || 0;
|
||||||
|
|
||||||
|
const regularPercent = totalHours > 0 ? (regularHours / totalHours) * 100 : 0;
|
||||||
|
const errorPercent = totalHours > 0 ? (errorHours / totalHours) * 100 : 0;
|
||||||
|
|
||||||
|
workTypesTable += `
|
||||||
|
<tr class="work-type-row">
|
||||||
|
<td class="px-4 py-3 text-sm font-medium text-gray-900">${workType.work_type_name || 'Unknown'}</td>
|
||||||
|
<td class="px-4 py-3 text-sm text-right font-semibold">${totalHours.toFixed(1)}h</td>
|
||||||
|
<td class="px-4 py-3 text-sm text-right text-green-600">${regularHours.toFixed(1)}h</td>
|
||||||
|
<td class="px-4 py-3 text-sm text-right text-red-600">${errorHours.toFixed(1)}h</td>
|
||||||
|
<td class="px-4 py-3 text-sm text-right font-medium ${errorRatePercent >= 10 ? 'text-red-600' : errorRatePercent >= 5 ? 'text-yellow-600' : 'text-green-600'}">${errorRatePercent}%</td>
|
||||||
|
<td class="px-4 py-3">
|
||||||
|
<div class="flex items-center space-x-2">
|
||||||
|
<div class="flex-1 bg-gray-200 rounded-full h-2">
|
||||||
|
<div class="bg-green-500 h-2 rounded-full progress-bar" style="width: ${regularPercent}%"></div>
|
||||||
|
</div>
|
||||||
|
<div class="flex-1 bg-gray-200 rounded-full h-2">
|
||||||
|
<div class="bg-red-500 h-2 rounded-full progress-bar" style="width: ${errorPercent}%"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
workTypesTable += `
|
||||||
|
<tr>
|
||||||
|
<td colspan="6" class="px-4 py-3 text-center text-gray-500">작업 유형 데이터가 없습니다.</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
workTypesTable += `
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
card.innerHTML = header + summary + workTypesTable;
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 마지막 업데이트 시간 갱신
|
||||||
|
function updateLastUpdated() {
|
||||||
|
const now = new Date();
|
||||||
|
const timeString = now.toLocaleString('ko-KR');
|
||||||
|
elements.lastUpdated.textContent = `마지막 업데이트: ${timeString}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 유틸리티 함수들
|
||||||
|
function formatNumber(num) {
|
||||||
|
return new Intl.NumberFormat('ko-KR').format(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatHours(hours) {
|
||||||
|
return `${hours.toFixed(1)}시간`;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
1083
web-ui/pages/analysis/work-report-analytics.html
Normal file
1083
web-ui/pages/analysis/work-report-analytics.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,497 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Rate Limit 관리</title>
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: 0 auto;
|
|
||||||
background: white;
|
|
||||||
border-radius: 12px;
|
|
||||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
||||||
color: white;
|
|
||||||
padding: 30px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header h1 {
|
|
||||||
font-size: 24px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.shield-icon {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.user-level {
|
|
||||||
background: rgba(255, 255, 255, 0.2);
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 20px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
gap: 20px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card {
|
|
||||||
background: #f8f9fa;
|
|
||||||
border: 1px solid #e9ecef;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card .label {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #6c757d;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.status-card .value {
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: bold;
|
|
||||||
font-family: 'Courier New', monospace;
|
|
||||||
color: #495057;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons-grid {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
||||||
gap: 15px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 12px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: all 0.2s;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
cursor: not-allowed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-blue {
|
|
||||||
background: #007bff;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-blue:hover:not(:disabled) {
|
|
||||||
background: #0056b3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-green {
|
|
||||||
background: #28a745;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-green:hover:not(:disabled) {
|
|
||||||
background: #1e7e34;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-orange {
|
|
||||||
background: #fd7e14;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-orange:hover:not(:disabled) {
|
|
||||||
background: #e55a00;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-gray {
|
|
||||||
background: #6c757d;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-gray:hover:not(:disabled) {
|
|
||||||
background: #545b62;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message {
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message.success {
|
|
||||||
background: #d4edda;
|
|
||||||
color: #155724;
|
|
||||||
border: 1px solid #c3e6cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message.error {
|
|
||||||
background: #f8d7da;
|
|
||||||
color: #721c24;
|
|
||||||
border: 1px solid #f5c6cb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message.warning {
|
|
||||||
background: #fff3cd;
|
|
||||||
color: #856404;
|
|
||||||
border: 1px solid #ffeaa7;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-section {
|
|
||||||
background: #e3f2fd;
|
|
||||||
border: 1px solid #bbdefb;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-section h3 {
|
|
||||||
color: #1565c0;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-section ul {
|
|
||||||
color: #1976d2;
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.help-section li {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loading {
|
|
||||||
opacity: 0.7;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.no-permission {
|
|
||||||
background: #fff3cd;
|
|
||||||
border: 1px solid #ffeaa7;
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="header">
|
|
||||||
<h1>
|
|
||||||
<svg class="shield-icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M12,1L3,5V11C3,16.55 6.84,21.74 12,23C17.16,21.74 21,16.55 21,11V5L12,1M12,7C13.4,7 14.8,8.6 14.8,10V11H16V21H8V11H9.2V10C9.2,8.6 10.6,7 12,7M12,8.2C11.2,8.2 10.4,8.7 10.4,10V11H13.6V10C13.6,8.7 12.8,8.2 12,8.2Z"/>
|
|
||||||
</svg>
|
|
||||||
Rate Limit 관리
|
|
||||||
</h1>
|
|
||||||
<div class="user-level" id="userLevel">권한 레벨: -</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="content">
|
|
||||||
<!-- 권한 없음 메시지 -->
|
|
||||||
<div class="no-permission" id="noPermission" style="display: none;">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24" style="width: 24px; height: 24px; margin-bottom: 10px;">
|
|
||||||
<path d="M12,2C13.1,2 14,2.9 14,4C14,5.1 13.1,6 12,6C10.9,6 10,5.1 10,4C10,2.9 10.9,2 12,2M21,9V7L15,1H5C3.89,1 3,1.89 3,3V21A2,2 0 0,0 5,23H19A2,2 0 0,0 21,21V9M19,9H14V4H5V21H19V9Z"/>
|
|
||||||
</svg>
|
|
||||||
<h3>접근 권한 부족</h3>
|
|
||||||
<p>Rate Limit 관리 기능은 권한 레벨 4 이상의 사용자만 사용할 수 있습니다.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 현재 상태 -->
|
|
||||||
<div id="statusSection">
|
|
||||||
<h2 style="margin-bottom: 20px; display: flex; align-items: center; gap: 8px;">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M12,2C13.1,2 14,2.9 14,4C14,5.1 13.1,6 12,6C10.9,6 10,5.1 10,4C10,2.9 10.9,2 12,2M21,9V7L15,1H5C3.89,1 3,1.89 3,3V21A2,2 0 0,0 5,23H19A2,2 0 0,0 21,21V9M19,9H14V4H5V21H19V9Z"/>
|
|
||||||
</svg>
|
|
||||||
현재 상태
|
|
||||||
</h2>
|
|
||||||
|
|
||||||
<div class="status-grid">
|
|
||||||
<div class="status-card">
|
|
||||||
<div class="label">클라이언트 IP</div>
|
|
||||||
<div class="value" id="clientIP">로딩 중...</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-card">
|
|
||||||
<div class="label">API 제한</div>
|
|
||||||
<div class="value" id="apiLimit">로딩 중...</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-card">
|
|
||||||
<div class="label">로그인 제한</div>
|
|
||||||
<div class="value" id="loginLimit">로딩 중...</div>
|
|
||||||
</div>
|
|
||||||
<div class="status-card">
|
|
||||||
<div class="label">시간 윈도우</div>
|
|
||||||
<div class="value">15분</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 컨트롤 버튼들 -->
|
|
||||||
<div id="controlSection">
|
|
||||||
<div class="buttons-grid">
|
|
||||||
<button class="btn btn-blue" onclick="resetRateLimit()">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M12,2C13.1,2 14,2.9 14,4C14,5.1 13.1,6 12,6C10.9,6 10,5.1 10,4C10,2.9 10.9,2 12,2M21,9V7L15,1H5C3.89,1 3,1.89 3,3V21A2,2 0 0,0 5,23H19A2,2 0 0,0 21,21V9M19,9H14V4H5V21H19V9Z"/>
|
|
||||||
</svg>
|
|
||||||
내 IP 제한 초기화
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-green" onclick="bypassRateLimit(3600000)">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22C6.47,22 2,17.5 2,12A10,10 0 0,1 12,2Z"/>
|
|
||||||
</svg>
|
|
||||||
1시간 제한 해제
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-orange" onclick="bypassRateLimit(86400000)">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22C6.47,22 2,17.5 2,12A10,10 0 0,1 12,2Z"/>
|
|
||||||
</svg>
|
|
||||||
24시간 제한 해제
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button class="btn btn-gray" onclick="checkStatus()">
|
|
||||||
<svg class="icon" viewBox="0 0 24 24">
|
|
||||||
<path d="M17.65,6.35C16.2,4.9 14.21,4 12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20C15.73,20 18.84,17.45 19.73,14H17.65C16.83,16.33 14.61,18 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6C13.66,6 15.14,6.69 16.22,7.78L13,11H20V4L17.65,6.35Z"/>
|
|
||||||
</svg>
|
|
||||||
상태 새로고침
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 메시지 표시 영역 -->
|
|
||||||
<div id="messageArea"></div>
|
|
||||||
|
|
||||||
<!-- 도움말 -->
|
|
||||||
<div class="help-section">
|
|
||||||
<h3>💡 사용 가이드</h3>
|
|
||||||
<ul>
|
|
||||||
<li><strong>초기화</strong>: 현재 IP의 요청 카운터를 0으로 리셋</li>
|
|
||||||
<li><strong>제한 해제</strong>: 지정된 시간 동안 Rate Limit 완전 비활성화</li>
|
|
||||||
<li><strong>권한 요구사항</strong>: 레벨 4-5 사용자만 접근 가능</li>
|
|
||||||
<li><strong>자동 해제</strong>: 임시 해제는 설정된 시간 후 자동으로 복구됨</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
let userLevel = 0;
|
|
||||||
let loading = false;
|
|
||||||
|
|
||||||
// 토큰 가져오기
|
|
||||||
function getToken() {
|
|
||||||
return localStorage.getItem('token') || sessionStorage.getItem('token');
|
|
||||||
}
|
|
||||||
|
|
||||||
// 로딩 상태 설정
|
|
||||||
function setLoading(isLoading) {
|
|
||||||
loading = isLoading;
|
|
||||||
const container = document.querySelector('.container');
|
|
||||||
if (isLoading) {
|
|
||||||
container.classList.add('loading');
|
|
||||||
} else {
|
|
||||||
container.classList.remove('loading');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 메시지 표시
|
|
||||||
function showMessage(message, type = 'info') {
|
|
||||||
const messageArea = document.getElementById('messageArea');
|
|
||||||
const messageDiv = document.createElement('div');
|
|
||||||
messageDiv.className = `message ${type}`;
|
|
||||||
messageDiv.textContent = message;
|
|
||||||
|
|
||||||
messageArea.innerHTML = '';
|
|
||||||
messageArea.appendChild(messageDiv);
|
|
||||||
|
|
||||||
// 5초 후 자동 제거
|
|
||||||
setTimeout(() => {
|
|
||||||
if (messageDiv.parentNode) {
|
|
||||||
messageDiv.parentNode.removeChild(messageDiv);
|
|
||||||
}
|
|
||||||
}, 5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 사용자 권한 확인
|
|
||||||
async function checkUserPermission() {
|
|
||||||
try {
|
|
||||||
const token = getToken();
|
|
||||||
if (!token) {
|
|
||||||
showMessage('로그인이 필요합니다.', 'error');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch('/api/auth/me', {
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const userData = await response.json();
|
|
||||||
userLevel = userData.access_level || 0;
|
|
||||||
document.getElementById('userLevel').textContent = `권한 레벨: ${userLevel}`;
|
|
||||||
|
|
||||||
if (userLevel < 4) {
|
|
||||||
document.getElementById('noPermission').style.display = 'block';
|
|
||||||
document.getElementById('statusSection').style.display = 'none';
|
|
||||||
document.getElementById('controlSection').style.display = 'none';
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
showMessage('사용자 정보 확인 실패', 'error');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showMessage('네트워크 오류: ' + error.message, 'error');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 현재 상태 조회
|
|
||||||
async function checkStatus() {
|
|
||||||
if (loading || userLevel < 4) return;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const token = getToken();
|
|
||||||
const response = await fetch('/api/admin/rate-limit/status', {
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (response.ok) {
|
|
||||||
const data = await response.json();
|
|
||||||
document.getElementById('clientIP').textContent = data.clientIP;
|
|
||||||
document.getElementById('apiLimit').textContent = `${data.rateLimitInfo.apiLimit}회/15분`;
|
|
||||||
document.getElementById('loginLimit').textContent = `${data.rateLimitInfo.loginLimit}회/15분`;
|
|
||||||
} else {
|
|
||||||
const errorData = await response.json();
|
|
||||||
showMessage('상태 조회 실패: ' + (errorData.error || response.statusText), 'error');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showMessage('네트워크 오류: ' + error.message, 'error');
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rate Limit 초기화
|
|
||||||
async function resetRateLimit(targetIP = null) {
|
|
||||||
if (loading || userLevel < 4) return;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const token = getToken();
|
|
||||||
const response = await fetch('/api/admin/rate-limit/reset', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ targetIP })
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
if (response.ok) {
|
|
||||||
showMessage('✅ ' + data.message, 'success');
|
|
||||||
checkStatus(); // 상태 새로고침
|
|
||||||
} else {
|
|
||||||
showMessage('❌ ' + data.error, 'error');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showMessage('❌ 초기화 실패: ' + error.message, 'error');
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Rate Limit 임시 비활성화
|
|
||||||
async function bypassRateLimit(duration = 3600000) {
|
|
||||||
if (loading || userLevel < 4) return;
|
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
try {
|
|
||||||
const token = getToken();
|
|
||||||
const response = await fetch('/api/admin/rate-limit/bypass', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': `Bearer ${token}`,
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ duration })
|
|
||||||
});
|
|
||||||
|
|
||||||
const data = await response.json();
|
|
||||||
if (response.ok) {
|
|
||||||
const hours = duration / 3600000;
|
|
||||||
showMessage(`🔓 ${hours}시간 동안 Rate Limit가 해제되었습니다.`, 'success');
|
|
||||||
checkStatus();
|
|
||||||
} else {
|
|
||||||
showMessage('❌ ' + data.error, 'error');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
showMessage('❌ Bypass 설정 실패: ' + error.message, 'error');
|
|
||||||
}
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 페이지 로드 시 초기화
|
|
||||||
async function init() {
|
|
||||||
const hasPermission = await checkUserPermission();
|
|
||||||
if (hasPermission) {
|
|
||||||
await checkStatus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 페이지 로드 시 실행
|
|
||||||
document.addEventListener('DOMContentLoaded', init);
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,87 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>출근부 조회 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/admin.css">
|
|
||||||
<link rel="stylesheet" href="/css/attendance.css" />
|
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout">
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div id="sidebar-container"></div>
|
|
||||||
|
|
||||||
<div id="content-container">
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>📊 출근부 조회</h1>
|
|
||||||
<p class="subtitle">월별 출근 현황 및 잔업 시간을 확인할 수 있습니다.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="pdfContent">
|
|
||||||
<!-- 조회 컨트롤 -->
|
|
||||||
<div class="control-panel card">
|
|
||||||
<div class="control-group">
|
|
||||||
<label for="year">연도</label>
|
|
||||||
<select id="year" class="form-control"></select>
|
|
||||||
</div>
|
|
||||||
<div class="control-group">
|
|
||||||
<label for="month">월</label>
|
|
||||||
<select id="month" class="form-control"></select>
|
|
||||||
</div>
|
|
||||||
<div class="control-actions">
|
|
||||||
<button id="loadAttendance" class="btn btn-primary">
|
|
||||||
<span class="icon">📊</span> 조회하기
|
|
||||||
</button>
|
|
||||||
<button id="downloadPdf" class="btn btn-secondary">
|
|
||||||
<span class="icon">📄</span> PDF 저장
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 출근부 테이블 -->
|
|
||||||
<div class="table-container card">
|
|
||||||
<div id="attendanceTableContainer">
|
|
||||||
<div class="empty-state">
|
|
||||||
<p>조회할 연도와 월을 선택하세요.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 범례 -->
|
|
||||||
<div class="legend card">
|
|
||||||
<h3>범례</h3>
|
|
||||||
<div class="legend-items">
|
|
||||||
<span class="legend-item">
|
|
||||||
<span class="color-box overtime-cell"></span> 잔업
|
|
||||||
</span>
|
|
||||||
<span class="legend-item">
|
|
||||||
<span class="color-box leave"></span> 연차/반차
|
|
||||||
</span>
|
|
||||||
<span class="legend-item">
|
|
||||||
<span class="color-box paid-leave"></span> 유급
|
|
||||||
</span>
|
|
||||||
<span class="legend-item">
|
|
||||||
<span class="color-box holiday"></span> 휴무
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script type="module" src="/js/load-sidebar.js"></script>
|
|
||||||
<script type="module" src="/js/attendance.js"></script>
|
|
||||||
|
|
||||||
<!-- PDF 생성 라이브러리 -->
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>공장 정보 등록 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/factory.css" />
|
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout">
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div id="sidebar-container"></div>
|
|
||||||
|
|
||||||
<div id="content-container">
|
|
||||||
<div class="container">
|
|
||||||
<h2>공장 정보 등록</h2>
|
|
||||||
<form id="uploadForm" enctype="multipart/form-data">
|
|
||||||
<label>공장명</label>
|
|
||||||
<input type="text" name="factory_name" placeholder="예: 울산 제1공장" required>
|
|
||||||
|
|
||||||
<label>주소</label>
|
|
||||||
<input type="text" name="address" placeholder="예: 울산광역시 남구 산업로 123" required>
|
|
||||||
|
|
||||||
<label>설명</label>
|
|
||||||
<textarea name="description" placeholder="공장에 대한 간단한 설명을 입력하세요." required></textarea>
|
|
||||||
|
|
||||||
<label>공장 지도 이미지</label>
|
|
||||||
<input type="file" name="map_image" accept="image/*" required>
|
|
||||||
<div id="file-preview" style="margin: 10px 0; text-align: center;"></div>
|
|
||||||
|
|
||||||
<button type="submit">등록하기</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script type="module" src="/js/load-sidebar.js"></script>
|
|
||||||
<script type="module" src="/js/factory-upload.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>공장 정보 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/factory.css" />
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout">
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div id="sidebar-container"></div>
|
|
||||||
|
|
||||||
<div id="content-container">
|
|
||||||
<div class="container">
|
|
||||||
<!-- 로딩 상태 -->
|
|
||||||
<div id="loading" class="loading">
|
|
||||||
공장 정보를 불러오는 중...
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 실제 컨텐츠 (초기에는 숨김) -->
|
|
||||||
<div id="content" style="display: none;">
|
|
||||||
<h2 id="factoryName">공장 이름</h2>
|
|
||||||
|
|
||||||
<div class="info-section">
|
|
||||||
<div class="info-label">📍 주소</div>
|
|
||||||
<p id="factoryAddress" style="margin: 0;">주소</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<img id="factoryImage" alt="공장 지도" style="max-width: 100%; margin: 20px 0;">
|
|
||||||
|
|
||||||
<div class="info-section">
|
|
||||||
<div class="info-label">📝 설명</div>
|
|
||||||
<p id="factoryDescription" style="margin: 0;">설명</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="margin-top: 30px; text-align: center;">
|
|
||||||
<button onclick="history.back()" style="padding: 10px 20px;">뒤로가기</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 에러 메시지 (필요시 표시) -->
|
|
||||||
<div id="error" class="error-state" style="display: none;">
|
|
||||||
공장 정보를 불러올 수 없습니다.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script type="module" src="/js/load-sidebar.js"></script>
|
|
||||||
<script type="module" src="/js/factory-view.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
<link rel="stylesheet" href="/css/main-layout.css">
|
||||||
<link rel="stylesheet" href="/css/management-dashboard.css">
|
<link rel="stylesheet" href="/css/management-dashboard.css">
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
<link rel="icon" type="image/png" href="/img/favicon.png">
|
||||||
<script src="/js/auth-check.js" defer></script>
|
<script type="module" src="/js/auth-check.js" defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="main-layout-with-navbar">
|
<div class="main-layout-with-navbar">
|
||||||
|
|||||||
@@ -17,10 +17,38 @@
|
|||||||
<div id="navbar-container"></div>
|
<div id="navbar-container"></div>
|
||||||
|
|
||||||
<div class="content-wrapper">
|
<div class="content-wrapper">
|
||||||
<!-- 시스템 관리자 페이지 헤더 -->
|
<!-- 시스템 관리자 배너 -->
|
||||||
<div class="page-header">
|
<div class="system-banner">
|
||||||
<h1><i class="fas fa-cogs"></i> 시스템 관리자</h1>
|
<div class="banner-content">
|
||||||
<span class="system-badge">SYSTEM</span>
|
<div class="banner-left">
|
||||||
|
<div class="system-icon">🔧</div>
|
||||||
|
<div class="banner-text">
|
||||||
|
<h1>시스템 관리자</h1>
|
||||||
|
<p>시스템 전반의 설정, 모니터링 및 관리를 담당합니다</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="banner-right">
|
||||||
|
<span class="system-badge">SYSTEM</span>
|
||||||
|
<div class="system-status">
|
||||||
|
<span class="status-dot online"></span>
|
||||||
|
<span>시스템 정상</span>
|
||||||
|
</div>
|
||||||
|
<div class="quick-actions">
|
||||||
|
<button class="quick-btn" onclick="window.location.href='/pages/admin/manage-user.html'" title="사용자 관리">
|
||||||
|
👤
|
||||||
|
</button>
|
||||||
|
<button class="quick-btn" onclick="window.location.href='/pages/analysis/work-report-analytics.html'" title="분석 대시보드">
|
||||||
|
📊
|
||||||
|
</button>
|
||||||
|
<button class="quick-btn" onclick="window.location.href='/pages/analysis/project-worktype-analysis.html'" title="프로젝트별 작업 시간 분석">
|
||||||
|
🏗️
|
||||||
|
</button>
|
||||||
|
<button class="quick-btn" onclick="refreshSystemStatus()" title="시스템 새로고침">
|
||||||
|
🔄
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 메인 컨텐츠 -->
|
<!-- 메인 컨텐츠 -->
|
||||||
@@ -144,6 +172,22 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 프로젝트별 작업 시간 분석 -->
|
||||||
|
<div class="management-card primary">
|
||||||
|
<div class="card-header">
|
||||||
|
<i class="fas fa-project-diagram"></i>
|
||||||
|
<h3>프로젝트 작업 분석</h3>
|
||||||
|
</div>
|
||||||
|
<div class="card-content">
|
||||||
|
<p>프로젝트별-작업별 시간 분석 및 에러율 모니터링</p>
|
||||||
|
<div class="card-actions">
|
||||||
|
<button class="btn btn-primary" onclick="window.location.href='/pages/analysis/project-worktype-analysis.html'">
|
||||||
|
<i class="fas fa-chart-bar"></i> 분석 보기
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- 모니터링 -->
|
<!-- 모니터링 -->
|
||||||
<div class="management-card">
|
<div class="management-card">
|
||||||
<div class="card-header">
|
<div class="card-header">
|
||||||
@@ -189,9 +233,39 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 테스트용 인라인 스크립트 -->
|
<!-- 시스템 관리자 스크립트 -->
|
||||||
<script>
|
<script>
|
||||||
console.log('🧪 인라인 스크립트 실행됨');
|
console.log('🔧 시스템 관리자 대시보드 로드됨');
|
||||||
|
|
||||||
|
// 시스템 상태 새로고침 함수
|
||||||
|
function refreshSystemStatus() {
|
||||||
|
console.log('🔄 시스템 상태 새로고침 중...');
|
||||||
|
|
||||||
|
// 시각적 피드백
|
||||||
|
const statusDot = document.querySelector('.status-dot');
|
||||||
|
const refreshBtn = document.querySelector('.quick-btn[title="시스템 새로고침"]');
|
||||||
|
|
||||||
|
if (refreshBtn) {
|
||||||
|
refreshBtn.style.transform = 'rotate(360deg)';
|
||||||
|
setTimeout(() => {
|
||||||
|
refreshBtn.style.transform = '';
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 실제 상태 업데이트 (시뮬레이션)
|
||||||
|
setTimeout(() => {
|
||||||
|
updateSystemTime();
|
||||||
|
console.log('✅ 시스템 상태 업데이트 완료');
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시스템 시간 업데이트
|
||||||
|
function updateSystemTime() {
|
||||||
|
const timeElement = document.getElementById('server-check-time');
|
||||||
|
if (timeElement) {
|
||||||
|
timeElement.textContent = new Date().toLocaleTimeString('ko-KR');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 간단한 테스트 함수
|
// 간단한 테스트 함수
|
||||||
function testClick() {
|
function testClick() {
|
||||||
@@ -199,17 +273,24 @@
|
|||||||
alert('버튼이 정상적으로 작동합니다!');
|
alert('버튼이 정상적으로 작동합니다!');
|
||||||
}
|
}
|
||||||
|
|
||||||
// DOM 로드 후 이벤트 리스너 설정
|
// DOM 로드 후 초기화
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
console.log('📄 DOM 로드 완료');
|
console.log('📄 시스템 대시보드 DOM 로드 완료');
|
||||||
|
|
||||||
|
// 초기 시간 설정
|
||||||
|
updateSystemTime();
|
||||||
|
|
||||||
|
// 주기적 시간 업데이트 (30초마다)
|
||||||
|
setInterval(updateSystemTime, 30000);
|
||||||
|
|
||||||
|
// 계정 관리 버튼 이벤트
|
||||||
const accountBtn = document.querySelector('[data-action="account-management"]');
|
const accountBtn = document.querySelector('[data-action="account-management"]');
|
||||||
if (accountBtn) {
|
if (accountBtn) {
|
||||||
accountBtn.addEventListener('click', testClick);
|
accountBtn.addEventListener('click', testClick);
|
||||||
console.log('✅ 계정 관리 버튼에 테스트 이벤트 리스너 추가됨');
|
console.log('✅ 계정 관리 버튼 이벤트 설정 완료');
|
||||||
} else {
|
|
||||||
console.log('❌ 계정 관리 버튼을 찾을 수 없음');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('🚀 시스템 관리자 대시보드 초기화 완료');
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="ko">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>일일 이슈 보고 | (주)테크니컬코리아</title>
|
|
||||||
<link rel="stylesheet" href="/css/main-layout.css">
|
|
||||||
<link rel="stylesheet" href="/css/daily-issue.css">
|
|
||||||
<link rel="icon" type="image/png" href="/img/favicon.png">
|
|
||||||
<script src="/js/auth-check.js" defer></script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="main-layout">
|
|
||||||
<div id="navbar-container"></div>
|
|
||||||
|
|
||||||
<div class="content-wrapper">
|
|
||||||
<div id="sidebar-container"></div>
|
|
||||||
|
|
||||||
<div id="content-container">
|
|
||||||
<div class="page-header">
|
|
||||||
<h1>📋 일일 이슈 보고</h1>
|
|
||||||
<p class="subtitle">금일 발생한 이슈 상황을 입력합니다.</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<form id="issueForm">
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="dateSelect">날짜</label>
|
|
||||||
<input type="date" id="dateSelect" class="form-control" required />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="projectSelect">프로젝트</label>
|
|
||||||
<select id="projectSelect" class="form-control" required>
|
|
||||||
<option value="">-- 프로젝트 선택 --</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label>작업자 선택</label>
|
|
||||||
<div id="workerList" class="multi-select-box">
|
|
||||||
날짜를 먼저 선택하세요.
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label for="issueTypeSelect">이슈 유형</label>
|
|
||||||
<select id="issueTypeSelect" class="form-control" required>
|
|
||||||
<option value="">-- 이슈 유형 선택 --</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-group">
|
|
||||||
<label>시간 범위</label>
|
|
||||||
<div class="time-range">
|
|
||||||
<select id="timeStart" class="form-control" required></select>
|
|
||||||
<span style="margin: 0 10px;">~</span>
|
|
||||||
<select id="timeEnd" class="form-control" required></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="form-actions">
|
|
||||||
<button type="button" class="btn btn-secondary" onclick="history.back()">취소</button>
|
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary">등록</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module" src="/js/load-navbar.js"></script>
|
|
||||||
<script type="module" src="/js/load-sidebar.js"></script>
|
|
||||||
<script type="module" src="/js/daily-issue.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
109
룰.md
109
룰.md
@@ -5,9 +5,24 @@
|
|||||||
|
|
||||||
본 문서는 (주)테크니컬코리아 생산팀 내부 포털의 원활한 개발 및 유지보수를 위한 규칙을 정의합니다. 모든 개발자는 본 규칙을 숙지하고 준수해야 합니다.
|
본 문서는 (주)테크니컬코리아 생산팀 내부 포털의 원활한 개발 및 유지보수를 위한 규칙을 정의합니다. 모든 개발자는 본 규칙을 숙지하고 준수해야 합니다.
|
||||||
|
|
||||||
## 2. 기술 스택
|
## 2. 기술 스택 및 개발 환경
|
||||||
|
|
||||||
### 2.1. 백엔드 (api.hyungi.net)
|
### 2.1. 개발 환경 (Docker 기반)
|
||||||
|
|
||||||
|
**🐳 현재 Docker Compose로 개발 중**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 컨테이너 상태 확인
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# 주요 컨테이너들:
|
||||||
|
- api_hyungi_dev (포트: 20005) - 백엔드 API 서버
|
||||||
|
- web_hyungi_dev (포트: 20000) - 프론트엔드 웹 서버
|
||||||
|
- db_hyungi_dev (포트: 20306) - MariaDB 데이터베이스
|
||||||
|
- pma_hyungi_dev (포트: 20080) - phpMyAdmin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2.2. 백엔드 (api.hyungi.net)
|
||||||
|
|
||||||
- **런타임:** Node.js
|
- **런타임:** Node.js
|
||||||
- **프레임워크:** Express.js
|
- **프레임워크:** Express.js
|
||||||
@@ -16,13 +31,24 @@
|
|||||||
- **프로세스 매니저:** PM2
|
- **프로세스 매니저:** PM2
|
||||||
- **컨테이너:** Docker
|
- **컨테이너:** Docker
|
||||||
- **포트:** 20005 (API 서버)
|
- **포트:** 20005 (API 서버)
|
||||||
|
- **API Base URL:** `http://localhost:20005`
|
||||||
|
|
||||||
### 2.2. 프론트엔드 (web-ui)
|
### 2.3. 프론트엔드 (web-ui)
|
||||||
|
|
||||||
- **언어:** HTML, CSS, JavaScript (ES6+ Modules)
|
- **언어:** HTML, CSS, JavaScript (ES6+ Modules)
|
||||||
- **라이브러리:** 별도 프레임워크 없이 순수 JS/HTML/CSS 사용
|
- **라이브러리:** 별도 프레임워크 없이 순수 JS/HTML/CSS 사용
|
||||||
- **웹서버:** Nginx
|
- **웹서버:** Nginx
|
||||||
- **포트:** 20000 (웹 서버)
|
- **포트:** 20000 (웹 서버)
|
||||||
|
- **Web UI URL:** `http://localhost:20000`
|
||||||
|
|
||||||
|
### 2.4. 데이터베이스 관리
|
||||||
|
|
||||||
|
- **MariaDB:** `localhost:20306`
|
||||||
|
- **사용자명:** `hyungi`
|
||||||
|
- **비밀번호:** `tycdoq-Kawcug-8wesfa`
|
||||||
|
- **데이터베이스:** `hyungi_dev`
|
||||||
|
- **phpMyAdmin:** `http://localhost:20080`
|
||||||
|
- **시스템 계정:** 동일한 계정 정보 사용
|
||||||
|
|
||||||
## 3. 코딩 컨벤션
|
## 3. 코딩 컨벤션
|
||||||
|
|
||||||
@@ -253,5 +279,82 @@ docker logs web_hyungi_dev
|
|||||||
3. `develop` 브랜치 -> `main` 브랜치로 PR
|
3. `develop` 브랜치 -> `main` 브랜치로 PR
|
||||||
4. `main` 브랜치에 머지되면 Docker 이미지를 빌드하여 배포
|
4. `main` 브랜치에 머지되면 Docker 이미지를 빌드하여 배포
|
||||||
|
|
||||||
|
## 9. API 구조 및 엔드포인트
|
||||||
|
|
||||||
|
### 9.1. 작업보고서 분석 API
|
||||||
|
|
||||||
|
#### 9.1.1. 개요
|
||||||
|
- **목적**: 데일리 워크 레포트 데이터의 종합 분석 및 시각화
|
||||||
|
- **권한**: Admin 등급 이상 (`admin`, `system`)
|
||||||
|
- **베이스 URL**: `/api/daily-work-reports-analysis`
|
||||||
|
|
||||||
|
#### 9.1.2. 엔드포인트 목록
|
||||||
|
|
||||||
|
| 메서드 | 엔드포인트 | 설명 | 권한 |
|
||||||
|
|--------|------------|------|------|
|
||||||
|
| `GET` | `/filters` | 분석용 필터 데이터 조회 | Admin+ |
|
||||||
|
| `GET` | `/period` | 기간별 종합 분석 | Admin+ |
|
||||||
|
| `GET` | `/project` | 프로젝트별 상세 분석 | Admin+ |
|
||||||
|
| `GET` | `/worker` | 작업자별 상세 분석 | Admin+ |
|
||||||
|
|
||||||
|
#### 9.1.3. 요청/응답 예시
|
||||||
|
|
||||||
|
**필터 데이터 조회:**
|
||||||
|
```http
|
||||||
|
GET /api/daily-work-reports-analysis/filters
|
||||||
|
Authorization: Bearer {jwt_token}
|
||||||
|
```
|
||||||
|
|
||||||
|
**응답:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"data": {
|
||||||
|
"projects": [
|
||||||
|
{"project_id": 1, "project_name": "프로젝트A"}
|
||||||
|
],
|
||||||
|
"workers": [
|
||||||
|
{"worker_id": 1, "worker_name": "홍길동"}
|
||||||
|
],
|
||||||
|
"workTypes": [
|
||||||
|
{"work_type_id": 1, "work_type_name": "설계"}
|
||||||
|
],
|
||||||
|
"dateRange": {
|
||||||
|
"min_date": "2025-01-01",
|
||||||
|
"max_date": "2025-12-31"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**기간별 분석:**
|
||||||
|
```http
|
||||||
|
GET /api/daily-work-reports-analysis/period?start_date=2025-08-01&end_date=2025-08-31&project_id=1
|
||||||
|
Authorization: Bearer {jwt_token}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 9.1.4. 보안 정책
|
||||||
|
- **인증**: JWT 토큰 필수
|
||||||
|
- **권한**: `admin` 또는 `system` 권한 필요
|
||||||
|
- **접근 제어**: 프론트엔드에서 권한 체크 후 페이지 접근 허용
|
||||||
|
- **오류 응답**: 권한 부족 시 403 Forbidden 반환
|
||||||
|
|
||||||
|
#### 9.1.5. 프론트엔드 연동
|
||||||
|
- **페이지**: `/pages/analysis/work-report-analytics.html`
|
||||||
|
- **네비게이션**: Admin 섹션에 `ADMIN` 배지와 함께 표시
|
||||||
|
- **권한 체크**: 페이지 로드 시 localStorage의 사용자 권한 확인
|
||||||
|
|
||||||
|
### 9.2. API 네이밍 규칙
|
||||||
|
|
||||||
|
#### 9.2.1. 라우트 네이밍
|
||||||
|
- **kebab-case** 사용 (예: `daily-work-reports-analysis`)
|
||||||
|
- **복수형 명사** 사용 (예: `reports`, `users`)
|
||||||
|
- **RESTful** 원칙 준수
|
||||||
|
|
||||||
|
#### 9.2.2. 파일 네이밍
|
||||||
|
- **컨트롤러**: `{resource}Controller.js` (camelCase)
|
||||||
|
- **라우트**: `{resource}Routes.js` (camelCase)
|
||||||
|
- **모델**: `{resource}Model.js` (camelCase)
|
||||||
|
|
||||||
---
|
---
|
||||||
본 규칙은 프로젝트 진행 상황에 따라 지속적으로 개선될 수 있습니다.
|
본 규칙은 프로젝트 진행 상황에 따라 지속적으로 개선될 수 있습니다.
|
||||||
Reference in New Issue
Block a user