From 68b68694e227cb27e7d8fa165374f40911847872 Mon Sep 17 00:00:00 2001 From: chpark Date: Wed, 20 May 2026 10:56:46 +0900 Subject: [PATCH] =?UTF-8?q?docs(manual):=20=EC=8B=A4=20=EC=BA=A1=EC=B2=98?= =?UTF-8?q?=2010=EC=9E=A5=20=EC=9E=84=EB=B2=A0=EB=94=A9=20+=20=EC=9E=90?= =?UTF-8?q?=EC=9E=AC=EA=B4=80=EB=A6=AC=C2=B7=EA=B5=AC=EB=A7=A4=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EC=8B=A0=EA=B7=9C=20=EA=B8=B0=EB=8A=A5=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 캡처 이미지 (Playwright 자동 캡처, docs/manual/screenshots/): - 01 로그인 → 02 메인 진입 - 03 견적관리 그리드 → 04 행 선택 + 결재상신 활성화 - 05 외부 커넥션 관리 (DB 연결 탭) - 08 화면 관리 목록 → 09 화면 상세 (디자이너 패널) - 10 사용자 대시보드 - 11 반제품검사 → 12 공정검사 + _capture.mjs / _capture_retry.mjs (재실행 스크립트, 1600x900 viewport) 매뉴얼 본문 업데이트: - §1 시스템 개요: 로그인 절차 + 그림 1·2 추가 - §3.1 영업·수주: 견적관리/행 선택 그림 3·4 - §3.3 구매·입고: 발주서 양식(일반/외주/영문) + 메일·PDF + 직인, 입고관리 3뷰 + 매입마감 신규 항목 보강 - §3.4 자재관리 신규 섹션 (자재리스트 + 불출의뢰서, StockRegister/MaterialMove/InventoryHistory/IssueDispatch 다이얼로그) - §4.1 외부 커넥션 그림 5, §5 대시보드 그림 6, §6 화면관리 그림 7·8, §6.3·6.4 품질관리 그림 9·10 - §2 카드 자재관리(NEW)·구매관리(메일·PDF·3양식) 보강 - 좌측 목차에 자재관리 항목 추가, 3.5→3.5 생산 / 3.6 품질 / 3.7 매출·CS 재번호 figure.shot CSS 추가 (1100px 폭, 부드러운 그림자). --- docs/manual/RPS_시스템_사용자_매뉴얼.html | 139 +++++++++++++++++-- docs/manual/screenshots/_capture.mjs | 152 +++++++++++++++++++++ docs/manual/screenshots/_capture_retry.mjs | 58 ++++++++ docs/manual/screenshots/_index.json | 42 ++++++ 4 files changed, 380 insertions(+), 11 deletions(-) create mode 100644 docs/manual/screenshots/_capture.mjs create mode 100644 docs/manual/screenshots/_capture_retry.mjs create mode 100644 docs/manual/screenshots/_index.json diff --git a/docs/manual/RPS_시스템_사용자_매뉴얼.html b/docs/manual/RPS_시스템_사용자_매뉴얼.html index 6b5994d6..5fe1ff7f 100644 --- a/docs/manual/RPS_시스템_사용자_매뉴얼.html +++ b/docs/manual/RPS_시스템_사용자_매뉴얼.html @@ -94,6 +94,10 @@ details { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 12px 16px; margin: 8px 0; } details summary { cursor: pointer; font-weight: 500; } details[open] summary { margin-bottom: 10px; } + figure.shot { margin: 16px 0; padding: 0; } + figure.shot img { width: 100%; max-width: 1100px; height: auto; display: block; border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08); } + figure.shot figcaption { margin-top: 8px; font-size: 13px; color: var(--muted); text-align: center; } + figure.shot figcaption strong { color: var(--text); } @media print { .layout { grid-template-columns: 1fr; } nav.toc { display: none; } @@ -115,6 +119,7 @@
  • 영업·수주
  • 개발·설계
  • 구매·입고
  • +
  • 자재관리
  • 생산
  • 품질
  • 매출·CS
  • @@ -180,6 +185,23 @@ 인증JWT + Refresh Token로그인 세션, 401 자동 갱신 +

    로그인

    +

    브라우저로 접속하면 가장 먼저 로그인 화면이 표시됩니다.

    +
    + 로그인 화면 +
    그림 1. 로그인 화면 — 사용자 ID 와 비밀번호 입력.
    +
    +
      +
    1. 사용자 ID 와 비밀번호를 입력하고 [로그인] 클릭.
    2. +
    3. 인증 성공 시 사용자에게 할당된 첫 메뉴(예: 영업관리 > 견적관리)로 자동 이동합니다.
    4. +
    5. 잘못된 자격증명이면 "패스워드가 일치하지 않습니다." 메시지가 표시됩니다.
    6. +
    + +
    + 로그인 직후 메인 화면 +
    그림 2. 로그인 직후 메인 화면 — 좌측 모듈 메뉴 + 자동 진입된 첫 화면.
    +
    + @@ -215,17 +237,18 @@

    🛒 구매관리

    -

    📦 자재관리

    +

    📦 자재관리 NEW

    @@ -318,6 +341,17 @@

    +
    + 견적관리 그리드 +
    그림 3. 견적관리 그리드 — 12 컬럼 (영업번호 / 주문유형 / 접수일 / 고객사 / 품명 / 견적수량 / 유무상 / 공급가액 등). + 상단 액션: [삭제] [+ 견적요청등록] [✎ 견적작성] [✈ 결재상신] [📧 메일발송] [초기화] [검색].
    +
    + +
    + 견적 행 선택 시 상태 +
    그림 4. 견적 행을 체크하면 [✈ 결재상신] 버튼이 활성화됩니다. 행 더블클릭 시 수정 모달이 열립니다.
    +
    +

    3.2 개발·설계

    @@ -354,8 +388,67 @@
    - -

    3.4 생산

    +

    발주서관리 — 양식 선택 / 메일 발송 / PDF (신규)

    +
    +

    발주서관리에서 행을 선택하면 다음 액션이 가능합니다:

    + +
    + +

    입고관리 — 3가지 뷰 + 입고등록 / 매입마감 (신규)

    +
    + +
    + + +

    3.4 자재관리 (신규)

    +
    +

    입고 후 창고로 들어온 자재를 관리합니다. 두 메뉴 모두 풀-CRUD + 인라인 액션을 지원합니다.

    + + + + + + + + + + + + +
    메뉴경로핵심 다이얼로그
    자재리스트/material/list + 재고등록 StockRegisterDialog · + 자재이동 MaterialMoveDialog · + 재고이력 InventoryHistoryDialog +
    불출의뢰서/material/issue-request + 의뢰서 작성 IssueRequestCreateDialog · + 불출 처리 IssueDispatchDialog +
    +

    + ✓ 흐름 + ① 입고 확정 → 자재리스트 자동 추가 + ② 생산팀 [불출의뢰서] 작성 → 부서/창고/품목/수량 지정 + ③ 자재팀 [불출 처리] → 실제 출고 + 재고 차감 + 이력 기록 +

    +
    + + +

    3.5 생산

    M-BOM 으로 생산계획을 수립하고 작업지시번호 단위로 실적을 입력합니다. @@ -368,8 +461,8 @@

    - -

    3.5 품질

    + +

    3.6 품질

    품질관리는 4단계로 흐릅니다:

    @@ -384,8 +477,8 @@

    불량 발생 → 책임부서로 통보 → 수정완료 시 재생수량 가산 → 최종양품수량 자동 산정. 자세한 내용은 6. 품질관리 메뉴 가이드.

    - -

    3.6 매출·CS

    + +

    3.7 매출·CS

    출하 완료 → 매출 인식 → Amaranth 로 세금계산서 발행. 고객 클레임은 CS 메뉴로 접수되어 분석/조치 후 종결됩니다.

    @@ -415,6 +508,10 @@

    위치: 관리자 > 자동화 관리 > 외부 커넥션 관리

    외부 시스템(ERP / 마스터 / 공공 API) 과의 모든 연결을 한 곳에서 관리합니다. 두 종류의 탭이 있습니다:

    +
    + 외부 커넥션 관리 - 데이터베이스 연결 탭 +
    그림 5. 외부 커넥션 관리 — [데이터베이스 연결] / [REST API 연결] 탭 전환. 각 행의 [테스트] 버튼으로 즉시 검증.
    +
    ┌────────────────────────────────────────────────────────────────────────────┐
     │  외부 커넥션 관리   외부 데이터베이스 및 REST API 연결 정보를 관리합니다.   │
     ├────────────────────────────────────────────────────────────────────────────┤
    @@ -651,6 +748,10 @@ const url = conn.baseUrl + "/apiproxy/api99u02A01";
  • To-Do — 결재 대기, 마감 임박 견적, 미입고 발주
  • +
    + 사용자 대시보드 +
    그림 6. 사용자 대시보드 — 매출/수주 / 리스크 알림 / To-Do 위젯 통합.
    +

    5.2 모니터링 보드

    @@ -697,6 +798,14 @@ const url = conn.baseUrl + "/apiproxy/api99u02A01";

    6.1 화면 디자이너 개요

    +
    + 화면 관리 목록 +
    그림 7. 화면 관리 — 좌측 그룹 트리 + 우측 화면 카드 목록. 각 화면 카드의 회색 영역을 누르면 상세가 열립니다.
    +
    +
    + 화면 상세 — 디자이너 패널 +
    그림 8. 화면 상세 — 메인 테이블 / 버튼 / 데이터 흐름 / 우측 미리보기가 한 화면에 통합. 우하단 [화면 디자이너에서 편집] 으로 풀스크린 편집 진입.
    +

    위치: 관리자 > 화면 관리 > 화면관리

    ┌─────────────────────────────────────────────────────────────────────────┐
    @@ -867,6 +976,10 @@ const url = conn.baseUrl + "/apiproxy/api99u02A01";

    6.3 공정검사 관리

    +
    + 공정검사 관리 +
    그림 9. 공정검사 관리 — 검사일/검사자(자동산정)/프로젝트번호/품번/품명/검사수량 합계 등 9컬럼.
    +

    경로: /COMPANY_16/quality/process-inspection

    작업 중 SPC 검사. 마스터 1건당 디테일 N건(검사항목)을 SUM 으로 집계하여 한 줄로 표시.

    @@ -880,6 +993,10 @@ const url = conn.baseUrl + "/apiproxy/api99u02A01";

    6.4 반제품검사 관리

    +
    + 반제품검사 관리 +
    그림 10. 반제품검사 관리 — 14컬럼. 입고/양품/불량/재생/최종양품 SUM 자동 산정 + 불량률(%) 계산.
    +

    경로: /COMPANY_16/quality/semi-product-inspection

    반제품 입고에 대한 양품/불량 판정. 단일 테이블(pms_quality_semi_product_inspection)에 양품 마스터(DATA_TYPE='GOOD')와 불량 행('DEFECT')을 동일 INSPECTION_GROUP_ID 로 묶어 저장합니다.

    diff --git a/docs/manual/screenshots/_capture.mjs b/docs/manual/screenshots/_capture.mjs new file mode 100644 index 00000000..7e81a5e3 --- /dev/null +++ b/docs/manual/screenshots/_capture.mjs @@ -0,0 +1,152 @@ +/** + * RPS PLM 시스템 메뉴얼용 화면 캡처 스크립트. + * + * 사용: + * node docs/manual/screenshots/_capture.mjs + * + * 전제: rps-front (localhost:9781) + rps_backend (localhost:8090) 실행 중. + * Playwright 는 /Users/chpark/invyone/frontend/node_modules/playwright 를 재사용. + */ +import { chromium } from "/Users/chpark/invyone/frontend/node_modules/playwright/index.mjs"; +import { writeFileSync } from "fs"; +import path from "path"; + +const FRONT = "http://localhost:9781"; +const OUT = "/Users/chpark/vexplor_rps/docs/manual/screenshots"; +const SHOTS = []; + +const wait = (ms) => new Promise((r) => setTimeout(r, ms)); + +async function shot(page, name, description) { + const file = path.join(OUT, `${name}.png`); + await page.screenshot({ path: file, fullPage: false }); + SHOTS.push({ name, description, file }); + console.log(` 📸 ${name} — ${description}`); +} + +(async () => { + const browser = await chromium.launch({ headless: true }); + const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 }, locale: "ko-KR" }); + const page = await ctx.newPage(); + + try { + // 1. 로그인 화면 + console.log("→ 로그인 화면"); + await page.goto(`${FRONT}/login`, { waitUntil: "domcontentloaded", timeout: 60000 }); + await page.waitForLoadState("networkidle", { timeout: 30000 }); + await wait(800); + await shot(page, "01_login", "로그인 화면 (사용자 ID / 비밀번호 입력)"); + + // 2. 로그인 진행 + console.log("→ 로그인"); + await page.getByPlaceholder("사용자 ID").fill("wace"); + await page.getByPlaceholder("비밀번호").fill("qlalfqjsgh11"); + await Promise.all([ + page.waitForURL((u) => !u.toString().includes("/login"), { timeout: 180000 }), + page.getByRole("button", { name: "로그인" }).click(), + ]); + await page.waitForLoadState("networkidle", { timeout: 120000 }).catch(() => {}); + await wait(6000); + await shot(page, "02_main", "로그인 직후 메인 화면 — 좌측 모듈 메뉴 + 견적관리 자동 진입"); + + // 3. 견적관리 (이미 로그인 후 첫 화면이 견적관리) + console.log("→ 견적관리 그리드"); + await page.goto(`${FRONT}/main`, { waitUntil: "networkidle", timeout: 60000 }); + await wait(6000); + // 영업관리 → 견적관리 클릭 + try { + await page.getByText("영업관리", { exact: true }).first().click({ timeout: 5000 }); + await wait(500); + await page.getByText("견적관리", { exact: true }).first().click({ timeout: 5000 }); + await wait(3000); + } catch { /* already there */ } + await shot(page, "03_estimate_list", "견적관리 — 12컬럼 그리드 + 검색 필터 + 결재상신 버튼"); + + // 4. 견적 행 선택 → 결재상신 버튼 활성화 상태 캡처 + console.log("→ 견적 행 선택"); + try { + const firstRow = page.locator("table tbody tr").first(); + if (await firstRow.isVisible({ timeout: 5000 })) { + await firstRow.click({ timeout: 3000 }); + await wait(800); + await shot(page, "04_estimate_selected", "견적 행 선택 시 상단 액션 버튼 활성화 (결재상신 강조)"); + } + } catch (e) { console.warn(" ⚠ skip 행선택:", e.message); } + + // 5. 외부 커넥션 관리 (REST API 탭) + console.log("→ 외부 커넥션 관리"); + await page.goto(`${FRONT}/admin/automaticMng/exconList`, { waitUntil: "networkidle", timeout: 60000 }); + await wait(6000); + await shot(page, "05_excon_db_tab", "외부 커넥션 관리 — 데이터베이스 연결 탭 (기본)"); + + // REST API 탭 클릭 + try { + await page.getByText("REST API 연결", { exact: true }).click({ timeout: 5000 }); + await wait(3000); + await shot(page, "06_excon_rest_tab", "외부 커넥션 관리 — REST API 연결 탭 (Amaranth 7종)"); + } catch (e) { console.warn(" ⚠ skip REST 탭:", e.message); } + + // 6. + 새 연결 버튼 클릭 → 등록 모달 + console.log("→ REST API 등록 모달"); + try { + const newBtn = page.getByRole("button", { name: /새 연결|새 REST|새로 추가|\+ 새/ }).first(); + if (await newBtn.isVisible({ timeout: 5000 })) { + await newBtn.click({ timeout: 3000 }); + await wait(2500); + await shot(page, "07_excon_rest_create", "REST API 신규 등록 모달 — 연결명/URL/인증 정보 입력"); + // ESC 닫기 + await page.keyboard.press("Escape"); + await wait(500); + } + } catch (e) { console.warn(" ⚠ skip 등록모달:", e.message); } + + // 7. 화면 관리 (Screen Designer 진입점) + console.log("→ 화면 관리"); + await page.goto(`${FRONT}/admin/screenMng/screenMngList`, { waitUntil: "networkidle", timeout: 60000 }); + await wait(6000); + await shot(page, "08_screen_mng_list", "화면 관리 — 등록된 화면 목록 (그룹 트리 + 카드)"); + + // 8. 화면 한개 클릭 → 설정 패널 + try { + const firstCard = page.locator(".cursor-pointer, [role=button]").filter({ hasText: /화면|sales|order|관리/ }).first(); + if (await firstCard.isVisible({ timeout: 4000 })) { + await firstCard.click({ timeout: 3000 }); + await wait(2500); + await shot(page, "09_screen_detail", "화면 상세 — 메인 테이블 + 버튼 + 데이터 흐름 + 미리보기"); + } + } catch (e) { console.warn(" ⚠ skip 화면상세:", e.message); } + + // 9. 대시보드 + console.log("→ 대시보드"); + await page.goto(`${FRONT}/dashboard`, { waitUntil: "domcontentloaded", timeout: 30000 }); + await wait(3000); + await shot(page, "10_dashboard", "사용자 대시보드 — 매출/수주 위젯 + 모니터링"); + + // 10. 품질관리 - 반제품검사 (데이터 보임) + console.log("→ 반제품검사"); + await page.goto(`${FRONT}/COMPANY_16/quality/semi-product-inspection`, { waitUntil: "domcontentloaded", timeout: 30000 }); + await wait(3500); + await shot(page, "11_quality_semi", "품질관리 — 반제품검사 (waceplm 운영 데이터 82행)"); + + // 11. 공정검사 + console.log("→ 공정검사"); + await page.goto(`${FRONT}/COMPANY_16/quality/process-inspection`, { waitUntil: "domcontentloaded", timeout: 30000 }); + await wait(3500); + await shot(page, "12_quality_process", "품질관리 — 공정검사 (3행, 검사자 자동 산정)"); + + console.log("\n✅ 캡처 완료"); + console.log(`총 ${SHOTS.length} 장`); + SHOTS.forEach((s) => console.log(` - ${s.name}.png : ${s.description}`)); + + // 인덱스 JSON 출력 + writeFileSync( + path.join(OUT, "_index.json"), + JSON.stringify(SHOTS.map((s) => ({ name: s.name, description: s.description })), null, 2), + ); + } catch (err) { + console.error("❌ 캡처 실패:", err.message); + process.exit(1); + } finally { + await browser.close(); + } +})(); diff --git a/docs/manual/screenshots/_capture_retry.mjs b/docs/manual/screenshots/_capture_retry.mjs new file mode 100644 index 00000000..c55b43df --- /dev/null +++ b/docs/manual/screenshots/_capture_retry.mjs @@ -0,0 +1,58 @@ +/** + * 부족한 캡처 재시도 — 02_main (로딩만 캡처됨), 06_excon_rest_tab (탭 클릭 실패). + */ +import { chromium } from "/Users/chpark/invyone/frontend/node_modules/playwright/index.mjs"; +import path from "path"; + +const FRONT = "http://localhost:9781"; +const OUT = "/Users/chpark/vexplor_rps/docs/manual/screenshots"; +const wait = (ms) => new Promise((r) => setTimeout(r, ms)); + +(async () => { + const browser = await chromium.launch({ headless: true }); + const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 }, locale: "ko-KR" }); + const page = await ctx.newPage(); + + try { + // 로그인 + await page.goto(`${FRONT}/login`, { waitUntil: "domcontentloaded", timeout: 60000 }); + await page.waitForLoadState("networkidle", { timeout: 30000 }).catch(() => {}); + await wait(2000); + await page.getByPlaceholder("사용자 ID").fill("wace"); + await page.getByPlaceholder("비밀번호").fill("qlalfqjsgh11"); + await page.getByRole("button", { name: "로그인" }).click({ timeout: 120000 }); + await page.waitForURL((u) => !u.toString().includes("/login"), { timeout: 180000 }); + await page.waitForLoadState("networkidle", { timeout: 120000 }).catch(() => {}); + await wait(15000); // 메인 진입 후 견적관리 페이지까지 완전 렌더 대기 + console.log("→ 메인 화면 재캡처"); + await page.screenshot({ path: path.join(OUT, "02_main.png"), fullPage: false }); + + // REST API 탭 재시도 + console.log("→ REST API 탭"); + await page.goto(`${FRONT}/admin/automaticMng/exconList`, { waitUntil: "networkidle", timeout: 60000 }); + await wait(6000); + // 다양한 셀렉터 시도 + try { + await page.locator('[role="tab"]').filter({ hasText: "REST API" }).click({ timeout: 5000 }); + } catch { + await page.locator('button:has-text("REST API 연결")').click({ timeout: 5000 }); + } + await wait(4000); + await page.screenshot({ path: path.join(OUT, "06_excon_rest_tab.png"), fullPage: false }); + console.log(" ✓ 06_excon_rest_tab.png"); + + // REST API 신규 등록 모달 + console.log("→ + 새 연결 버튼"); + try { + await page.getByRole("button", { name: /^\+/ }).first().click({ timeout: 4000 }); + await wait(3000); + await page.screenshot({ path: path.join(OUT, "07_excon_rest_create.png"), fullPage: false }); + console.log(" ✓ 07_excon_rest_create.png"); + } catch (e) { console.warn(" ⚠ 모달 클릭 실패:", e.message); } + + } catch (e) { + console.error("FAIL:", e.message); + } finally { + await browser.close(); + } +})(); diff --git a/docs/manual/screenshots/_index.json b/docs/manual/screenshots/_index.json new file mode 100644 index 00000000..3bb20eb2 --- /dev/null +++ b/docs/manual/screenshots/_index.json @@ -0,0 +1,42 @@ +[ + { + "name": "01_login", + "description": "로그인 화면 (사용자 ID / 비밀번호 입력)" + }, + { + "name": "02_main", + "description": "로그인 직후 메인 화면 — 좌측 모듈 메뉴 + 견적관리 자동 진입" + }, + { + "name": "03_estimate_list", + "description": "견적관리 — 12컬럼 그리드 + 검색 필터 + 결재상신 버튼" + }, + { + "name": "04_estimate_selected", + "description": "견적 행 선택 시 상단 액션 버튼 활성화 (결재상신 강조)" + }, + { + "name": "05_excon_db_tab", + "description": "외부 커넥션 관리 — 데이터베이스 연결 탭 (기본)" + }, + { + "name": "08_screen_mng_list", + "description": "화면 관리 — 등록된 화면 목록 (그룹 트리 + 카드)" + }, + { + "name": "09_screen_detail", + "description": "화면 상세 — 메인 테이블 + 버튼 + 데이터 흐름 + 미리보기" + }, + { + "name": "10_dashboard", + "description": "사용자 대시보드 — 매출/수주 위젯 + 모니터링" + }, + { + "name": "11_quality_semi", + "description": "품질관리 — 반제품검사 (waceplm 운영 데이터 82행)" + }, + { + "name": "12_quality_process", + "description": "품질관리 — 공정검사 (3행, 검사자 자동 산정)" + } +] \ No newline at end of file