Compare commits
33 Commits
f88d8e53cb
...
manage
| Author | SHA1 | Date | |
|---|---|---|---|
| b10063a93f | |||
| 930dc2d1de | |||
| 039bc4c5a3 | |||
| d7a322a6ca | |||
| 588d787d02 | |||
| 5f4834de10 | |||
| bf7bf93179 | |||
| 686ea738da | |||
| f636d1c7f8 | |||
| 0bed3c489b | |||
| d75a57cc97 | |||
| df25f04119 | |||
| 79b3fd646e | |||
| b2134d7515 | |||
| 9891ea0a32 | |||
| 21ad66c8b4 | |||
| 68eabcc228 | |||
| fa8eaeef25 | |||
| 61e580b74a | |||
| b3207b5ce0 | |||
| eab0a5bb3f | |||
| c13f596453 | |||
| 7882d0cd05 | |||
| 4827d953d1 | |||
| 868661426f | |||
| 90042a003a | |||
| bc611c3ff7 | |||
| 6e8f606591 | |||
| 01a6e197ce | |||
| d4498c356f | |||
| 47cd2bf5b2 | |||
| 28709a3457 | |||
| b5e121136f |
Binary file not shown.
5130
PTC/dashboard_preview.html
Normal file
5130
PTC/dashboard_preview.html
Normal file
File diff suppressed because it is too large
Load Diff
2027
PTC/index.html
2027
PTC/index.html
File diff suppressed because it is too large
Load Diff
8668
PTC/management_dashboard_preview.html
Normal file
8668
PTC/management_dashboard_preview.html
Normal file
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@
|
|||||||
- [ ] UI 렌더링 완성 (PTC 데이터 선택 시 테이블 공백 문제 해결)
|
- [ ] UI 렌더링 완성 (PTC 데이터 선택 시 테이블 공백 문제 해결)
|
||||||
- [ ] PTC 고유 계정 체계(7xx, 8xx, 513) 분류 로직 고도화
|
- [ ] PTC 고유 계정 체계(7xx, 8xx, 513) 분류 로직 고도화
|
||||||
- [ ] PTC 전용 실행 예산 보고서 양식 개발 및 출력 기능
|
- [ ] PTC 전용 실행 예산 보고서 양식 개발 및 출력 기능
|
||||||
- [ ] PTC 대시보드 고도화 (순유입/유출 잔액 합계 및 시각화 개선)
|
- [x] PTC 대시보드 고도화 (순유입/유출 잔액 합계 및 시각화 개선)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -48,3 +48,15 @@
|
|||||||
- PTC 순유입 및 유출 잔액 합계 산출 로직 개선
|
- PTC 순유입 및 유출 잔액 합계 산출 로직 개선
|
||||||
- 대시보드 상의 차트 및 요약 테이블에 실시간 데이터 반영
|
- 대시보드 상의 차트 및 요약 테이블에 실시간 데이터 반영
|
||||||
- 데이터 동기화 및 탭 전환 최적화
|
- 데이터 동기화 및 탭 전환 최적화
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. [PTC::Dashboard] 통합 대시보드 시각화 및 재무 상태 분석 기능 구현
|
||||||
|
**설명**: 프로젝트 전반의 재무 현황을 시각화하고, 공법 및 금액별로 자동 분류하여 상태를 진단하는 통합 대시보드 기능을 구현합니다.
|
||||||
|
|
||||||
|
### 주요 작업
|
||||||
|
- [x] 공법(Method) 및 제품군(Family)별 프로젝트 자동 분류 로직 구현
|
||||||
|
- [x] 입금/출금 기반 수익률(Margin Rate) 및 진행률(Progress Rate) 연동 시각화
|
||||||
|
- [x] 금액별 버킷(Buckets) 및 재무 상태(Status Bands: 정상, 선투입, 회수지연, 위험) 자동 판별 로직 적용
|
||||||
|
- [x] API 서버(`/api/dashboard-prototype`) 및 프론트엔드 반응형 레이아웃 최적화
|
||||||
|
- [x] Windows 사내망 공유용 PowerShell 자동화 스크립트(`start_ptc_share.ps1`) 개발
|
||||||
|
|||||||
263
README.md
263
README.md
@@ -1,25 +1,258 @@
|
|||||||
# PTC Project Management System
|
# PTC Manage (manage 브랜치)
|
||||||
|
|
||||||
이 프로젝트는 `PTC(2023-2026.02).xlsx` 데이터를 기반으로 한 프로젝트 관리 및 집행 분석 시스템입니다.
|
PTC 실행 원장 기반의 사내 프로젝트 관리/원가 분석 웹앱입니다.
|
||||||
|
`manage` 브랜치는 **프로젝트 관리 + 프로젝트 생애주기 원가 + 관리 대시보드** 운영 기능을 중심으로 유지됩니다.
|
||||||
|
|
||||||
## 주요 구성
|
- 기본 실행 주소: `http://localhost:4000/PTC/`
|
||||||
|
- 관리 실험 화면: `http://localhost:4000/PTC-lab-manage/`
|
||||||
|
- 단일 Python 서버가 API + 프론트를 함께 제공합니다.
|
||||||
|
|
||||||
- **Frontend (`/PTC/index.html`)**: React 기반의 단일 페이지 애플리케이션 (SPA)으로 프로젝트 대시보드 및 예산 관리를 담당합니다.
|
## 1. 현재 브랜치 핵심 기능
|
||||||
- **Backend (`/server/ptc_api_server.py`)**: Python 기반의 API 서버로 SQLite DB를 통해 데이터를 제공합니다.
|
|
||||||
- **Database (`/db/`)**: PostgreSQL 스키마 및 로컬 SQLite DB 관련 스크립트가 포함되어 있습니다.
|
|
||||||
- **Windows Scripts (`/windows/`)**: 로컬 환경에서 서버를 실행하고 공유하기 위한 배치 파일들입니다.
|
|
||||||
|
|
||||||
## 실행 방법
|
- 프로젝트 마스터 관리
|
||||||
|
- 프로젝트명/구분/공법/기간/메모 수정
|
||||||
|
- 프로젝트 간 연관 코드 관리
|
||||||
|
- 프로젝트 관리 탭에서는 거래내역 표를 제거하고, 거래는 `거래내역확인` 탭에서만 조회
|
||||||
|
- 프로젝트 생애주기 원가
|
||||||
|
- 연관 프로젝트(영업/설계/시공) 흐름을 3열 고정 레이아웃으로 조회
|
||||||
|
- 영업/설계 카드 클릭 시 배분 팝업에서 `해당프로젝트/총프로젝트` 저장
|
||||||
|
- 배분값 저장/삭제 후 반영 매출 자동 재계산
|
||||||
|
- 시공 컬럼에 공정률 표시(숫자 강조)
|
||||||
|
- 영업/설계 연결 프로젝트가 없을 때 톤다운된 비어있음 상태 표시
|
||||||
|
- 계정별 금액/항목 목록을 박스형 카드가 아닌 라인형 리스트로 표시
|
||||||
|
- 프로젝트 생애주기 원가 분해
|
||||||
|
- `시공비/인건비/관리비` 상세 모달 제공
|
||||||
|
- 인건비/관리비에 `직접분/공통배분분` 분리 표시
|
||||||
|
- 현재는 연결 프로젝트 비용을 직접분으로 처리(공통배분분은 향후 공통배분 기능 추가 시 반영)
|
||||||
|
- 배분 로직
|
||||||
|
- 예: 설계 프로젝트에 `1/3` 저장 시, 생애주기 화면 반영금액은 해당 프로젝트 금액의 `1/3`
|
||||||
|
- 저장은 `project_lifecycle_allocations` 테이블에 영구 반영
|
||||||
|
- 계정 표시 정책(프로젝트 화면)
|
||||||
|
- `기타 수지/자산` 계정(예: `194 전도금`)은 프로젝트/생애주기 집계 및 상세에서 숨김
|
||||||
|
- 계정 재매핑
|
||||||
|
- 프로젝트별 계정코드 재분류(허용 계정 범위 검증 포함)
|
||||||
|
|
||||||
|
## 2. 기술 스택
|
||||||
|
|
||||||
|
- Backend: Python 3 표준 라이브러리 (`http.server`, `sqlite3` 등)
|
||||||
|
- DB: SQLite (`db/ptc_local.sqlite3`)
|
||||||
|
- Frontend: 정적 HTML 대시보드 페이지 (`PTC/*.html`)
|
||||||
|
- 운영 보조: Windows 배치 스크립트 (`windows/*.bat`)
|
||||||
|
|
||||||
|
별도 백엔드 프레임워크(FastAPI/Flask) 없이 단일 서버 스크립트로 동작합니다.
|
||||||
|
|
||||||
|
## 3. 디렉터리 구조
|
||||||
|
|
||||||
|
```text
|
||||||
|
/home/hyein/project
|
||||||
|
├─ PTC/
|
||||||
|
│ ├─ index.html # 메인 화면
|
||||||
|
│ ├─ dashboard_preview.html # 실험 대시보드
|
||||||
|
│ ├─ admin_dashboard.html # 관리자 화면
|
||||||
|
│ └─ management_dashboard_preview.html # 관리/생애주기 핵심 화면
|
||||||
|
├─ server/
|
||||||
|
│ ├─ ptc_api_server.py # API + 프론트 서빙 서버
|
||||||
|
│ └─ ptc_source_path.txt # 사용할 원본 xlsx 경로 설정값
|
||||||
|
├─ db/
|
||||||
|
│ ├─ ptc_local.sqlite3 # 로컬 DB 파일
|
||||||
|
│ ├─ import_ptc_xlsx.py # xlsx -> staging csv 변환 스크립트
|
||||||
|
│ ├─ schema.sql / seed.sql # (별도 Postgres 실험용)
|
||||||
|
│ └─ README.md
|
||||||
|
├─ windows/
|
||||||
|
│ ├─ start_ptc_share.bat # 사내 공유 실행
|
||||||
|
│ ├─ set_ptc_source.bat # 원본 xlsx 선택/저장
|
||||||
|
│ └─ README.txt
|
||||||
|
└─ README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. 빠른 시작
|
||||||
|
|
||||||
|
### 4.1 요구사항
|
||||||
|
|
||||||
|
- Python 3.10+ 권장
|
||||||
|
- 로컬 파일 접근 권한
|
||||||
|
- 원본 엑셀 파일 존재
|
||||||
|
- 기본: `PTC 입출금내역(2015~).xlsx`
|
||||||
|
|
||||||
|
### 4.2 서버 실행
|
||||||
|
|
||||||
|
프로젝트 루트에서:
|
||||||
|
|
||||||
### 1. API 서버 실행
|
|
||||||
```bash
|
```bash
|
||||||
python3 server/ptc_api_server.py
|
python3 server/ptc_api_server.py
|
||||||
```
|
```
|
||||||
서버는 기본적으로 4000 포트에서 실행됩니다.
|
|
||||||
|
|
||||||
### 2. 프론트엔드 접속
|
실행 후:
|
||||||
`PTC/index.html` 파일을 브라우저로 열거나, 로컬 웹 서버(예: 8000 포트)를 통해 접속합니다.
|
|
||||||
API 서버 주소는 `index.html` 내의 `API_BASE` 변수에서 설정할 수 있습니다.
|
|
||||||
|
|
||||||
## 데이터 업데이트
|
- API Health: `http://localhost:4000/api/health`
|
||||||
`db/import_ptc_xlsx.py` 스크립트를 사용하여 엑셀 데이터를 DB로 변환할 수 있습니다. 자세한 내용은 `db/README.md`를 참조하세요.
|
- 메인 UI: `http://localhost:4000/PTC/`
|
||||||
|
- 관리 UI: `http://localhost:4000/PTC-lab-manage/`
|
||||||
|
|
||||||
|
## 5. 데이터 로딩 방식
|
||||||
|
|
||||||
|
서버 시작 시 `init_db()`가 아래 순서로 동작합니다.
|
||||||
|
|
||||||
|
1. SQLite 스키마/인덱스/마이그레이션 보정
|
||||||
|
2. 원본 xlsx 경로 확인
|
||||||
|
- `server/ptc_source_path.txt` 값이 있으면 우선 사용
|
||||||
|
- 없으면 기본 파일(`PTC 입출금내역(2015~).xlsx`) 사용
|
||||||
|
3. `xlsx_source_signature(경로+mtime)` 비교
|
||||||
|
4. 원본이 바뀐 경우 `ptc_transactions` 전체 재적재
|
||||||
|
5. `project_master` 초기값(프로젝트코드 기준) 자동 보강
|
||||||
|
|
||||||
|
즉, 원본 파일 갱신 시 서버 재시작만으로 로컬 DB가 다시 동기화됩니다.
|
||||||
|
|
||||||
|
## 6. 화면별 URL
|
||||||
|
|
||||||
|
- `/PTC/` : 메인 대시보드
|
||||||
|
- `/PTC-lab/` : 대시보드 실험 화면
|
||||||
|
- `/PTC-admin/` : 관리자 화면
|
||||||
|
- `/PTC-lab-manage/` : 프로젝트 관리/생애주기 원가 화면
|
||||||
|
|
||||||
|
## 7. 프로젝트 생애주기 배분(중요)
|
||||||
|
|
||||||
|
### 7.1 사용 방법
|
||||||
|
|
||||||
|
1. `/PTC-lab-manage/` 접속
|
||||||
|
2. 대상 시공 프로젝트 선택
|
||||||
|
3. `관련 프로젝트 흐름`에서 영업/설계 카드 클릭
|
||||||
|
4. 팝업에서 `해당 프로젝트수`와 `총 프로젝트수` 입력
|
||||||
|
- 예: `1 / 3`
|
||||||
|
5. 저장 시 반영금액 = 원금액 × `(1/3)`
|
||||||
|
|
||||||
|
### 7.2 저장/삭제 API
|
||||||
|
|
||||||
|
- 저장: `POST /api/lifecycle-allocation/upsert`
|
||||||
|
- 삭제: `POST /api/lifecycle-allocation/delete`
|
||||||
|
|
||||||
|
저장 데이터는 `project_lifecycle_allocations` 테이블에 유지되며, 페이지 재진입 후에도 반영됩니다.
|
||||||
|
|
||||||
|
### 7.3 관련 프로젝트 흐름(영업/설계/시공)
|
||||||
|
|
||||||
|
- 컬럼은 항상 `영업/설계/시공` 3개를 고정 표시합니다.
|
||||||
|
- 영업/설계가 없으면 `연결 프로젝트 없음`을 톤다운 텍스트로 보여줍니다.
|
||||||
|
- 시공 컬럼은 현재 프로젝트 기준으로 표시되며, 공정률(`x.x%`)이 헤더에 노출됩니다.
|
||||||
|
- 영업/설계만 배분 팝업 클릭 대상이고, 시공은 읽기 전용입니다.
|
||||||
|
|
||||||
|
### 7.4 프로젝트 생애주기 원가(분해 기준)
|
||||||
|
|
||||||
|
- 상단 요약: `총 입금 / 총 지출 / 총 수익 / 수익률`.
|
||||||
|
- 하단 분해: `시공비 / 인건비 / 관리비` 클릭 시 상세 모달.
|
||||||
|
- 인건비/관리비 상세는 `직접분 / 공통배분분`을 함께 보여줍니다.
|
||||||
|
- 현재 구현 기준:
|
||||||
|
- 연결 프로젝트에 귀속된 비용은 직접분으로 집계
|
||||||
|
- 공통배분분은 0원(향후 공통비 배분 로직 추가 예정)
|
||||||
|
|
||||||
|
## 8. 프로젝트 화면 숨김 계정 정책
|
||||||
|
|
||||||
|
프로젝트/생애주기 관점에서는 특정 계정을 집계에서 완전히 제외합니다.
|
||||||
|
|
||||||
|
- 기준 상수: `PROJECT_VIEW_EXCLUDED_ACCOUNT_CODES`
|
||||||
|
- 포함 예시: `194(전도금)`, `191(출자금)`, `259(선수금)`, `901~904`, `961`, `962`, `999` 등
|
||||||
|
|
||||||
|
의도:
|
||||||
|
|
||||||
|
- 프로젝트 실적(입금/지출/수익) 화면에 불필요한 자산/영업외 항목 노출 방지
|
||||||
|
- 카드 합계와 상세 내역의 해석 일관성 유지
|
||||||
|
|
||||||
|
## 9. 주요 DB 테이블
|
||||||
|
|
||||||
|
- `ptc_transactions`
|
||||||
|
- 원본 거래 행(정규화 포함) 저장
|
||||||
|
- `project_master`
|
||||||
|
- 프로젝트 마스터(명칭/구분/공법/기간/메모)
|
||||||
|
- `project_relations`
|
||||||
|
- 프로젝트 간 연관 관계
|
||||||
|
- `project_lifecycle_allocations`
|
||||||
|
- 생애주기 배분값(`분자/분모`) 저장
|
||||||
|
- `project_budget_lines`, `project_budget_account_lines`
|
||||||
|
- 프로젝트 예산 라인
|
||||||
|
- `project_progress`, `project_pile_progress_entries`
|
||||||
|
- 공정/말뚝 진행 데이터
|
||||||
|
- `meta`
|
||||||
|
- 원본 시그니처 등 시스템 메타
|
||||||
|
|
||||||
|
## 10. 주요 API
|
||||||
|
|
||||||
|
### 10.1 GET
|
||||||
|
|
||||||
|
- `GET /api/health` : 서버/적재건수
|
||||||
|
- `GET /api/summary` : 전체 요약
|
||||||
|
- `GET /api/project-types` : 프로젝트 구분 목록
|
||||||
|
- `GET /api/projects` : 프로젝트 목록/검색
|
||||||
|
- `GET /api/project-detail` : 프로젝트 상세
|
||||||
|
- `GET /api/project-budget-actual-detail` : 예산 vs 실적 상세
|
||||||
|
- `GET /api/lifecycle-account-detail` : 생애주기 계정 상세
|
||||||
|
- `GET /api/management-overview` : 관리 화면 요약
|
||||||
|
- `GET /api/management-overview-accounts` : 관리 화면 계정집계
|
||||||
|
- `GET /api/transactions` : 원장 행 미리보기
|
||||||
|
|
||||||
|
`GET /api/project-detail` 응답의 `related_projects` 항목에는 시공 공정률(`progress_rate`)이 포함됩니다.
|
||||||
|
|
||||||
|
### 10.2 POST
|
||||||
|
|
||||||
|
- `POST /api/project-master/upsert` : 프로젝트 마스터 저장
|
||||||
|
- `POST /api/lifecycle-allocation/upsert` : 생애주기 배분 저장
|
||||||
|
- `POST /api/lifecycle-allocation/delete` : 생애주기 배분 삭제
|
||||||
|
- `POST /api/project-master/batch-update-method` : 공법 일괄 업데이트
|
||||||
|
- `POST /api/project-account-remap` : 프로젝트 계정 재매핑
|
||||||
|
- `POST /api/project-account-remap-rows` : 행 단위 재매핑
|
||||||
|
- `POST /api/project-budget/upsert` : 프로젝트 예산 저장
|
||||||
|
- `POST /api/project-pile-progress/upsert` : 말뚝 진행 저장
|
||||||
|
|
||||||
|
## 11. 운영 스크립트 (Windows)
|
||||||
|
|
||||||
|
`windows/README.txt` 기준 요약:
|
||||||
|
|
||||||
|
- `set_ptc_source.bat` : 사용할 원본 `.xlsx` 선택 + 서버 재시작
|
||||||
|
- `start_ptc_share.bat` : WSL 서버 시작/방화벽/공유 주소 안내
|
||||||
|
- `check_ptc_share.bat` : 공유 상태 확인
|
||||||
|
- `stop_ptc_share.bat` : 공유 중지
|
||||||
|
- `install_ptc_share_autostart.bat` : 로그인 시 자동 실행 등록
|
||||||
|
|
||||||
|
## 12. 트러블슈팅
|
||||||
|
|
||||||
|
### 12.1 화면에 "PTC 화면을 준비하는 중입니다"만 보일 때
|
||||||
|
|
||||||
|
- 프론트 스크립트 에러 가능성이 큽니다.
|
||||||
|
- 최근 이슈 예: nullish 연산자(`??`) + 논리연산자 혼용 시 괄호 누락
|
||||||
|
- 대응:
|
||||||
|
1. 브라우저 새로고침(강력 새로고침)
|
||||||
|
2. 서버 재시작
|
||||||
|
3. 콘솔 에러 라인 확인 후 `PTC/management_dashboard_preview.html` 수정
|
||||||
|
|
||||||
|
### 12.2 배분값 저장 후 다시 1/1로 보일 때
|
||||||
|
|
||||||
|
- 저장 API 호출 실패 또는 validation 실패 가능성
|
||||||
|
- 확인:
|
||||||
|
- `allocation_numerator <= allocation_denominator`
|
||||||
|
- `allocation_denominator > 0`
|
||||||
|
- `base_project_code`, `source_project_code` 누락 여부
|
||||||
|
|
||||||
|
### 12.3 카드 금액과 상세 내역이 다르게 느껴질 때
|
||||||
|
|
||||||
|
- 프로젝트 화면에서는 숨김 계정 정책이 적용됩니다.
|
||||||
|
- `기타 수지/자산` 계정은 의도적으로 상세/집계에서 제외됩니다.
|
||||||
|
|
||||||
|
### 12.4 코드 수정 후 화면이 이전 동작으로 보일 때
|
||||||
|
|
||||||
|
- 서버 프로세스가 이전 코드를 계속 실행 중일 수 있습니다.
|
||||||
|
- `server/ptc_api_server.py` 수정 후에는 서버를 재시작해 최신 로직(배분/공정률/직접분-공통배분분 집계)이 반영되었는지 확인하세요.
|
||||||
|
|
||||||
|
## 13. 개발 시 참고
|
||||||
|
|
||||||
|
- 현재 서버는 단일 파일(`server/ptc_api_server.py`) 중심 구조입니다.
|
||||||
|
- 스키마 변경 시 `init_db()`의 `pragma table_info` 기반 보정 로직을 같이 업데이트하세요.
|
||||||
|
- UI 변경 시 관리 화면 파일:
|
||||||
|
- `PTC/management_dashboard_preview.html`
|
||||||
|
|
||||||
|
## 14. 커밋/브랜치 운영 권장
|
||||||
|
|
||||||
|
- 운영 브랜치: `manage`
|
||||||
|
- 기능 단위로 커밋 분리
|
||||||
|
- 예: `feat(lifecycle): ...`, `fix(project-view): ...`
|
||||||
|
- 데이터 파일(`.xlsx`, `.sqlite3`)은 가급적 직접 커밋하지 않고 경로/절차 중심으로 관리
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
문의/개선 시에는 **재현 경로(화면 URL + 프로젝트코드 + 계정코드 + 날짜 범위)**를 함께 남기면 원인 분석이 훨씬 빨라집니다.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
1
server/ptc_source_path.txt
Normal file
1
server/ptc_source_path.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/home/hyein/project/PTC 입출금내역(2015~).xlsx
|
||||||
@@ -1,14 +1,19 @@
|
|||||||
사용 파일
|
사용 파일
|
||||||
- start_ptc_share.bat : 관리자 권한으로 실행되며, WSL 서버 시작 + portproxy + 방화벽까지 자동 설정
|
- start_ptc_share.bat : 공유용 실행 파일. 관리자 권한으로 다시 실행되어 WSL 서버 시작, IP 공유 설정, 방화벽 허용, 공유 주소 복사까지 처리합니다.
|
||||||
|
- install_ptc_share_autostart.bat : Windows 로그인 시 자동으로 공유가 시작되도록 작업 스케줄러에 등록합니다.
|
||||||
|
- remove_ptc_share_autostart.bat : 자동 실행 등록을 해제합니다.
|
||||||
|
- set_ptc_source.bat : 사용할 PTC 원본 `.xlsx` 파일을 선택하고 저장한 뒤 서버를 다시 시작합니다.
|
||||||
- stop_ptc_share.bat : 공유 중지
|
- stop_ptc_share.bat : 공유 중지
|
||||||
- check_ptc_share.bat : 현재 공유 상태 확인
|
- check_ptc_share.bat : 현재 공유 상태 확인
|
||||||
|
|
||||||
사용 순서
|
사용 순서
|
||||||
1. start_ptc_share.bat 실행
|
1. 원본 파일을 바꾸려면 set_ptc_source.bat 실행
|
||||||
2. 브라우저에서 http://172.16.40.36:8000/PTC/ 확인
|
2. start_ptc_share.bat 실행
|
||||||
3. 안 되면 check_ptc_share.bat 실행
|
3. 같은 PC에서는 `http://localhost:4000/PTC/` 확인
|
||||||
|
4. 다른 사람에게는 배치파일이 출력한 `http://내PCIP:4000/PTC/` 주소 전달
|
||||||
|
4. 안 되면 check_ptc_share.bat 실행
|
||||||
|
|
||||||
주의
|
주의
|
||||||
- PC가 켜져 있어야 합니다.
|
- PC가 켜져 있어야 합니다.
|
||||||
- WSL이 재시작되어 IP가 바뀌면 start_ptc_share.bat 를 다시 실행하세요.
|
- WSL이 재시작되어 IP가 바뀌면 start_ptc_share.bat 를 다시 실행하세요.
|
||||||
- 관리자 권한이 필요합니다.
|
- 이제 프론트와 API를 모두 4000 포트 하나로 제공합니다.
|
||||||
|
|||||||
@@ -1,20 +1,23 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal EnableExtensions
|
setlocal EnableExtensions
|
||||||
|
set "HOST_IP=172.16.40.36"
|
||||||
|
|
||||||
echo [Windows portproxy]
|
echo [Windows portproxy]
|
||||||
netsh interface portproxy show v4tov4
|
netsh interface portproxy show v4tov4
|
||||||
echo.
|
echo.
|
||||||
echo [WSL web]
|
|
||||||
wsl.exe bash -lc "curl -I -s http://127.0.0.1:8000/PTC/ | head -n 1"
|
|
||||||
echo.
|
|
||||||
echo [WSL api]
|
echo [WSL api]
|
||||||
wsl.exe bash -lc "curl -s http://127.0.0.1:4000/api/health"
|
wsl.exe bash -lc "curl -s http://127.0.0.1:4000/api/health"
|
||||||
echo.
|
echo.
|
||||||
|
echo [WSL web]
|
||||||
|
wsl.exe bash -lc "curl -I -s http://127.0.0.1:4000/PTC-lab/ | head -n 1"
|
||||||
|
echo.
|
||||||
|
echo [WSL manage web]
|
||||||
|
wsl.exe bash -lc "curl -I -s http://127.0.0.1:4000/PTC-lab-manage/ | head -n 1"
|
||||||
|
echo.
|
||||||
echo [Office LAN web]
|
echo [Office LAN web]
|
||||||
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://172.16.40.36:8000/PTC/' -UseBasicParsing -TimeoutSec 5).StatusCode } catch { $_.Exception.Message }"
|
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://%HOST_IP%:4000/PTC-lab-manage/' -UseBasicParsing -TimeoutSec 5).StatusCode } catch { $_.Exception.Message }"
|
||||||
echo.
|
echo.
|
||||||
echo [Office LAN api]
|
echo [Office LAN api]
|
||||||
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://172.16.40.36:4000/api/health' -UseBasicParsing -TimeoutSec 5).Content } catch { $_.Exception.Message }"
|
powershell -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://%HOST_IP%:4000/api/health' -UseBasicParsing -TimeoutSec 5).Content } catch { $_.Exception.Message }"
|
||||||
echo.
|
echo.
|
||||||
pause
|
pause
|
||||||
|
|
||||||
|
|||||||
42
windows/set_ptc_source.bat
Normal file
42
windows/set_ptc_source.bat
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal EnableExtensions
|
||||||
|
|
||||||
|
set "CONFIG_PATH=/home/hyein/project/server/ptc_source_path.txt"
|
||||||
|
set "SELECTED_FILE="
|
||||||
|
set "WSL_SOURCE_PATH="
|
||||||
|
|
||||||
|
for /f "usebackq delims=" %%i in (`powershell -NoProfile -STA -Command "Add-Type -AssemblyName System.Windows.Forms; $dialog = New-Object System.Windows.Forms.OpenFileDialog; $dialog.Filter = 'Excel Files (*.xlsx)|*.xlsx'; $dialog.Title = 'PTC 원본 엑셀 파일 선택'; $dialog.InitialDirectory = [Environment]::GetFolderPath('Desktop'); if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { $dialog.FileName }"`) do (
|
||||||
|
set "SELECTED_FILE=%%i"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%SELECTED_FILE%"=="" (
|
||||||
|
echo 파일 선택이 취소되었습니다.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo 선택한 파일:
|
||||||
|
echo %SELECTED_FILE%
|
||||||
|
|
||||||
|
for /f "usebackq delims=" %%i in (`wsl.exe wslpath -a "%SELECTED_FILE%"`) do (
|
||||||
|
set "WSL_SOURCE_PATH=%%i"
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%WSL_SOURCE_PATH%"=="" (
|
||||||
|
echo WSL 경로 변환에 실패했습니다.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
wsl.exe bash -lc "printf '%s\n' \"%WSL_SOURCE_PATH%\" > %CONFIG_PATH%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo 원본 파일 설정 저장에 실패했습니다.
|
||||||
|
pause
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo 설정 저장 완료
|
||||||
|
echo 다음 실행부터 이 파일을 사용합니다.
|
||||||
|
echo.
|
||||||
|
echo 바로 서버를 다시 시작합니다...
|
||||||
|
call "%~dp0start_ptc_share.bat"
|
||||||
@@ -1,70 +1,7 @@
|
|||||||
@echo off
|
@echo off
|
||||||
setlocal EnableExtensions EnableDelayedExpansion
|
setlocal
|
||||||
|
pushd "%~dp0" >nul 2>&1
|
||||||
set "PROJECT_DIR=/home/hyein/project"
|
powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0start_ptc_share.ps1"
|
||||||
set "WEB_PORT=8000"
|
set "EXIT_CODE=%ERRORLEVEL%"
|
||||||
set "API_PORT=4000"
|
popd >nul 2>&1
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
net session >nul 2>&1
|
|
||||||
if not "%errorlevel%"=="0" (
|
|
||||||
echo 관리자 권한으로 다시 실행합니다...
|
|
||||||
powershell -NoProfile -ExecutionPolicy Bypass -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
|
||||||
exit /b
|
|
||||||
)
|
|
||||||
|
|
||||||
echo WSL IP 확인 중...
|
|
||||||
for /f "usebackq delims=" %%i in (`wsl.exe bash -lc "hostname -I | cut -d' ' -f1"`) do (
|
|
||||||
set "WSL_IP=%%i"
|
|
||||||
)
|
|
||||||
|
|
||||||
if "%WSL_IP%"=="" (
|
|
||||||
echo WSL IP를 확인하지 못했습니다.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
echo WSL IP: %WSL_IP%
|
|
||||||
echo 기존 서버 정리 및 재실행 중...
|
|
||||||
wsl.exe bash -lc "pkill -f 'python3 -m http.server 8000' >/dev/null 2>&1 || true; pkill -f '/home/hyein/project/server/ptc_api_server.py' >/dev/null 2>&1 || true; nohup python3 -m http.server 8000 --directory /home/hyein/project >/tmp/ptc_web.log 2>&1 & nohup python3 /home/hyein/project/server/ptc_api_server.py >/tmp/ptc_api.log 2>&1 & sleep 2"
|
|
||||||
|
|
||||||
echo 포트포워딩 갱신 중...
|
|
||||||
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=%WEB_PORT% >nul 2>&1
|
|
||||||
netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=%API_PORT% >nul 2>&1
|
|
||||||
|
|
||||||
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=%WEB_PORT% connectaddress=%WSL_IP% connectport=%WEB_PORT%
|
|
||||||
if errorlevel 1 (
|
|
||||||
echo 8000 포트포워딩 설정에 실패했습니다.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=%API_PORT% connectaddress=%WSL_IP% connectport=%API_PORT%
|
|
||||||
if errorlevel 1 (
|
|
||||||
echo 4000 포트포워딩 설정에 실패했습니다.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
echo 방화벽 규칙 적용 중...
|
|
||||||
netsh advfirewall firewall delete rule name="PTC 8000" >nul 2>&1
|
|
||||||
netsh advfirewall firewall delete rule name="PTC 4000" >nul 2>&1
|
|
||||||
netsh advfirewall firewall add rule name="PTC 8000" dir=in action=allow protocol=TCP localport=%WEB_PORT% >nul
|
|
||||||
netsh advfirewall firewall add rule name="PTC 4000" dir=in action=allow protocol=TCP localport=%API_PORT% >nul
|
|
||||||
|
|
||||||
echo 서버 상태 확인 중...
|
|
||||||
wsl.exe bash -lc "curl -s http://127.0.0.1:4000/api/health >/tmp/ptc_api_health.json && curl -I -s http://127.0.0.1:8000/PTC/ >/tmp/ptc_web_health.txt"
|
|
||||||
if errorlevel 1 (
|
|
||||||
echo WSL 내부 서버 확인에 실패했습니다.
|
|
||||||
echo /tmp/ptc_api.log 와 /tmp/ptc_web.log 를 확인해 주세요.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo 공유 준비 완료
|
|
||||||
echo 메인 화면: http://172.16.40.36:%WEB_PORT%/PTC/
|
|
||||||
echo API 안내 : http://172.16.40.36:%API_PORT%/
|
|
||||||
echo.
|
|
||||||
echo 참고: WSL이 재시작되어 IP가 바뀌면 이 파일을 다시 실행하세요.
|
|
||||||
pause
|
|
||||||
|
|
||||||
|
|||||||
135
windows/start_ptc_share.ps1
Normal file
135
windows/start_ptc_share.ps1
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
param(
|
||||||
|
[switch]$NoBrowser,
|
||||||
|
[switch]$NoPause
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
function Test-IsAdmin {
|
||||||
|
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||||
|
$principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
|
||||||
|
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-IsAdmin)) {
|
||||||
|
$childArgs = @(
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy", "Bypass",
|
||||||
|
"-File", "`"$PSCommandPath`""
|
||||||
|
)
|
||||||
|
if ($NoBrowser) { $childArgs += "-NoBrowser" }
|
||||||
|
if ($NoPause) { $childArgs += "-NoPause" }
|
||||||
|
Start-Process -FilePath "powershell.exe" -Verb RunAs -ArgumentList @(
|
||||||
|
$childArgs
|
||||||
|
)
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
$projectDir = "/home/hyein/project"
|
||||||
|
$apiPort = 4000
|
||||||
|
$localUrl = "http://localhost:$apiPort/PTC-lab-manage/"
|
||||||
|
$preferredLanIp = "172.16.40.36"
|
||||||
|
$defaultSource = "/home/hyein/project/PTC(2023-2026.02).xlsx"
|
||||||
|
$sourceConfigPath = "/home/hyein/project/server/ptc_source_path.txt"
|
||||||
|
|
||||||
|
function Invoke-WslBash([string]$command) {
|
||||||
|
$output = & wsl.exe bash -lc $command 2>&1
|
||||||
|
$exitCode = $LASTEXITCODE
|
||||||
|
return [PSCustomObject]@{
|
||||||
|
Output = @($output)
|
||||||
|
ExitCode = $exitCode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$currentSourceResult = Invoke-WslBash "cat '$sourceConfigPath' 2>/dev/null || printf '%s\n' '$defaultSource'"
|
||||||
|
$currentSource = ($currentSourceResult.Output | Select-Object -First 1).Trim()
|
||||||
|
if ([string]::IsNullOrWhiteSpace($currentSource)) {
|
||||||
|
$currentSource = $defaultSource
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Starting PTC server..."
|
||||||
|
Write-Host "Source file: $currentSource"
|
||||||
|
|
||||||
|
$startResult = Invoke-WslBash "pkill -f '/home/hyein/project/server/ptc_api_server.py' >/dev/null 2>&1 || true; nohup python3 /home/hyein/project/server/ptc_api_server.py >/tmp/ptc_api.log 2>&1 & sleep 3"
|
||||||
|
if ($startResult.ExitCode -ne 0) {
|
||||||
|
Write-Host "Failed to start the server in WSL." -ForegroundColor Red
|
||||||
|
if (-not $NoPause) {
|
||||||
|
Read-Host "Press Enter to exit"
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$healthResult = Invoke-WslBash "curl -fsS http://127.0.0.1:$apiPort/api/health >/tmp/ptc_api_health.json && curl -fsSI http://127.0.0.1:$apiPort/PTC-lab/ >/tmp/ptc_web_health.txt && curl -fsSI http://127.0.0.1:$apiPort/PTC-lab-manage/ >/tmp/ptc_manage_web_health.txt"
|
||||||
|
if ($healthResult.ExitCode -ne 0) {
|
||||||
|
Write-Host "Local server check failed. Recent server log:" -ForegroundColor Red
|
||||||
|
$logResult = Invoke-WslBash "tail -n 80 /tmp/ptc_api.log"
|
||||||
|
$logResult.Output | ForEach-Object { Write-Host $_ }
|
||||||
|
if (-not $NoPause) {
|
||||||
|
Read-Host "Press Enter to exit"
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $NoBrowser) {
|
||||||
|
Start-Process $localUrl
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Local URL: $localUrl"
|
||||||
|
|
||||||
|
$lanIps = @(Get-NetIPAddress -AddressFamily IPv4 |
|
||||||
|
Where-Object {
|
||||||
|
$_.IPAddress -notlike '127.*' -and
|
||||||
|
$_.IPAddress -notlike '169.254.*' -and
|
||||||
|
$_.PrefixOrigin -ne 'WellKnown'
|
||||||
|
} |
|
||||||
|
Sort-Object InterfaceMetric, SkipAsSource |
|
||||||
|
Select-Object -ExpandProperty IPAddress)
|
||||||
|
|
||||||
|
$lanIp = $lanIps | Select-Object -First 1
|
||||||
|
|
||||||
|
$wslIpResult = Invoke-WslBash "hostname -I | awk '{print \$1}'"
|
||||||
|
$wslIp = ($wslIpResult.Output | Select-Object -First 1).Trim()
|
||||||
|
|
||||||
|
if (-not [string]::IsNullOrWhiteSpace($lanIp) -and -not [string]::IsNullOrWhiteSpace($wslIp)) {
|
||||||
|
Write-Host "Configuring LAN sharing..."
|
||||||
|
& netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=$apiPort | Out-Null
|
||||||
|
& netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=$apiPort connectaddress=$wslIp connectport=$apiPort | Out-Null
|
||||||
|
& netsh advfirewall firewall delete rule name="PTC 4000" | Out-Null
|
||||||
|
& netsh advfirewall firewall add rule name="PTC 4000" dir=in action=allow protocol=TCP localport=$apiPort | Out-Null
|
||||||
|
|
||||||
|
if (-not ($lanIps -contains $preferredLanIp)) {
|
||||||
|
Write-Host "Preferred share IP $preferredLanIp is not assigned on this PC." -ForegroundColor Red
|
||||||
|
Write-Host "Detected Windows IPs: $($lanIps -join ', ')" -ForegroundColor Yellow
|
||||||
|
if (-not $NoPause) {
|
||||||
|
Read-Host "Press Enter to exit"
|
||||||
|
}
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$shareIp = $preferredLanIp
|
||||||
|
$shareUrl = "http://$shareIp:$apiPort/PTC-lab-manage/"
|
||||||
|
Write-Host "Windows IP: $lanIp"
|
||||||
|
Write-Host "Preferred share IP in use: $shareIp"
|
||||||
|
Write-Host "WSL IP: $wslIp"
|
||||||
|
Write-Host "LAN URL: $shareUrl"
|
||||||
|
Set-Clipboard -Value $shareUrl
|
||||||
|
Write-Host "The share URL has been copied to the clipboard."
|
||||||
|
|
||||||
|
try {
|
||||||
|
$lanWebStatus = (Invoke-WebRequest -Uri $shareUrl -UseBasicParsing -TimeoutSec 5).StatusCode
|
||||||
|
$lanApiStatus = (Invoke-WebRequest -Uri "http://$shareIp:$apiPort/api/health" -UseBasicParsing -TimeoutSec 5).StatusCode
|
||||||
|
Write-Host "LAN web check: $lanWebStatus"
|
||||||
|
Write-Host "LAN api check: $lanApiStatus"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "LAN check failed for $shareIp:$apiPort" -ForegroundColor Red
|
||||||
|
Write-Host $_.Exception.Message -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "LAN sharing was skipped because Windows IP or WSL IP could not be detected."
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not $NoPause) {
|
||||||
|
Read-Host "Press Enter to close"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user