7c4817b045
· wace fn_openSaleRegPopup(PROJECT_NO, "detail") 의도 재해석 — read-only 상세 조회 모드 · 행 전체 클릭(onRowClick) → PROJECT_NO 컬럼 셀 클릭(cellClick)으로 좁힘 (wace 1:1) · 판매관리 페이지 라우팅 폐기 → ProjectInfoDialog 신설 (같은 탭, list row 직접 사용, 추가 API 호출 0) · 표시 항목: 프로젝트번호/영업번호/주문유형/제품구분/국내해외/고객사/유무상/품번/품명/S/N/수주수량/접수일/요청납기/발주일/프로젝트명/작성자 · 영업관리 변경 롤백 (SaleListFilter.project_no, useSearchParams 자동 선택, 초기화 핸들러) · 01-progress / 01-progress-verify 문서 갱신 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
74 lines
3.1 KiB
TypeScript
74 lines
3.1 KiB
TypeScript
"use client";
|
|
|
|
// 진행관리 PROJECT_NO 셀 클릭 시 표시되는 프로젝트 정보 다이얼로그 (read-only).
|
|
// wace `fn_openSaleRegPopup(PROJECT_NO, "detail")` 대응 — 새 창 대신 같은 탭 내 다이얼로그.
|
|
// list SQL 응답(ProgressRow)에 필요 데이터가 모두 포함돼 있어 별도 detail API 호출 불필요.
|
|
|
|
import React from "react";
|
|
import { Button } from "@/components/ui/button";
|
|
import {
|
|
Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle,
|
|
} from "@/components/ui/dialog";
|
|
import { ProgressRow } from "@/lib/api/projectMgmt";
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
row: ProgressRow | null;
|
|
}
|
|
|
|
const fmtQty = (v: unknown) => {
|
|
if (v == null || v === "") return "";
|
|
const n = Number(String(v).replace(/,/g, ""));
|
|
return isNaN(n) ? String(v) : n.toLocaleString();
|
|
};
|
|
|
|
export function ProjectInfoDialog({ open, onOpenChange, row }: Props) {
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="max-w-xl">
|
|
<DialogHeader>
|
|
<DialogTitle>프로젝트 정보</DialogTitle>
|
|
</DialogHeader>
|
|
|
|
{row ? (
|
|
<div className="grid grid-cols-[120px_1fr] gap-y-2 gap-x-3 text-sm py-2">
|
|
<Label>프로젝트번호</Label><Value>{row.project_no}</Value>
|
|
<Label>영업번호</Label><Value>{row.contract_no}</Value>
|
|
<Label>주문유형</Label><Value>{row.category_name}</Value>
|
|
<Label>제품구분</Label><Value>{row.product_name}</Value>
|
|
<Label>국내/해외</Label><Value>{row.area_name}</Value>
|
|
<Label>고객사</Label><Value>{row.customer_name}</Value>
|
|
<Label>유/무상</Label><Value>{row.free_of_charge}</Value>
|
|
<Label>품번</Label><Value>{row.product_item_code}</Value>
|
|
<Label>품명</Label><Value>{row.product_item_name}</Value>
|
|
<Label>S/N</Label><Value>{row.serial_no}</Value>
|
|
<Label>수주수량</Label><Value className="text-right">{fmtQty(row.contract_qty)}</Value>
|
|
<Label>접수일</Label><Value>{row.reg_date}</Value>
|
|
<Label>요청납기</Label><Value>{row.req_del_date}</Value>
|
|
<Label>발주일</Label><Value>{row.order_date}</Value>
|
|
<Label>프로젝트명</Label><Value>{row.project_name ?? ""}</Value>
|
|
<Label>작성자</Label><Value>{row.writer_name}</Value>
|
|
</div>
|
|
) : null}
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" onClick={() => onOpenChange(false)}>닫기</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|
|
|
|
function Label({ children }: { children: React.ReactNode }) {
|
|
return <div className="text-right text-xs text-muted-foreground self-center">{children}</div>;
|
|
}
|
|
function Value({ children, className }: { children: React.ReactNode; className?: string }) {
|
|
const empty = children == null || children === "";
|
|
return (
|
|
<div className={`min-h-7 px-2 py-1 rounded bg-muted/40 text-sm ${className ?? ""}`}>
|
|
{empty ? <span className="text-muted-foreground/60">-</span> : children}
|
|
</div>
|
|
);
|
|
}
|