생산관리 4개 메뉴 보정 — 디렉토리/그리드 헤더/소요량 SQL

디렉토리 rename (menu_info 등록 URL 일치)
- prod-plan-result → plan-result
- prod-plan-result-equip → plan-result-equip
- semi-product-requirement → semi-product-req
- raw-material-requirement → raw-material-req
- menu_info objid 100033~100036 이 가리키는 URL 과 1:1 매칭 + gridId 동기화

DataGrid 헤더 잘림/한 글자 깨짐 수정
- 헤더 라벨 span: whitespace-nowrap + title (이전 break-words 가 한글 단어를 글자 단위로 wrap 시키던 문제 제거)
- 부모 컨테이너 overflow-hidden 도 제거 — 좁은 컬럼에서도 글자가 한 줄로 자연스럽게 표시
- plan-result / plan-result-equip 좁은 컬럼 너비 보정 (수주/추가생산/총생산/완조립/등록자/진척율)

반제품/원자재 소요량 numeric 캐스팅 에러 수정
- RPS DB mbom_detail.qty/required_qty 는 numeric(15,4) — wace_plm 의 varchar 패턴(NULLIF 후 ::INTEGER) 적용 시 invalid input syntax 발생
- COALESCE(MD.QTY, 1)::INTEGER / COALESCE(MD.REQUIRED_QTY, 0)::NUMERIC 으로 교체
This commit is contained in:
hjjeong
2026-05-14 18:13:26 +09:00
parent bd47ca80df
commit c83a73a111
6 changed files with 33 additions and 33 deletions
@@ -95,14 +95,14 @@ export async function getSemiRequirement(items: MbomRequirementInputItem[]): Pro
SELECT
MD.PART_NO,
MD.PART_NAME,
COALESCE(NULLIF(MD.QTY, '')::INTEGER, 1) AS ITEM_QTY,
COALESCE(MD.QTY, 1)::INTEGER AS ITEM_QTY,
P.PART_TYPE,
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = P.PART_TYPE LIMIT 1), '') AS CATEGORY_NAME,
COALESCE(P.UNIT, '') AS UNIT,
COALESCE(P.MATERIAL, '') AS MATERIAL,
COALESCE(P.SPEC, '') AS SPEC
FROM MBOM_DETAIL MD
INNER JOIN PART_MNG P ON P.OBJID::VARCHAR = MD.PART_OBJID
INNER JOIN PART_MNG P ON P.OBJID = MD.PART_OBJID
WHERE MD.MBOM_HEADER_OBJID = $1
AND MD.STATUS = 'ACTIVE'
AND (MD.PARENT_OBJID IS NOT NULL AND MD.PARENT_OBJID != '')
@@ -162,11 +162,11 @@ export async function getRawRequirement(items: MbomRequirementInputItem[]): Prom
SELECT
MD.PART_NO,
MD.PART_NAME,
COALESCE(NULLIF(MD.QTY, '')::INTEGER, 1) AS ITEM_QTY,
COALESCE(MD.QTY, 1)::INTEGER AS ITEM_QTY,
COALESCE((SELECT CODE_NAME FROM COMM_CODE WHERE CODE_ID = P.PART_TYPE LIMIT 1), '') AS CATEGORY_NAME,
COALESCE(P.UNIT, '') AS UNIT
FROM MBOM_DETAIL MD
INNER JOIN PART_MNG P ON P.OBJID::VARCHAR = MD.PART_OBJID
INNER JOIN PART_MNG P ON P.OBJID = MD.PART_OBJID
WHERE MD.MBOM_HEADER_OBJID = $1
AND MD.STATUS = 'ACTIVE'
AND (MD.PARENT_OBJID IS NOT NULL AND MD.PARENT_OBJID != '')
@@ -207,7 +207,7 @@ export async function getRawRequirement(items: MbomRequirementInputItem[]): Prom
SELECT
MD.RAW_MATERIAL_PART_NO AS PART_NO,
MD.RAW_MATERIAL AS PART_NAME,
COALESCE(NULLIF(MD.REQUIRED_QTY, '')::NUMERIC, 0) AS ITEM_QTY,
COALESCE(MD.REQUIRED_QTY, 0)::NUMERIC AS ITEM_QTY,
MD.RAW_MATERIAL,
MD.RAW_MATERIAL_SIZE
FROM MBOM_DETAIL MD
@@ -91,20 +91,20 @@ export default function ProdPlanResultEquipPage() {
);
const GRID_COLUMNS: DataGridColumn[] = useMemo(() => ([
{ key: "project_no", label: "프로젝트번호", width: "w-[130px]" },
{ key: "product_name", label: "제품구분", width: "w-[100px]", align: "center" },
{ key: "category_code_name", label: "주문유형", width: "w-[100px]", align: "center" },
{ key: "production_type_name", label: "생산유형", width: "w-[100px]", align: "center" },
{ key: "project_no", label: "프로젝트번호", width: "w-[140px]" },
{ key: "product_name", label: "제품구분", width: "w-[110px]", align: "center" },
{ key: "category_code_name", label: "주문유형", width: "w-[110px]", align: "center" },
{ key: "production_type_name", label: "생산유형", width: "w-[110px]", align: "center" },
{ key: "customer_name", label: "고객사", minWidth: "min-w-[160px]" },
{ key: "req_del_date", label: "요청납기", width: "w-[110px]", align: "center" },
{ key: "req_del_date", label: "요청납기", width: "w-[115px]", align: "center" },
{ key: "customer_request", label: "고객사요청사항", minWidth: "min-w-[200px]" },
{ key: "part_no", label: "품번", width: "w-[140px]" },
{ key: "part_name", label: "품명", minWidth: "min-w-[180px]" },
{ key: "serial_no", label: "S/N", width: "w-[110px]", align: "center" },
{ key: "prod_wbs_cnt", label: "생산WBS", width: "w-[90px]", align: "right", formatNumber: true },
{ key: "prod_progress_rate", label: "생산진척율(%)", width: "w-[120px]", align: "right" },
{ key: "delv_wbs_cnt", label: "납품WBS", width: "w-[90px]", align: "right", formatNumber: true },
{ key: "delv_progress_rate", label: "납품진척율(%)", width: "w-[120px]", align: "right" },
{ key: "prod_wbs_cnt", label: "생산WBS", width: "w-[110px]", align: "right", formatNumber: true },
{ key: "prod_progress_rate", label: "생산진척율(%)", width: "w-[140px]", align: "right" },
{ key: "delv_wbs_cnt", label: "납품WBS", width: "w-[110px]", align: "right", formatNumber: true },
{ key: "delv_progress_rate", label: "납품진척율(%)", width: "w-[140px]", align: "right" },
]), []);
const summary = useMemo(() => {
@@ -173,7 +173,7 @@ export default function ProdPlanResultEquipPage() {
showRowNumber
showCheckbox
emptyMessage="조건에 맞는 데이터가 없습니다."
gridId="production-prod-plan-result-equip"
gridId="production-plan-result-equip"
pageSizeOptions={[25, 50, 100, 200, 500]}
paginationStyle="range"
serverPaging
@@ -108,24 +108,24 @@ export default function ProdPlanResultPage() {
}, []);
const GRID_COLUMNS: DataGridColumn[] = useMemo(() => ([
{ key: "project_no", label: "프로젝트번호", width: "w-[130px]" },
{ key: "product_name", label: "제품구분", width: "w-[100px]", align: "center" },
{ key: "category_code_name", label: "주문유형", width: "w-[100px]", align: "center" },
{ key: "production_type_name",label: "생산유형", width: "w-[100px]", align: "center" },
{ key: "project_no", label: "프로젝트번호", width: "w-[140px]" },
{ key: "product_name", label: "제품구분", width: "w-[110px]", align: "center" },
{ key: "category_code_name", label: "주문유형", width: "w-[110px]", align: "center" },
{ key: "production_type_name",label: "생산유형", width: "w-[110px]", align: "center" },
{ key: "customer_name", label: "고객사", minWidth: "min-w-[160px]" },
{ key: "req_del_date", label: "요청납기", width: "w-[110px]", align: "center" },
{ key: "customer_request", label: "고객사요청사항", minWidth: "min-w-[180px]" },
{ key: "req_del_date", label: "요청납기", width: "w-[115px]", align: "center" },
{ key: "customer_request", label: "고객사요청사항", minWidth: "min-w-[190px]" },
{ key: "part_no", label: "품번", width: "w-[140px]" },
{ key: "part_name", label: "품명", minWidth: "min-w-[180px]" },
{ key: "serial_no", label: "S/N", width: "w-[110px]", align: "center", onClick: openSerial },
{ key: "quantity", label: "수주수량", width: "w-[90px]", align: "right", formatNumber: true },
{ key: "extra_prod_qty", label: "추가생산수량", width: "w-[110px]", align: "right", formatNumber: true },
{ key: "total_prod_qty", label: "총생산수량", width: "w-[100px]", align: "right", formatNumber: true },
{ key: "assembly_qty", label: "완조립", width: "w-[80px]", align: "right", formatNumber: true },
{ key: "inspection_qty", label: "검사", width: "w-[80px]", align: "right", formatNumber: true },
{ key: "ship_wait_qty", label: "포장", width: "w-[80px]", align: "right", formatNumber: true },
{ key: "writer_name", label: "등록자", width: "w-[80px]", align: "center" },
{ key: "regdate_title", label: "등록일", width: "w-[100px]", align: "center" },
{ key: "quantity", label: "수주수량", width: "w-[110px]", align: "right", formatNumber: true },
{ key: "extra_prod_qty", label: "추가생산수량", width: "w-[130px]", align: "right", formatNumber: true },
{ key: "total_prod_qty", label: "총생산수량", width: "w-[120px]", align: "right", formatNumber: true },
{ key: "assembly_qty", label: "완조립", width: "w-[95px]", align: "right", formatNumber: true },
{ key: "inspection_qty", label: "검사", width: "w-[85px]", align: "right", formatNumber: true },
{ key: "ship_wait_qty", label: "포장", width: "w-[85px]", align: "right", formatNumber: true },
{ key: "writer_name", label: "등록자", width: "w-[95px]", align: "center" },
{ key: "regdate_title", label: "등록일", width: "w-[105px]", align: "center" },
]), [openSerial]);
const summary = useMemo(() => {
@@ -205,7 +205,7 @@ export default function ProdPlanResultPage() {
showRowNumber
showCheckbox
emptyMessage="조건에 맞는 데이터가 없습니다."
gridId="production-prod-plan-result"
gridId="production-plan-result"
pageSizeOptions={[25, 50, 100, 200, 500]}
paginationStyle="range"
serverPaging
@@ -184,7 +184,7 @@ export default function RawMaterialRequirementPage() {
loading={loading}
showRowNumber
emptyMessage="조회 결과가 없습니다."
gridId="production-raw-material-requirement"
gridId="production-raw-material-req"
pageSizeOptions={[25, 50, 100, 200, 500]}
paginationStyle="range"
showColumnSettings
@@ -185,7 +185,7 @@ export default function SemiProductRequirementPage() {
loading={loading}
showRowNumber
emptyMessage="조회 결과가 없습니다."
gridId="production-semi-product-requirement"
gridId="production-semi-product-req"
pageSizeOptions={[25, 50, 100, 200, 500]}
paginationStyle="range"
showColumnSettings
+1 -1
View File
@@ -188,7 +188,7 @@ function SortableHeaderCell({
if (col.sortable !== false) onSort(col.key);
}}
>
<span className="text-xs font-medium truncate">{col.label}</span>
<span className="text-xs font-medium whitespace-nowrap" title={col.label}>{col.label}</span>
{isSorted && (
<span className="text-primary text-xs shrink-0">{sortDir === "asc" ? "↑" : "↓"}</span>
)}