aacbb62ad8
- 신규 테이블 5종 (운영 11133 → RPS 11134 DDL 1:1):
inventory_mgmt / inventory_mgmt_in / inventory_mgmt_out /
inventory_mgmt_out_master / inventory_mgmt_history
- 백엔드 /api/inventory-mng — 리스트·재고등록·자재이동·삭제·이력 +
불출의뢰 생성·접수·자재불출(재고 차감)·삭제. 채번 Rfw-YYYY-seq.
- 프론트 /COMPANY_16/material/{list, issue-request} +
StockRegister / MaterialMove / IssueRequestCreate /
InventoryHistory / IssueDispatch 다이얼로그 5종.
- AdminPageRenderer 등록 + /material/ prefix.
102 lines
3.6 KiB
TypeScript
102 lines
3.6 KiB
TypeScript
"use client";
|
|
|
|
// 자재관리 > 자재리스트 — 입출고 이력 다이얼로그
|
|
// wace 1:1: inventoryRequestHistoryPopUp.jsp
|
|
// 입고/이동/출고 UNION 결과 노출
|
|
|
|
import React, { useEffect, useState } from "react";
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, DialogDescription } from "@/components/ui/dialog";
|
|
import { Button } from "@/components/ui/button";
|
|
import { X } from "lucide-react";
|
|
import { inventoryMngApi } from "@/lib/api/inventoryMng";
|
|
import { toast } from "sonner";
|
|
|
|
interface HistoryRow {
|
|
objid: string;
|
|
part_no: string;
|
|
part_name: string;
|
|
gubun: string;
|
|
qty: string;
|
|
location_name: string;
|
|
sub_location_name: string;
|
|
regdate: string;
|
|
writer_name: string;
|
|
}
|
|
|
|
interface Props {
|
|
open: boolean;
|
|
onClose: () => void;
|
|
parentObjid: string; // inventory_mgmt.objid
|
|
partLabel?: string;
|
|
}
|
|
|
|
export function InventoryHistoryDialog({ open, onClose, parentObjid, partLabel }: Props) {
|
|
const [rows, setRows] = useState<HistoryRow[]>([]);
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
useEffect(() => {
|
|
if (!open || !parentObjid) return;
|
|
setLoading(true);
|
|
(async () => {
|
|
try {
|
|
const data = await inventoryMngApi.history(parentObjid);
|
|
setRows(data as HistoryRow[]);
|
|
} catch (e: any) {
|
|
toast.error(e?.response?.data?.message ?? e?.message ?? "이력 조회 실패");
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
})();
|
|
}, [open, parentObjid]);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={(v) => !v && onClose()}>
|
|
<DialogContent className="max-w-4xl">
|
|
<DialogHeader>
|
|
<DialogTitle>입출고 이력{partLabel ? ` — ${partLabel}` : ""}</DialogTitle>
|
|
<DialogDescription>해당 자재의 입고/이동/출고 이력을 표시합니다.</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="overflow-x-auto text-xs">
|
|
<table className="w-full border">
|
|
<thead className="bg-muted/50">
|
|
<tr>
|
|
<th className="border px-2 py-1">구분</th>
|
|
<th className="border px-2 py-1 text-right">수량</th>
|
|
<th className="border px-2 py-1">Location</th>
|
|
<th className="border px-2 py-1">Sub</th>
|
|
<th className="border px-2 py-1">담당자</th>
|
|
<th className="border px-2 py-1">일자</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{loading && (
|
|
<tr><td colSpan={6} className="border px-2 py-3 text-center">조회 중...</td></tr>
|
|
)}
|
|
{!loading && rows.length === 0 && (
|
|
<tr><td colSpan={6} className="border px-2 py-3 text-center">이력이 없습니다.</td></tr>
|
|
)}
|
|
{rows.map((r, i) => (
|
|
<tr key={i}>
|
|
<td className="border px-2 py-1">{r.gubun}</td>
|
|
<td className="border px-2 py-1 text-right">{r.qty || "0"}</td>
|
|
<td className="border px-2 py-1">{r.location_name}</td>
|
|
<td className="border px-2 py-1">{r.sub_location_name}</td>
|
|
<td className="border px-2 py-1">{r.writer_name}</td>
|
|
<td className="border px-2 py-1">{r.regdate?.toString().slice(0, 19).replace("T", " ")}</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button size="sm" variant="ghost" onClick={onClose}>
|
|
<X className="h-3.5 w-3.5 mr-1" /> 닫기
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|