feat: 테스트 테이블에서 채번 규칙 목록 조회 API 추가 및 회사별 카테고리 컬럼 조회 기능 구현

- 테스트 테이블에서 채번 규칙 목록을 조회하는 API를 추가하였습니다. 이 API는 회사 코드와 선택적 메뉴 OBJID를 기반으로 규칙을 반환합니다.
- 회사별 카테고리 컬럼을 조회하는 API를 추가하여, 회사 코드에 따라 카테고리 컬럼을 필터링하여 반환하도록 개선하였습니다.
- 관련된 서비스 및 라우터를 업데이트하여 새로운 기능을 통합하였습니다.
This commit is contained in:
kjs
2026-01-26 16:32:20 +09:00
parent 9b8546ebef
commit 1753822211
9 changed files with 552 additions and 273 deletions

View File

@@ -33,10 +33,12 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogFooter,
} from "@/components/ui/dialog";
interface GridSettings {
columns: number;
@@ -173,112 +175,118 @@ export const SlimToolbar: React.FC<SlimToolbarProps> = ({
{screenResolution && (
<>
<div className="h-6 w-px bg-gray-300" />
<Popover open={showCustomInput} onOpenChange={setShowCustomInput}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex items-center space-x-2 rounded-md bg-blue-50 px-3 py-1.5 transition-colors hover:bg-blue-100">
{getCategoryIcon(screenResolution.category || "desktop")}
<span className="text-sm font-medium text-blue-900">{screenResolution.name}</span>
<span className="text-xs text-blue-600">
({screenResolution.width} × {screenResolution.height})
</span>
{onResolutionChange && <ChevronDown className="h-3 w-3 text-blue-600" />}
</button>
</DropdownMenuTrigger>
{onResolutionChange && (
<DropdownMenuContent align="start" className="w-64">
<DropdownMenuLabel className="text-xs text-gray-500"></DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
<DropdownMenuItem
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Monitor className="h-4 w-4 text-blue-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500">릿</DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "tablet").map((resolution) => (
<DropdownMenuItem
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Tablet className="h-4 w-4 text-green-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500"></DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "mobile").map((resolution) => (
<DropdownMenuItem
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Smartphone className="h-4 w-4 text-purple-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500"> </DropdownMenuLabel>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button className="flex items-center space-x-2 rounded-md bg-blue-50 px-3 py-1.5 transition-colors hover:bg-blue-100">
{getCategoryIcon(screenResolution.category || "desktop")}
<span className="text-sm font-medium text-blue-900">{screenResolution.name}</span>
<span className="text-xs text-blue-600">
({screenResolution.width} × {screenResolution.height})
</span>
{onResolutionChange && <ChevronDown className="h-3 w-3 text-blue-600" />}
</button>
</DropdownMenuTrigger>
{onResolutionChange && (
<DropdownMenuContent align="start" className="w-64">
<DropdownMenuLabel className="text-xs text-gray-500"></DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "desktop").map((resolution) => (
<DropdownMenuItem
onClick={(e) => {
e.preventDefault();
setCustomWidth(screenResolution.width.toString());
setCustomHeight(screenResolution.height.toString());
setShowCustomInput(true);
}}
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Settings className="h-4 w-4 text-gray-600" />
<span className="flex-1"> ...</span>
<Monitor className="h-4 w-4 text-blue-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
</DropdownMenuContent>
)}
</DropdownMenu>
<PopoverContent align="start" className="w-64 p-3">
<div className="space-y-3">
<div className="text-sm font-medium"> </div>
<div className="grid grid-cols-2 gap-2">
<div className="space-y-1">
<Label className="text-xs text-gray-500"> (px)</Label>
<Input
type="number"
value={customWidth}
onChange={(e) => setCustomWidth(e.target.value)}
placeholder="1920"
className="h-8 text-xs"
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-gray-500"> (px)</Label>
<Input
type="number"
value={customHeight}
onChange={(e) => setCustomHeight(e.target.value)}
placeholder="1080"
className="h-8 text-xs"
/>
</div>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500">릿</DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "tablet").map((resolution) => (
<DropdownMenuItem
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Tablet className="h-4 w-4 text-green-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500"></DropdownMenuLabel>
{SCREEN_RESOLUTIONS.filter((r) => r.category === "mobile").map((resolution) => (
<DropdownMenuItem
key={resolution.name}
onClick={() => onResolutionChange(resolution)}
className="flex items-center space-x-2"
>
<Smartphone className="h-4 w-4 text-purple-600" />
<span className="flex-1">{resolution.name}</span>
<span className="text-xs text-gray-400">
{resolution.width}×{resolution.height}
</span>
</DropdownMenuItem>
))}
<DropdownMenuSeparator />
<DropdownMenuLabel className="text-xs text-gray-500"> </DropdownMenuLabel>
<DropdownMenuItem
onClick={() => {
setCustomWidth(screenResolution.width.toString());
setCustomHeight(screenResolution.height.toString());
setShowCustomInput(true);
}}
className="flex items-center space-x-2"
>
<Settings className="h-4 w-4 text-gray-600" />
<span className="flex-1"> ...</span>
</DropdownMenuItem>
</DropdownMenuContent>
)}
</DropdownMenu>
{/* 사용자 정의 해상도 다이얼로그 */}
<Dialog open={showCustomInput} onOpenChange={setShowCustomInput}>
<DialogContent className="sm:max-w-[320px]">
<DialogHeader>
<DialogTitle> </DialogTitle>
</DialogHeader>
<div className="grid grid-cols-2 gap-4 py-4">
<div className="space-y-2">
<Label htmlFor="customWidth" className="text-sm"> (px)</Label>
<Input
id="customWidth"
type="number"
value={customWidth}
onChange={(e) => setCustomWidth(e.target.value)}
placeholder="1920"
/>
</div>
<Button onClick={handleCustomResolution} size="sm" className="w-full">
<div className="space-y-2">
<Label htmlFor="customHeight" className="text-sm"> (px)</Label>
<Input
id="customHeight"
type="number"
value={customHeight}
onChange={(e) => setCustomHeight(e.target.value)}
placeholder="1080"
/>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setShowCustomInput(false)}>
</Button>
<Button onClick={handleCustomResolution}>
</Button>
</div>
</PopoverContent>
</Popover>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)}