feat(WEB): 견적 개소 복제 기능 추가 - 부호 자동 채번
- LocationListPanel에 복제 버튼(Copy 아이콘) 추가 - 복제 시 모든 개소 데이터(bomResult 포함) 복사 - 부호 자동 채번: 같은 접두어의 최대 번호 +1, 자릿수 유지
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useCallback } from "react";
|
||||
import { Plus, Upload, Download, Pencil, Trash2 } from "lucide-react";
|
||||
import { Plus, Upload, Download, Pencil, Trash2, Copy } from "lucide-react";
|
||||
import { toast } from "sonner";
|
||||
|
||||
import { Button } from "../ui/button";
|
||||
@@ -77,6 +77,7 @@ interface LocationListPanelProps {
|
||||
onSelectLocation: (id: string) => void;
|
||||
onAddLocation: (location: Omit<LocationItem, "id">) => Promise<boolean>;
|
||||
onDeleteLocation: (id: string) => void;
|
||||
onCloneLocation?: (id: string) => void;
|
||||
onUpdateLocation: (locationId: string, updates: Partial<LocationItem>) => void;
|
||||
onExcelUpload: (locations: Omit<LocationItem, "id">[]) => void;
|
||||
finishedGoods: FinishedGoods[];
|
||||
@@ -94,6 +95,7 @@ export function LocationListPanel({
|
||||
onSelectLocation,
|
||||
onAddLocation,
|
||||
onDeleteLocation,
|
||||
onCloneLocation,
|
||||
onUpdateLocation,
|
||||
onExcelUpload,
|
||||
finishedGoods,
|
||||
@@ -523,6 +525,16 @@ export function LocationListPanel({
|
||||
>
|
||||
<Pencil className="h-4 w-4 text-gray-600" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onCloneLocation?.(loc.id);
|
||||
}}
|
||||
className="p-1 hover:bg-blue-100 rounded"
|
||||
title="복제"
|
||||
>
|
||||
<Copy className="h-4 w-4 text-blue-500" />
|
||||
</button>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
|
||||
@@ -500,6 +500,46 @@ export function QuoteRegistrationV2({
|
||||
}
|
||||
}, []);
|
||||
|
||||
// 개소 삭제
|
||||
// 개소 복제 (부호 자동 채번)
|
||||
const handleCloneLocation = useCallback((locationId: string) => {
|
||||
const source = formData.locations.find((loc) => loc.id === locationId);
|
||||
if (!source) return;
|
||||
|
||||
// 부호에서 접두어와 번호 분리 (예: "DS-01" → prefix="DS-", num=1)
|
||||
const codeMatch = source.code.match(/^(.*?)(\d+)$/);
|
||||
let newCode = source.code + "-copy";
|
||||
|
||||
if (codeMatch) {
|
||||
const prefix = codeMatch[1]; // "DS-"
|
||||
const numLength = codeMatch[2].length; // 2 (자릿수 보존)
|
||||
|
||||
// 같은 접두어를 가진 부호 중 최대 번호 찾기
|
||||
let maxNum = 0;
|
||||
formData.locations.forEach((loc) => {
|
||||
const m = loc.code.match(new RegExp(`^${prefix.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(\\d+)$`));
|
||||
if (m) {
|
||||
maxNum = Math.max(maxNum, parseInt(m[1], 10));
|
||||
}
|
||||
});
|
||||
|
||||
newCode = prefix + String(maxNum + 1).padStart(numLength, "0");
|
||||
}
|
||||
|
||||
const clonedLocation: LocationItem = {
|
||||
...source,
|
||||
id: `loc-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
||||
code: newCode,
|
||||
};
|
||||
|
||||
setFormData((prev) => ({
|
||||
...prev,
|
||||
locations: [...prev.locations, clonedLocation],
|
||||
}));
|
||||
setSelectedLocationId(clonedLocation.id);
|
||||
toast.success(`개소가 복제되었습니다. (${newCode})`);
|
||||
}, [formData.locations]);
|
||||
|
||||
// 개소 삭제
|
||||
const handleDeleteLocation = useCallback((locationId: string) => {
|
||||
setFormData((prev) => ({
|
||||
@@ -840,6 +880,7 @@ export function QuoteRegistrationV2({
|
||||
onSelectLocation={setSelectedLocationId}
|
||||
onAddLocation={handleAddLocation}
|
||||
onDeleteLocation={handleDeleteLocation}
|
||||
onCloneLocation={handleCloneLocation}
|
||||
onUpdateLocation={handleUpdateLocation}
|
||||
onExcelUpload={handleExcelUpload}
|
||||
finishedGoods={finishedGoods}
|
||||
|
||||
Reference in New Issue
Block a user