diff --git a/backend-node/src/controllers/workInstructionController.ts b/backend-node/src/controllers/workInstructionController.ts index f37584d3..9f855147 100644 --- a/backend-node/src/controllers/workInstructionController.ts +++ b/backend-node/src/controllers/workInstructionController.ts @@ -188,13 +188,25 @@ export async function save(req: AuthenticatedRequest, res: Response) { wiId = insertRes.rows[0].id; } + let totalQty = 0; + let firstRouting: string | null = null; for (const item of items) { + const itemRouting = item.routing || null; + if (!firstRouting && itemRouting) firstRouting = itemRouting; + totalQty += Number(item.qty || 0); await client.query( `INSERT INTO work_instruction_detail (id,company_code,work_instruction_no,work_instruction_id,item_number,qty,remark,source_table,source_id,part_code,routing_version_id,created_date,writer) VALUES (gen_random_uuid()::text,$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,NOW(),$11)`, - [companyCode, wiNo, wiId, item.itemNumber||item.itemCode||"", item.qty||"0", item.remark||"", item.sourceTable||"", item.sourceId||"", item.partCode||item.itemNumber||item.itemCode||"", item.routing||null, userId] + [companyCode, wiNo, wiId, item.itemNumber||item.itemCode||"", item.qty||"0", item.remark||"", item.sourceTable||"", item.sourceId||"", item.partCode||item.itemNumber||item.itemCode||"", itemRouting, userId] ); } + // 마스터 qty/routing 자동 동기화 (디테일 합계 + 첫 번째 라우팅) + const effectiveRouting = routingVersionId || firstRouting; + await client.query( + `UPDATE work_instruction SET qty = $1, routing = COALESCE(routing, $2) WHERE id = $3`, + [String(totalQty), effectiveRouting, wiId] + ); + await client.query("COMMIT"); return res.json({ success: true, data: { id: wiId, workInstructionNo: wiNo } }); } catch (txErr) { await client.query("ROLLBACK"); throw txErr; } diff --git a/frontend/app/(main)/COMPANY_10/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_10/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_10/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_10/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_16/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_16/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_16/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_16/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_29/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_29/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_29/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_29/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_30/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_30/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_30/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_30/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_7/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_7/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_7/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_7/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_8/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_8/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_8/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_8/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />
diff --git a/frontend/app/(main)/COMPANY_9/equipment/info/page.tsx b/frontend/app/(main)/COMPANY_9/equipment/info/page.tsx index f32273ae..cad20e4d 100644 --- a/frontend/app/(main)/COMPANY_9/equipment/info/page.tsx +++ b/frontend/app/(main)/COMPANY_9/equipment/info/page.tsx @@ -35,6 +35,7 @@ import { useTableSettings } from "@/hooks/useTableSettings"; import { TableSettingsModal } from "@/components/common/TableSettingsModal"; import { DynamicSearchFilter, FilterValue } from "@/components/common/DynamicSearchFilter"; import { EDataTable, EDataTableColumn } from "@/components/common/EDataTable"; +import { previewNumberingCode, allocateNumberingCode } from "@/lib/api/numberingRule"; const EQUIP_TABLE = "equipment_mng"; const INSPECTION_TABLE = "equipment_inspection_item"; @@ -73,6 +74,7 @@ export default function EquipmentInfoPage() { const [equipModalOpen, setEquipModalOpen] = useState(false); const [equipEditMode, setEquipEditMode] = useState(false); const [equipForm, setEquipForm] = useState>({}); + const [equipCodeRuleId, setEquipCodeRuleId] = useState(null); const [saving, setSaving] = useState(false); // 기본정보 탭 편집 폼 @@ -242,7 +244,20 @@ export default function EquipmentInfoPage() { }; // 설비 등록/수정 - const openEquipRegister = () => { setEquipForm({}); setEquipEditMode(false); setEquipModalOpen(true); }; + const openEquipRegister = async () => { + setEquipForm({}); setEquipEditMode(false); setEquipCodeRuleId(null); setEquipModalOpen(true); + try { + const ruleRes = await apiClient.get("/numbering-rules/by-column/equipment_mng/equipment_code"); + if (ruleRes.data?.success && ruleRes.data?.data?.ruleId) { + const ruleId = ruleRes.data.data.ruleId; + setEquipCodeRuleId(ruleId); + const previewRes = await previewNumberingCode(ruleId); + if (previewRes.success && previewRes.data?.generatedCode) { + setEquipForm((p) => ({ ...p, equipment_code: previewRes.data.generatedCode })); + } + } + } catch { /* 채번 규칙 없으면 수동 입력 */ } + }; const openEquipEdit = () => { if (!selectedEquip) return; setEquipForm({ ...selectedEquip }); setEquipEditMode(true); setEquipModalOpen(true); }; const handleEquipSave = async () => { @@ -254,6 +269,16 @@ export default function EquipmentInfoPage() { await apiClient.put(`/table-management/tables/${EQUIP_TABLE}/edit`, { originalData: { id }, updatedData: fields }); toast.success("수정되었습니다."); } else { + // 채번 규칙이 있으면 allocate + if (equipCodeRuleId) { + try { + const allocRes = await allocateNumberingCode(equipCodeRuleId); + if (allocRes.success && allocRes.data?.generatedCode) { + fields.equipment_code = allocRes.data.generatedCode; + } else { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } catch { toast.error("설비코드 채번 실패"); setSaving(false); return; } + } + if (!fields.equipment_code) { toast.error("설비코드는 필수입니다."); setSaving(false); return; } await apiClient.post(`/table-management/tables/${EQUIP_TABLE}/add`, { id: crypto.randomUUID(), ...fields }); toast.success("등록되었습니다."); } @@ -709,7 +734,7 @@ export default function EquipmentInfoPage() {
- setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} />
+ !equipCodeRuleId && setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} readOnly={!!equipCodeRuleId || equipEditMode} placeholder={equipCodeRuleId ? "자동 채번" : "설비코드"} className={cn("h-9", (equipCodeRuleId || equipEditMode) && "bg-muted cursor-not-allowed")} />
setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" />