-
-
-
- setSearchTerm(e.target.value)}
- className="pl-10"
- />
-
-
-
-
-
-
-
-
+
+
+
+
+ setSearchTerm(e.target.value)}
+ className="h-10 pl-10 text-sm"
+ />
-
-
- {/* 배치 작업 목록 */}
-
-
- 배치 작업 목록 ({filteredJobs.length}개)
-
-
- {isLoading ? (
-
- ) : filteredJobs.length === 0 ? (
-
- {jobs.length === 0 ? "배치 작업이 없습니다." : "검색 결과가 없습니다."}
-
- ) : (
+
+
+
+
+
+
+
+
+ {/* 배치 작업 목록 제목 */}
+
+ 총 {filteredJobs.length}개
+
+
+ {isLoading ? (
+ <>
+ {/* 데스크톱 스켈레톤 */}
+
-
- 작업명
- 타입
- 스케줄
- 상태
- 실행 통계
- 성공률
- 마지막 실행
- 작업
+
+ 작업명
+ 타입
+ 스케줄
+ 상태
+ 실행 통계
+ 성공률
+ 마지막 실행
+ 작업
+
+
+
+ {Array.from({ length: 5 }).map((_, i) => (
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+
+ {/* 모바일 스켈레톤 */}
+
+ {Array.from({ length: 4 }).map((_, i) => (
+
+
+
+ {Array.from({ length: 3 }).map((_, j) => (
+
+ ))}
+
+
+ ))}
+
+ >
+ ) : filteredJobs.length === 0 ? (
+
+ {jobs.length === 0 ? "배치 작업이 없습니다." : "검색 결과가 없습니다."}
+
+ ) : (
+ <>
+ {/* 데스크톱 테이블 */}
+
+
+
+
+ 작업명
+ 타입
+ 스케줄
+ 상태
+ 실행 통계
+ 성공률
+ 마지막 실행
+ 작업
{filteredJobs.map((job) => (
-
-
+
+
{job.job_name}
{job.description && (
-
- {job.description}
-
+
{job.description}
)}
-
- {getTypeBadge(job.job_type)}
-
-
- {job.schedule_cron || "-"}
-
-
- {getStatusBadge(job.is_active)}
-
-
-
+
{getTypeBadge(job.job_type)}
+
{job.schedule_cron || "-"}
+
{getStatusBadge(job.is_active)}
+
+
총 {job.execution_count}회
-
+
성공 {job.success_count} / 실패 {job.failure_count}
-
-
-
= 90 ? 'text-green-600' :
- getSuccessRate(job) >= 70 ? 'text-yellow-600' : 'text-red-600'
- }`}>
- {getSuccessRate(job)}%
-
-
+
+ = 90 ? 'text-success' :
+ getSuccessRate(job) >= 70 ? 'text-warning' : 'text-destructive'
+ }`}>
+ {getSuccessRate(job)}%
+
-
+
{job.last_executed_at
? new Date(job.last_executed_at).toLocaleString()
: "-"}
-
+
- )}
-
-
+
+
+ {/* 모바일 카드 */}
+
+ {filteredJobs.map((job) => (
+
+
+
+
{job.job_name}
+ {job.description && (
+
{job.description}
+ )}
+
+
{getStatusBadge(job.is_active)}
+
+
+
+ 타입
+ {getTypeBadge(job.job_type)}
+
+
+ 스케줄
+ {job.schedule_cron || "-"}
+
+
+ 실행 횟수
+ {job.execution_count}회
+
+
+ 성공률
+ = 90 ? 'text-success' :
+ getSuccessRate(job) >= 70 ? 'text-warning' : 'text-destructive'
+ }`}>
+ {getSuccessRate(job)}%
+
+
+
+ 마지막 실행
+
+ {job.last_executed_at
+ ? new Date(job.last_executed_at).toLocaleDateString()
+ : "-"}
+
+
+
+
+
+
+
+
+
+ ))}
+
+ >
+ )}
{/* 배치 타입 선택 모달 */}
{isBatchTypeModalOpen && (
diff --git a/frontend/app/(main)/admin/standards/page.tsx b/frontend/app/(main)/admin/standards/page.tsx
index 71a63371..67a43bab 100644
--- a/frontend/app/(main)/admin/standards/page.tsx
+++ b/frontend/app/(main)/admin/standards/page.tsx
@@ -4,7 +4,6 @@ import React, { useState, useMemo } 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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import {
@@ -20,7 +19,7 @@ import {
} from "@/components/ui/alert-dialog";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
-import { Plus, Search, Edit, Trash2, Eye, Filter, RotateCcw, Settings, SortAsc, SortDesc } from "lucide-react";
+import { Plus, Search, Edit, Trash2, Eye, RotateCcw, SortAsc, SortDesc } from "lucide-react";
import { useWebTypes } from "@/hooks/admin/useWebTypes";
import Link from "next/link";
@@ -104,230 +103,241 @@ export default function WebTypesManagePage() {
setSortDirection("asc");
};
- // 로딩 상태
- if (isLoading) {
- return (
-
-
웹타입 목록을 불러오는 중...
+ return (
+
+ {/* 페이지 헤더 */}
+
+
+
웹타입 관리
+
화면관리에서 사용할 웹타입들을 관리합니다
+
+
+
+
- );
- }
- // 에러 상태
- if (error) {
- return (
-
-
-
웹타입 목록을 불러오는데 실패했습니다.
-