feat: Implement automatic equipment code generation and allocation in equipment registration
- Enhanced the equipment registration process to support automatic code generation based on predefined numbering rules. - Integrated API calls to fetch and preview numbering rules, allowing for dynamic equipment code assignment. - Added error handling to manage failures in code allocation, ensuring a smoother user experience during equipment registration. - Updated the input field for equipment code to reflect automatic generation status, improving clarity for users. - These changes aim to streamline the equipment management process and enhance usability across multiple company implementations.
This commit is contained in:
@@ -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; }
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
@@ -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<Record<string, any>>({});
|
||||
const [equipCodeRuleId, setEquipCodeRuleId] = useState<string | null>(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() {
|
||||
<div className="flex-1 overflow-y-auto">
|
||||
<div className="grid grid-cols-2 gap-4 py-4">
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비코드</Label>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_code: e.target.value }))} placeholder="설비코드" className="h-9" disabled={equipEditMode} /></div>
|
||||
<Input value={equipForm.equipment_code || ""} onChange={(e) => !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")} /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비명 <span className="text-destructive">*</span></Label>
|
||||
<Input value={equipForm.equipment_name || ""} onChange={(e) => setEquipForm((p) => ({ ...p, equipment_name: e.target.value }))} placeholder="설비명" className="h-9" /></div>
|
||||
<div className="space-y-1.5"><Label className="text-sm">설비유형</Label>
|
||||
|
||||
Reference in New Issue
Block a user