From 844a1d50fcc1bc536e31f8b618ba9d2c31c30d8d Mon Sep 17 00:00:00 2001 From: hyeongwoo-choi Date: Mon, 20 Jul 2026 00:32:53 +0000 Subject: [PATCH] =?UTF-8?q?=ED=94=84=EB=A1=A0=ED=8A=B8=20=EC=A0=84?= =?UTF-8?q?=EB=A9=B4=20=EA=B5=AC=EC=84=B1:=20330=EA=B0=9C=20=EC=A0=84=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=99=94=EB=A9=B4=20=ED=8F=AC?= =?UTF-8?q?=ED=84=B8=20(=EB=A7=A4=EB=8B=88=ED=8E=98=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=9E=90=EB=8F=99=EC=83=9D=EC=84=B1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tools/gen_screens.py: svc 소스에서 입력(getl/gets_)·출력(setl/sets) 필드와 한글 설명을 추출해 app/ui/screens.js(330 화면 매니페스트) 생성 - index.html 확장: 모듈별 메뉴트리(11그룹×30화면) + 화면검색 + 주요업무 즐겨찾기 9종, 화면별 입력폼 자동구성(한글라벨·기본값), 조회성 화면 XA 자동 off, 결과그리드·거래저널 - README: 화면 계층(4.0) 문서화 - 검증: screens.js 서빙, ACQ_DUPCHK(조회)·RC_STATS(통계)·MM_MERCH_REG(XA 등록) 실호출 정상 Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 21 +- app/ui/index.html | 238 ++- app/ui/screens.js | 4304 ++++++++++++++++++++++++++++++++++++++++++ tools/gen_screens.py | 30 + 4 files changed, 4488 insertions(+), 105 deletions(-) create mode 100644 app/ui/screens.js create mode 100755 tools/gen_screens.py diff --git a/README.md b/README.md index 23800b7..d56b82a 100644 --- a/README.md +++ b/README.md @@ -84,13 +84,16 @@ acquire-core-x/ │ ├─ conf/ # app.ini(CCONFIG), ndrxconfig.xml(생성), setapp.sh(XA env) │ ├─ ubftab/acq.fd # UBF 필드테이블 (전 모듈 공용) │ ├─ build.sh # 모듈 자동발견 빌드 + ndrxconfig 생성 -│ ├─ entrypoint.sh # 빌드 → ndrxd 기동 +│ ├─ entrypoint.sh # 빌드 → ndrxd 기동 (+ 업무화면 게이트웨이 :8090) +│ ├─ ui/ # 업무화면 포털 (index.html + screens.js — 330 화면 매니페스트) │ └─ src// # 11개 모듈 (ac au rc st py lg cl mm vl mg cm) │ ├─ _svr.pgc # 얇은 모듈 서버(디스패처) │ ├─ svc/*.pgc + *.h # 1서비스=1파일 + 카피북 (모듈당 30) │ ├─ dbio/*.pgc + *.h # DB 접근 계층 (모듈당 ~40) │ ├─ batch/*.pgc # XA 배치 (모듈당 ~22) │ └─ run/*.sh # 운영 기동 스크립트 (모듈당 ~17) +├─ tools/ +│ └─ gen_screens.py # svc 소스 → 화면 매니페스트(screens.js) 재생성기 └─ docs/ ├─ architecture.md # 상세 아키텍처 └─ service-catalog.md # 서비스 카탈로그 @@ -105,7 +108,20 @@ docker compose -f docker/docker-compose.yml up -d --build # postgres + endur ``` 빌드(전 모듈 ecpg→buildserver, ~240 배치 컴파일)는 수 분 걸린다. 완료되면 `ndrxd`가 -11개 모듈 서버 + `tmsrv`를 부팅한다. +11개 모듈 서버 + `tmsrv`를 부팅하고, **업무화면 포털**이 http://localhost:8090/ 에 뜬다. + +### 4.0 업무화면 (프론트 — RFI의 Xplatform 내부화면 포지션) + +``` +브라우저 업무화면(app/ui, Xplatform풍) → acq_httpgw(C, Webtier 포지션) → tpcall → 모듈서버 → PostgreSQL +``` +- `app/src/clients/acq_httpgw.c` — C 경량 HTTP 게이트웨이(:8090, libatmiclt만 링크). + `GET /api/call?svc=&_tx=1&T_필드=값...` → UBF 구성(CBchg) → (옵션) 글로벌 XA + `tpbegin/tpcommit` → `tpcall` → 응답 UBF 전체를 JSON 직렬화. +- `app/ui/index.html` + `screens.js` — 한국어 업무포털. **330개 전 서비스가 화면으로 노출** + (모듈별 메뉴트리·검색·주요업무 즐겨찾기 9종). 각 화면의 입력폼은 해당 tpservice 소스에서 + 추출한 실제 입력 필드(getl/gets_)로 자동 구성되며(`tools/gen_screens.py`), 실행 시 실제 + tpcall 이 돌고 결과 그리드·거래 저널에 표시된다. ### 4.1 필수 런타임 요건 (없으면 ndrxd 부팅 실패 — 실측으로 규명) @@ -218,4 +234,5 @@ $C exec db psql -U acq -d acq -c "select count(*) from pg_prepared_xacts;" # 0 - [x] ECPG XA 서비스 체인(매입→대사→정산) + 커밋 row psql 검증 + 롤백(`prepared_xacts=0`) - [x] 2,000본+ 실동작 시스템 (2,052 파일 / `.pgc` 1,015본, 전 모듈 dbio·batch 세분화) - [x] 전 `.pgc` 정규화-고유 (클론 0) +- [x] 업무화면 포털(:8090) — 330 화면, HTTP→tpcall 게이트웨이, 화면에서 XA 체인 실행 검증 - [ ] Klaro Forge 마이그레이션 → Spring Boot (Phase 3, 예정) diff --git a/app/ui/index.html b/app/ui/index.html index d0096be..6e21144 100644 --- a/app/ui/index.html +++ b/app/ui/index.html @@ -9,8 +9,7 @@ html, body { height: 100%; font-family: "Malgun Gothic", "맑은 고딕", Dotum, sans-serif; font-size: 12px; color: #222; } body { display: flex; flex-direction: column; background: #e8ebef; } - /* 상단 타이틀바 */ - #titlebar { height: 44px; background: linear-gradient(#2c5d8f, #1d4269); color: #fff; display: flex; align-items: center; padding: 0 14px; } + #titlebar { height: 44px; background: linear-gradient(#2c5d8f, #1d4269); color: #fff; display: flex; align-items: center; padding: 0 14px; flex-shrink: 0; } #titlebar .logo { font-size: 16px; font-weight: bold; letter-spacing: 1px; } #titlebar .sub { margin-left: 12px; font-size: 11px; color: #bcd3e8; } #titlebar .right { margin-left: auto; font-size: 11px; color: #d6e4f2; } @@ -19,36 +18,41 @@ #main { flex: 1; display: flex; min-height: 0; } /* 좌측 메뉴 트리 */ - #menu { width: 208px; background: #f4f6f8; border-right: 1px solid #b8c2cc; overflow-y: auto; } - #menu .grp { padding: 7px 10px; background: #dbe3ea; border-bottom: 1px solid #c3cdd6; font-weight: bold; color: #2c4a66; cursor: default; } - #menu .itm { padding: 6px 10px 6px 22px; border-bottom: 1px solid #e6eaee; cursor: pointer; color: #333; } + #menuwrap { width: 232px; background: #f4f6f8; border-right: 1px solid #b8c2cc; display: flex; flex-direction: column; } + #menusearch { padding: 6px; border-bottom: 1px solid #ccd4dc; } + #menusearch input { width: 100%; height: 24px; border: 1px solid #9aa8b5; padding: 0 8px; font-size: 12px; } + #menu { flex: 1; overflow-y: auto; } + #menu .grp { padding: 7px 10px; background: #dbe3ea; border-bottom: 1px solid #c3cdd6; font-weight: bold; color: #2c4a66; cursor: pointer; display: flex; } + #menu .grp .cnt { margin-left: auto; font-weight: normal; color: #7b8a99; font-size: 10px; } + #menu .grp::before { content: "▸ "; color: #7b8a99; } + #menu .grp.open::before { content: "▾ "; } + #menu .itm { padding: 5px 8px 5px 22px; border-bottom: 1px solid #e6eaee; cursor: pointer; color: #333; + white-space: nowrap; overflow: hidden; text-overflow: ellipsis; display: none; } + #menu .grp.open + .itms .itm, #menu .itms.show .itm { display: block; } #menu .itm:hover { background: #e8f0f8; } #menu .itm.on { background: #cfe0f0; color: #14487c; font-weight: bold; } - #menu .itm .cd { color: #888; font-size: 10px; margin-right: 5px; } + #menu .itm .cd { color: #888; font-size: 10px; margin-right: 5px; font-family: Consolas, monospace; } - /* 컨텐츠 */ #content { flex: 1; display: flex; flex-direction: column; min-width: 0; } - #tabbar { height: 30px; background: #d5dce3; border-bottom: 1px solid #a9b4bf; display: flex; align-items: flex-end; padding: 0 8px; } + #tabbar { height: 30px; background: #d5dce3; border-bottom: 1px solid #a9b4bf; display: flex; align-items: flex-end; padding: 0 8px; flex-shrink: 0; } #tabbar .tab { padding: 5px 16px 4px; background: #fff; border: 1px solid #a9b4bf; border-bottom: none; font-weight: bold; color: #1d4269; } #work { flex: 1; overflow: auto; padding: 12px; } .panel { background: #fff; border: 1px solid #b0bac4; margin-bottom: 12px; } - .panel h3 { font-size: 12px; padding: 6px 10px; background: #eef2f6; border-bottom: 1px solid #ccd4dc; - color: #1d4269; display: flex; align-items: center; } - .panel h3::before { content: ""; width: 4px; height: 12px; background: #2c5d8f; margin-right: 6px; } + .panel h3 { font-size: 12px; padding: 6px 10px; background: #eef2f6; border-bottom: 1px solid #ccd4dc; color: #1d4269; display: flex; align-items: center; } + .panel h3::before { content: ""; width: 4px; height: 12px; background: #2c5d8f; margin-right: 6px; flex-shrink: 0; } .panel .bd { padding: 10px; } - /* 폼 */ table.frm { border-collapse: collapse; width: 100%; } - table.frm th { background: #f0f3f6; border: 1px solid #d3dae1; padding: 5px 8px; text-align: right; width: 130px; font-weight: normal; color: #445; } + table.frm th { background: #f0f3f6; border: 1px solid #d3dae1; padding: 5px 8px; text-align: right; width: 150px; font-weight: normal; color: #445; } table.frm td { border: 1px solid #d3dae1; padding: 3px 6px; } - table.frm input { width: 100%; max-width: 260px; height: 22px; border: 1px solid #9aa8b5; padding: 0 6px; font-size: 12px; } + table.frm input[type=text] { width: 100%; max-width: 280px; height: 22px; border: 1px solid #9aa8b5; padding: 0 6px; font-size: 12px; } + table.frm .fldcd { color: #98a4b0; font-size: 10px; margin-left: 8px; font-family: Consolas, monospace; } .btnrow { margin-top: 10px; text-align: right; } button { height: 26px; padding: 0 16px; margin-left: 6px; background: linear-gradient(#fdfdfd, #dfe5ea); border: 1px solid #8fa0b0; cursor: pointer; font-size: 12px; } button.pri { background: linear-gradient(#3f76ad, #29578a); color: #fff; border-color: #1d4269; font-weight: bold; } button:hover { filter: brightness(1.06); } - /* 그리드 */ table.grd { border-collapse: collapse; width: 100%; } table.grd th { background: #dfe6ec; border: 1px solid #b8c2cc; padding: 4px 6px; color: #2c4a66; } table.grd td { border: 1px solid #d3dae1; padding: 3px 6px; background: #fff; } @@ -57,8 +61,7 @@ .ok { color: #0a7d2c; font-weight: bold; } .err { color: #c22; font-weight: bold; } - #statusbar { height: 24px; background: #d5dce3; border-top: 1px solid #a9b4bf; display: flex; align-items: center; - padding: 0 10px; font-size: 11px; color: #345; } + #statusbar { height: 24px; background: #d5dce3; border-top: 1px solid #a9b4bf; display: flex; align-items: center; padding: 0 10px; font-size: 11px; color: #345; flex-shrink: 0; } #statusbar .dot { width: 8px; height: 8px; border-radius: 50%; background: #23a54a; margin-right: 6px; } @@ -66,101 +69,133 @@
글로벌 매입업무포털 (Enduro/X · ECPG/PostgreSQL · XA) - 사용자: 매입운영1팀 | 영업일 | 화면번호 AC0101 + 사용자: 매입운영1팀 | 영업일 | 화면 - | 전체화면 -
- +
-
매입 접수
+
-
TP 모니터 연결됨 — 게이트웨이 /api/call
+