ERP-node/frontend/components/screen/ScreenList.tsx

261 lines
9.5 KiB
TypeScript

"use client";
import { useState, useEffect } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { MoreHorizontal, Edit, Trash2, Copy, Eye, Plus, Search, Palette } from "lucide-react";
import { ScreenDefinition } from "@/types/screen";
interface ScreenListProps {
onScreenSelect: (screen: ScreenDefinition) => void;
selectedScreen: ScreenDefinition | null;
onDesignScreen: (screen: ScreenDefinition) => void;
}
export default function ScreenList({ onScreenSelect, selectedScreen, onDesignScreen }: ScreenListProps) {
const [screens, setScreens] = useState<ScreenDefinition[]>([]);
const [loading, setLoading] = useState(true);
const [searchTerm, setSearchTerm] = useState("");
const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1);
// 샘플 데이터 (실제로는 API에서 가져옴)
useEffect(() => {
const mockScreens: ScreenDefinition[] = [
{
screenId: 1,
screenName: "사용자 관리 화면",
screenCode: "USER_MANAGEMENT",
tableName: "user_info",
companyCode: "COMP001",
description: "사용자 정보를 관리하는 화면",
isActive: "Y",
createdDate: new Date("2024-01-15"),
updatedDate: new Date("2024-01-15"),
createdBy: "admin",
updatedBy: "admin",
},
{
screenId: 2,
screenName: "부서 관리 화면",
screenCode: "DEPT_MANAGEMENT",
tableName: "dept_info",
companyCode: "COMP001",
description: "부서 정보를 관리하는 화면",
isActive: "Y",
createdDate: new Date("2024-01-16"),
updatedDate: new Date("2024-01-16"),
createdBy: "admin",
updatedBy: "admin",
},
{
screenId: 3,
screenName: "제품 관리 화면",
screenCode: "PRODUCT_MANAGEMENT",
tableName: "product_info",
companyCode: "COMP001",
description: "제품 정보를 관리하는 화면",
isActive: "Y",
createdDate: new Date("2024-01-17"),
updatedDate: new Date("2024-01-17"),
createdBy: "admin",
updatedBy: "admin",
},
];
setScreens(mockScreens);
setLoading(false);
}, []);
const filteredScreens = screens.filter(
(screen) =>
screen.screenName.toLowerCase().includes(searchTerm.toLowerCase()) ||
screen.screenCode.toLowerCase().includes(searchTerm.toLowerCase()) ||
screen.tableName.toLowerCase().includes(searchTerm.toLowerCase()),
);
const handleScreenSelect = (screen: ScreenDefinition) => {
onScreenSelect(screen);
};
const handleEdit = (screen: ScreenDefinition) => {
// 편집 모달 열기
console.log("편집:", screen);
};
const handleDelete = (screen: ScreenDefinition) => {
if (confirm(`"${screen.screenName}" 화면을 삭제하시겠습니까?`)) {
// 삭제 API 호출
console.log("삭제:", screen);
}
};
const handleCopy = (screen: ScreenDefinition) => {
// 복사 모달 열기
console.log("복사:", screen);
};
const handleView = (screen: ScreenDefinition) => {
// 미리보기 모달 열기
console.log("미리보기:", screen);
};
if (loading) {
return (
<div className="flex items-center justify-center py-8">
<div className="text-gray-500"> ...</div>
</div>
);
}
return (
<div className="space-y-4">
{/* 검색 및 필터 */}
<div className="flex items-center justify-between">
<div className="flex items-center space-x-2">
<div className="relative">
<Search className="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 transform text-gray-400" />
<Input
placeholder="화면명, 코드, 테이블명으로 검색..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="w-80 pl-10"
/>
</div>
</div>
<Button className="bg-blue-600 hover:bg-blue-700">
<Plus className="mr-2 h-4 w-4" />
</Button>
</div>
{/* 화면 목록 테이블 */}
<Card>
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span> ({filteredScreens.length})</span>
</CardTitle>
</CardHeader>
<CardContent>
<Table>
<TableHeader>
<TableRow>
<TableHead></TableHead>
<TableHead> </TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
<TableHead></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredScreens.map((screen) => (
<TableRow
key={screen.screenId}
className={`cursor-pointer hover:bg-gray-50 ${
selectedScreen?.screenId === screen.screenId ? "border-blue-200 bg-blue-50" : ""
}`}
onClick={() => handleScreenSelect(screen)}
>
<TableCell>
<div>
<div className="font-medium text-gray-900">{screen.screenName}</div>
{screen.description && <div className="mt-1 text-sm text-gray-500">{screen.description}</div>}
</div>
</TableCell>
<TableCell>
<Badge variant="outline" className="font-mono">
{screen.screenCode}
</Badge>
</TableCell>
<TableCell>
<span className="font-mono text-sm text-gray-600">{screen.tableName}</span>
</TableCell>
<TableCell>
<Badge
variant={screen.isActive === "Y" ? "default" : "secondary"}
className={screen.isActive === "Y" ? "bg-green-100 text-green-800" : "bg-gray-100 text-gray-800"}
>
{screen.isActive === "Y" ? "활성" : "비활성"}
</Badge>
</TableCell>
<TableCell>
<div className="text-sm text-gray-600">{screen.createdDate.toLocaleDateString()}</div>
<div className="text-xs text-gray-400">{screen.createdBy}</div>
</TableCell>
<TableCell>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" className="h-8 w-8 p-0">
<MoreHorizontal className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={() => onDesignScreen(screen)}>
<Palette className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleView(screen)}>
<Eye className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleEdit(screen)}>
<Edit className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleCopy(screen)}>
<Copy className="mr-2 h-4 w-4" />
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleDelete(screen)} className="text-red-600">
<Trash2 className="mr-2 h-4 w-4" />
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
{filteredScreens.length === 0 && <div className="py-8 text-center text-gray-500"> .</div>}
</CardContent>
</Card>
{/* 페이지네이션 */}
{totalPages > 1 && (
<div className="flex items-center justify-center space-x-2">
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage(Math.max(1, currentPage - 1))}
disabled={currentPage === 1}
>
</Button>
<span className="text-sm text-gray-600">
{currentPage} / {totalPages}
</span>
<Button
variant="outline"
size="sm"
onClick={() => setCurrentPage(Math.min(totalPages, currentPage + 1))}
disabled={currentPage === totalPages}
>
</Button>
</div>
)}
</div>
);
}