Files
hjjeong 50669a66ee 프로젝트관리>제품구분_WBS관리 메뉴 신설 — wace WBS 템플릿 1:1 이식
· 메인 그리드 5컬럼(제품구분/제목/WBS/등록자/등록일) + 통합 팝업(트리 CRUD + 엑셀 임포트 + 템플릿 다운로드)
· 운영 매핑: pms_wbs_template(헤더) + pms_wbs_task_standard(트리) — 활성 갈래 확정 (_info/_standard2 갈래는 2021년 멈춘 레거시)
· wace mergeExcelUploadWBS 1:1: 신규=헤더+트리 INSERT, 수정=트리 일괄 DELETE→INSERT (헤더 변경 없음)
· objid 채번 gen_random_uuid()::text, 엑셀 파싱 xlsx(SheetJS), 정적 템플릿 frontend/public/templates/
· DataGrid 컬럼 단위 onClick 추가 (WBS 폴더 셀 클릭용)
· DDL: 8개 테이블 162컬럼 (docs/migration/project/ddl-extracted/200_pms_wbs.sql) / GAP: docs/migration/project/02-wbs-template.md
· 프로젝트 자동 복사/진행관리 연계는 wace도 미완성 — P2 범위 외

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 13:43:51 +09:00

114 lines
3.1 KiB
TypeScript

import { apiClient } from "./client";
// ─── 타입 (wace project.xml wbsTemplateMngGridList 1:1) ─────
export interface TemplateRow {
objid: string;
product_objid: string | null;
product_name: string | null; // CODE_NAME(PRODUCT_OBJID)
title: string | null;
writer: string | null;
writer_title: string | null; // DEPT_NAME || USER_NAME
reg_date: string | null;
reg_date_title: string | null; // YYYY-MM-DD
wbs_task_cnt: number | string | null;
customer_product: string | null;
}
export interface TemplateMaster {
objid: string;
product_objid: string;
product_objid_name: string;
title: string;
writer: string;
reg_date: string;
customer_product: string;
}
export interface TemplateTask {
objid: string;
parent_objid: string;
task_name: string;
task_seq: string;
task_level: string;
user_id: string;
user_id_title: string;
writer: string;
reg_date: string;
unit_no: string;
upper_task_objid: string;
}
export interface TemplateDetail {
master: TemplateMaster;
tasks: TemplateTask[];
}
// 저장 payload — wace mergeExcelUploadWBS의 폼 hidden 직렬화에 대응
export interface WbsTaskInput {
WBS_TASK_OBJID: string;
TASK_NAME: string;
UNIT_NO: string;
UPPER_TASK_OBJID: string;
TASK_LEVEL: string;
}
export interface SaveTemplatePayload {
templateObjId?: string; // 있으면 수정, 없으면 신규
product: string;
title: string;
customer_product?: string;
tasks: WbsTaskInput[]; // TOTAL 행 포함 (TASK_LEVEL=0)
}
// 엑셀 파싱 결과
export interface ParsedExcelRow {
WBS_OBJID: string;
UNIT_NO: string;
TASK_NAME: string;
}
// ─── API ────────────────────────────────────────────────
export const wbsTemplateApi = {
async list(product?: string): Promise<TemplateRow[]> {
const res = await apiClient.get("/project/wbs-template", {
params: product ? { product } : {},
});
return (res.data?.data ?? []) as TemplateRow[];
},
async detail(objid: string): Promise<TemplateDetail | null> {
const res = await apiClient.get(`/project/wbs-template/${objid}`);
return res.data?.data ?? null;
},
async checkDuplicate(product: string, title: string): Promise<boolean> {
const res = await apiClient.get("/project/wbs-template/check-duplicate", {
params: { product, title },
});
return Boolean(res.data?.data?.duplicate);
},
async save(payload: SaveTemplatePayload) {
const res = await apiClient.post("/project/wbs-template", payload);
return res.data;
},
async remove(objids: string[]) {
const res = await apiClient.delete("/project/wbs-template", {
data: { objids },
});
return res.data;
},
async parseExcel(file: File): Promise<ParsedExcelRow[]> {
const form = new FormData();
form.append("file", file);
const res = await apiClient.post("/project/wbs-template/parse-excel", form, {
headers: { "Content-Type": "multipart/form-data" },
});
return (res.data?.data ?? []) as ParsedExcelRow[];
},
};