메뉴 복사로직 개선

This commit is contained in:
kjs 2025-12-18 10:55:26 +09:00
parent c3f066f88f
commit 75e5326b3e
4 changed files with 925 additions and 58 deletions

View File

@ -3394,13 +3394,23 @@ export async function copyMenu(
}
: undefined;
// 추가 복사 옵션 (카테고리, 코드, 채번규칙 등)
const additionalCopyOptions = req.body.additionalCopyOptions
? {
copyCodeCategory: req.body.additionalCopyOptions.copyCodeCategory === true,
copyNumberingRules: req.body.additionalCopyOptions.copyNumberingRules === true,
copyCategoryMapping: req.body.additionalCopyOptions.copyCategoryMapping === true,
}
: undefined;
// 메뉴 복사 실행
const menuCopyService = new MenuCopyService();
const result = await menuCopyService.copyMenu(
parseInt(menuObjid, 10),
targetCompanyCode,
userId,
screenNameConfig
screenNameConfig,
additionalCopyOptions
);
logger.info("✅ 메뉴 복사 API 성공");

File diff suppressed because it is too large Load Diff

View File

@ -56,6 +56,12 @@ export function MenuCopyDialog({
const [removeText, setRemoveText] = useState("");
const [addPrefix, setAddPrefix] = useState("");
// 카테고리/코드 복사 옵션
const [copyCodeCategory, setCopyCodeCategory] = useState(false);
const [copyNumberingRules, setCopyNumberingRules] = useState(false);
const [copyCategoryMapping, setCopyCategoryMapping] = useState(false);
const [copyTableTypeColumns, setCopyTableTypeColumns] = useState(false);
// 회사 목록 로드
useEffect(() => {
if (open) {
@ -66,6 +72,10 @@ export function MenuCopyDialog({
setUseBulkRename(false);
setRemoveText("");
setAddPrefix("");
setCopyCodeCategory(false);
setCopyNumberingRules(false);
setCopyCategoryMapping(false);
setCopyTableTypeColumns(false);
}
}, [open]);
@ -112,10 +122,19 @@ export function MenuCopyDialog({
}
: undefined;
// 추가 복사 옵션
const additionalCopyOptions = {
copyCodeCategory,
copyNumberingRules,
copyCategoryMapping,
copyTableTypeColumns,
};
const response = await menuApi.copyMenu(
menuObjid,
targetCompanyCode,
screenNameConfig
screenNameConfig,
additionalCopyOptions
);
if (response.success && response.data) {
@ -264,19 +283,82 @@ export function MenuCopyDialog({
</div>
)}
{/* 추가 복사 옵션 */}
{!result && (
<div className="space-y-3">
<p className="text-xs font-medium"> ():</p>
<div className="space-y-2 pl-2 border-l-2">
<div className="flex items-center gap-2">
<Checkbox
id="copyCodeCategory"
checked={copyCodeCategory}
onCheckedChange={(checked) => setCopyCodeCategory(checked as boolean)}
disabled={copying}
/>
<Label
htmlFor="copyCodeCategory"
className="text-xs cursor-pointer"
>
+
</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox
id="copyNumberingRules"
checked={copyNumberingRules}
onCheckedChange={(checked) => setCopyNumberingRules(checked as boolean)}
disabled={copying}
/>
<Label
htmlFor="copyNumberingRules"
className="text-xs cursor-pointer"
>
</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox
id="copyCategoryMapping"
checked={copyCategoryMapping}
onCheckedChange={(checked) => setCopyCategoryMapping(checked as boolean)}
disabled={copying}
/>
<Label
htmlFor="copyCategoryMapping"
className="text-xs cursor-pointer"
>
+
</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox
id="copyTableTypeColumns"
checked={copyTableTypeColumns}
onCheckedChange={(checked) => setCopyTableTypeColumns(checked as boolean)}
disabled={copying}
/>
<Label
htmlFor="copyTableTypeColumns"
className="text-xs cursor-pointer"
>
</Label>
</div>
</div>
</div>
)}
{/* 복사 항목 안내 */}
{!result && (
<div className="rounded-md border p-3 text-xs">
<p className="font-medium mb-2"> :</p>
<p className="font-medium mb-2"> :</p>
<ul className="list-disc list-inside space-y-1 text-muted-foreground">
<li> ( )</li>
<li> + (, )</li>
<li> (, )</li>
<li> + </li>
<li> + </li>
</ul>
<p className="mt-2 text-warning">
.
<p className="mt-2 text-muted-foreground">
* , , .
</p>
</div>
)}
@ -294,10 +376,40 @@ export function MenuCopyDialog({
<span className="text-muted-foreground">:</span>{" "}
<span className="font-medium">{result.copiedScreens}</span>
</div>
<div className="col-span-2">
<div>
<span className="text-muted-foreground">:</span>{" "}
<span className="font-medium">{result.copiedFlows}</span>
</div>
{(result.copiedCodeCategories ?? 0) > 0 && (
<div>
<span className="text-muted-foreground"> :</span>{" "}
<span className="font-medium">{result.copiedCodeCategories}</span>
</div>
)}
{(result.copiedCodes ?? 0) > 0 && (
<div>
<span className="text-muted-foreground">:</span>{" "}
<span className="font-medium">{result.copiedCodes}</span>
</div>
)}
{(result.copiedNumberingRules ?? 0) > 0 && (
<div>
<span className="text-muted-foreground">:</span>{" "}
<span className="font-medium">{result.copiedNumberingRules}</span>
</div>
)}
{(result.copiedCategoryMappings ?? 0) > 0 && (
<div>
<span className="text-muted-foreground"> :</span>{" "}
<span className="font-medium">{result.copiedCategoryMappings}</span>
</div>
)}
{(result.copiedTableTypeColumns ?? 0) > 0 && (
<div>
<span className="text-muted-foreground"> :</span>{" "}
<span className="font-medium">{result.copiedTableTypeColumns}</span>
</div>
)}
</div>
</div>
)}

View File

@ -170,6 +170,12 @@ export const menuApi = {
screenNameConfig?: {
removeText?: string;
addPrefix?: string;
},
additionalCopyOptions?: {
copyCodeCategory?: boolean;
copyNumberingRules?: boolean;
copyCategoryMapping?: boolean;
copyTableTypeColumns?: boolean;
}
): Promise<ApiResponse<MenuCopyResult>> => {
try {
@ -177,7 +183,8 @@ export const menuApi = {
`/admin/menus/${menuObjid}/copy`,
{
targetCompanyCode,
screenNameConfig
screenNameConfig,
additionalCopyOptions
}
);
return response.data;
@ -199,6 +206,11 @@ export interface MenuCopyResult {
copiedMenus: number;
copiedScreens: number;
copiedFlows: number;
copiedCodeCategories?: number;
copiedCodes?: number;
copiedNumberingRules?: number;
copiedCategoryMappings?: number;
copiedTableTypeColumns?: number;
menuIdMap: Record<number, number>;
screenIdMap: Record<number, number>;
flowIdMap: Record<number, number>;