Files
wace_rps/frontend/lib/api/ecrMng.ts
T
chpark 4007042311 ECR · 고객 CS · 결재 시스템 + Amaranth 전자결재 RestAPI 연계 + wace_plm 데이터 import
[ECR(Engineering Change Request) 관리]
- ecr_mng / product_mgmt / part_mng 테이블 + seq_ecr_no 시퀀스
- 설변요청 코드(0000090) 자식 코드 시드 (설계오류/품질개선/원가절감/고객요청/법규대응/부품단종)
- API: 목록/상세/등록·수정(merge)/조치완료/삭제 + 옵션(작성자/제품/부품/공통코드)
- 화면: 필터바, 그리드, 등록·수정 모달, 상세 모달, 조치완료 모달

[고객 CS 관리]
- customer_cs_mng 테이블 (기존 customer_mng 거래처 마스터와 충돌 회피)
- 공통코드 5종 카테고리(0000200~0000204) 자동 시드: 관리유형/제품구분/담당자/조치유형/CS상태
- API: 목록/상세/등록·수정/삭제/대시보드(요약·상태별·관리유형별·제품구분별)
- 화면: 요약 카드 4종, 10종 필터바, 14컬럼 그리드, 등록·수정·상세 모달

[결재(APPROVAL) 시스템 — wace_plm ApprovalService 포팅]
- approval / route / inboxtask / approval_target / approval_kind / amaranth_approval 6개 테이블
- 라이프사이클: 상신(startApproval) → 결재함(listInbox) → 승인/반려(approveTask/rejectTask)
  → 다음 결재자 ready 자동 전달, 마지막이면 route+approval+target 일괄 complete
- target_type 별 도메인 status 동기화 훅 (ECR_MNG/CUSTOMER_MNG)
- API: /api/wace-approval/{inbox,start,inbox/:id/approve|reject,by-target,:id,:id/amaranth-link}

[Amaranth(Wehago) 전자결재 RestAPI 연계]
- 외부 커넥션 'Amaranth - 결재' 자동 시드 (auth_config: callerName/accessToken/hashKey/groupSeq/aesKey)
- amaranthApprovalClient: 자바 AmaranthApprovalApiClient 1:1 포팅
  HMAC-SHA256 wehago-sign / AES-128-CBC empSeq 암호화 / HTTPS / JSON 파싱
- 6개 endpoint: 인증토큰/결재함/문서목록/문서상세/SSO URL/문서상신
- 하드코딩 0건 — DB 외부 커넥션의 인증 정보를 매 호출 시 로드
- 통신 검증 완료 (dummy empSeq 로 응답 정상 수신)
- 프록시 라우트 /api/amaranth-approval/{box,docs,docs/:id,sso,submit,auth-token}

[wace_plm 데이터 import]
- WacePlmDataImportService: source PG 클라이언트 → 우리 DB ON CONFLICT DO NOTHING idempotent
- 환경변수 WACE_PLM_DB_* 만 읽음 (운영 비번 코드 0건, 미설정 시 명시적 에러)
- /api/wace-import/{all,ecr,cs,masters,approval} (SUPER_ADMIN 전용)

[Bugfix]
- 배치 편집 conditional 매핑 silent drop 방지 — 평가 필드/규칙 누락 시
  어느 컬럼이 어떤 이유로 빠졌는지 toast 로 명시 + 저장 차단
- 시드 topup 강화 — extra_auth_config(aesKey 등) 누락된 기존 레코드 자동 보강

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:01:56 +09:00

94 lines
2.8 KiB
TypeScript

/**
* ECR(Engineering Change Request) 관리 API 클라이언트
* - 백엔드: backend-node/src/routes/ecrMngRoutes.ts
*/
import { apiClient } from "./client";
export interface EcrItem {
objid: string;
ecr_no: string;
product_name?: string;
product_objid?: string;
upg_no?: string;
part_no?: string;
part_name?: string;
part_objid?: string;
request_cd?: string;
request_name?: string;
title: string;
writer?: string;
writer_name?: string;
status_cd?: string;
status_name?: string;
check_user_id?: string;
check_name?: string;
before_contents?: string;
after_contents?: string;
reg_date?: string;
check_date?: string;
}
export interface EcrListResponse {
success: boolean;
list: EcrItem[];
pagination: { page: number; pageSize: number; total: number; totalPages: number };
}
export interface EcrListParams {
year?: string;
productCode?: string;
requestCode?: string;
writer?: string;
statusCode?: string;
page?: number;
pageSize?: number;
}
export const ecrMngApi = {
list: async (params: EcrListParams = {}): Promise<EcrListResponse> => {
const { data } = await apiClient.get("/ecr", { params });
return data;
},
detail: async (objId: string | number): Promise<EcrItem> => {
const { data } = await apiClient.get(`/ecr/${objId}`);
return data.data;
},
/** 등록/수정 (objId 가 있으면 update) */
merge: async (payload: {
objId?: string | number;
title: string;
product_objid?: string | number | null;
part_objid?: string | number | null;
request_codeArr?: string;
before_contents?: string;
after_contents?: string;
}): Promise<{ objid: string; ecr_no: string; status_cd: string }> => {
const { data } = await apiClient.post("/ecr", payload);
return data.data;
},
/** 조치완료 — status → 0000102 */
complete: async (objId: string | number, after_contents: string) => {
const { data } = await apiClient.post(`/ecr/${objId}/complete`, { after_contents });
return data;
},
remove: async (objIds: string[]) => {
const { data } = await apiClient.delete("/ecr", { data: { objIds } });
return data;
},
// 옵션 — 드롭다운/체크박스용
writerOptions: async (): Promise<Array<{ value: string; label: string }>> =>
(await apiClient.get("/ecr/options/writers")).data.data,
productOptions: async (): Promise<Array<{ value: string; label: string }>> =>
(await apiClient.get("/ecr/options/products")).data.data,
partOptions: async (): Promise<Array<{ value: string; label: string }>> =>
(await apiClient.get("/ecr/options/parts")).data.data,
/** parentCodeId='0000090' (요청코드) / '0000099' (상태) */
commCodeOptions: async (parentCodeId: string): Promise<Array<{ value: string; label: string }>> =>
(await apiClient.get(`/ecr/options/codes/${parentCodeId}`)).data.data,
};