구매관리 발주서 폼 저장/삭제 + general 양식 다이얼로그
- 백엔드: POST /api/purchase/order-form/save (마스터 55 + 파트 40 컬럼 UPSERT + 삭제파트 cascade, 트랜잭션, wace mergePurchaseOrderMaster/PartInfo 1:1) - 백엔드: DELETE /api/purchase/order-form/:objid (마스터+파트 cascade) - 프론트 lib/api: initOrderForm/getOrderForm/saveOrderForm/deleteOrderForm - 프론트 컴포넌트: PurchaseOrderGeneralFormDialog — wace purchaseOrderFormPopup_general.jsp 1:1 (좌 5필드/우 담당자 + 회사정보 2줄/그리드 10컬럼/총공급가액/보안문구) - /purchase/proposal "발주서생성" 버튼 활성화 → 품의서 자동 채움 다이얼로그 - /purchase/order 행 클릭/체크 → 수정/삭제 액션 + 다이얼로그 - Radix UI 접근성: DialogTitle/Description sr-only 처리 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -18,6 +18,10 @@ import { PageHeader } from "@/components/common/PageHeader";
|
||||
import { purchaseApi, PurchaseListFilter, OptionItem, getYearOptions } from "@/lib/api/purchase";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { exportToExcel } from "@/lib/utils/excelExport";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Pencil, Trash2 } from "lucide-react";
|
||||
import { PurchaseOrderGeneralFormDialog } from "@/components/purchase/PurchaseOrderGeneralFormDialog";
|
||||
import { useConfirmDialog } from "@/components/common/ConfirmDialog";
|
||||
|
||||
const MAIL_SEND_OPTS: SmartSelectOption[] = [
|
||||
{ code: "Y", label: "발송완료" },
|
||||
@@ -65,6 +69,11 @@ export default function PurchaseOrderWacePage() {
|
||||
const [productOpts, setProductOpts] = useState<OptionItem[]>([]);
|
||||
const [purchaseOpts, setPurchaseOpts] = useState<OptionItem[]>([]);
|
||||
|
||||
// 수정 다이얼로그
|
||||
const [editOpen, setEditOpen] = useState(false);
|
||||
const [editObjid, setEditObjid] = useState<string>("");
|
||||
const { confirm, ConfirmDialogComponent } = useConfirmDialog();
|
||||
|
||||
const yearOpts = useMemo(() => getYearOptions(), []);
|
||||
|
||||
const fetchList = useCallback(async (override?: Partial<PurchaseListFilter>) => {
|
||||
@@ -138,7 +147,40 @@ export default function PurchaseOrderWacePage() {
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col overflow-hidden p-2 gap-2">
|
||||
<PageHeader loading={loading} onSearch={handleSearch} onReset={handleReset} />
|
||||
<PageHeader loading={loading} onSearch={handleSearch} onReset={handleReset}
|
||||
actions={<>
|
||||
<Button size="sm" variant="outline" className="h-8 gap-1 px-2 text-xs"
|
||||
disabled={checkedIds.length !== 1}
|
||||
onClick={() => {
|
||||
const id = checkedIds[0]; if (!id) return;
|
||||
setEditObjid(id);
|
||||
setEditOpen(true);
|
||||
}}>
|
||||
<Pencil className="h-3.5 w-3.5" /> 수정
|
||||
</Button>
|
||||
<Button size="sm" variant="destructive" className="h-8 gap-1 px-2 text-xs"
|
||||
disabled={checkedIds.length === 0}
|
||||
onClick={async () => {
|
||||
const ok = await confirm(`선택한 ${checkedIds.length}건을 삭제하시겠어요?`, {
|
||||
description: "발주서와 품목이 함께 삭제돼요.",
|
||||
variant: "destructive",
|
||||
confirmText: "삭제",
|
||||
});
|
||||
if (!ok) return;
|
||||
try {
|
||||
for (const id of checkedIds) {
|
||||
await purchaseApi.deleteOrderForm(id);
|
||||
}
|
||||
toast.success("삭제 완료");
|
||||
setCheckedIds([]);
|
||||
fetchList();
|
||||
} catch (e: any) {
|
||||
toast.error(e?.response?.data?.message ?? e?.message ?? "삭제 실패");
|
||||
}
|
||||
}}>
|
||||
<Trash2 className="h-3.5 w-3.5" /> 삭제
|
||||
</Button>
|
||||
</>} />
|
||||
|
||||
<CompactFilterBar totalText={<>총 {total.toLocaleString()}건</>}>
|
||||
<CompactFilterField label="년도" width={100}>
|
||||
@@ -233,7 +275,21 @@ export default function PurchaseOrderWacePage() {
|
||||
exportToExcel(exportRows, "발주서관리.xlsx", "발주서");
|
||||
}}
|
||||
showChart
|
||||
onRowClick={(row: any) => {
|
||||
if (!row?.objid) return;
|
||||
setEditObjid(String(row.objid));
|
||||
setEditOpen(true);
|
||||
}}
|
||||
/>
|
||||
|
||||
<PurchaseOrderGeneralFormDialog
|
||||
open={editOpen}
|
||||
pomObjid={editObjid}
|
||||
onClose={() => setEditOpen(false)}
|
||||
onSaved={() => { setEditOpen(false); fetchList(); }}
|
||||
/>
|
||||
|
||||
{ConfirmDialogComponent}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import { PageHeader } from "@/components/common/PageHeader";
|
||||
import { apiClient } from "@/lib/api/client";
|
||||
import { purchaseApi, PurchaseListFilter, OptionItem } from "@/lib/api/purchase";
|
||||
import { exportToExcel } from "@/lib/utils/excelExport";
|
||||
import { PurchaseOrderGeneralFormDialog } from "@/components/purchase/PurchaseOrderGeneralFormDialog";
|
||||
|
||||
const PARENT_PURCHASE_TYPE = "0001814"; // 구매유형 comm_code
|
||||
const PARENT_PART_TYPE = "0000001"; // 제품구분 comm_code
|
||||
@@ -46,6 +47,10 @@ export default function ProposalPage() {
|
||||
const [partTypeOpts, setPartTypeOpts] = useState<SmartSelectOption[]>([]);
|
||||
const [userOpts, setUserOpts] = useState<OptionItem[]>([]);
|
||||
|
||||
// 발주서생성 다이얼로그
|
||||
const [orderFormOpen, setOrderFormOpen] = useState(false);
|
||||
const [orderFormProposalId, setOrderFormProposalId] = useState<string>("");
|
||||
|
||||
const fetchList = useCallback(async (override?: Partial<PurchaseListFilter>) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
@@ -124,7 +129,12 @@ export default function ProposalPage() {
|
||||
</Button>
|
||||
<Button size="sm" variant="default" className="h-8 gap-1 px-2 text-xs"
|
||||
disabled={checkedIds.length !== 1}
|
||||
onClick={() => toast.info("발주서생성 — purchase_order_part 신설 후 활성")}>
|
||||
onClick={() => {
|
||||
const proposalId = checkedIds[0];
|
||||
if (!proposalId) return;
|
||||
setOrderFormProposalId(proposalId);
|
||||
setOrderFormOpen(true);
|
||||
}}>
|
||||
<ClipboardCheck className="h-3.5 w-3.5" /> 발주서생성
|
||||
</Button>
|
||||
</>}
|
||||
@@ -194,6 +204,13 @@ export default function ProposalPage() {
|
||||
}}
|
||||
showChart
|
||||
/>
|
||||
|
||||
<PurchaseOrderGeneralFormDialog
|
||||
open={orderFormOpen}
|
||||
proposalObjid={orderFormProposalId}
|
||||
onClose={() => setOrderFormOpen(false)}
|
||||
onSaved={() => { setOrderFormOpen(false); fetchList(); }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user