generated from gc/template-java-maven
feat: Request Logs 조회 기간 프리셋 + 필터 UI 개선
- 날짜 프리셋 버튼 추가 (오늘/어제/최근7일/이번달/지난달/직접선택) - 필터 영역 한 줄로 통합 (서비스/상태/Method/검색/초기화) - IP 입력 필드 제거
This commit is contained in:
부모
97e5a24343
커밋
765d0e01c6
@ -26,14 +26,13 @@ const REQUEST_STATUSES = ['SUCCESS', 'FAIL', 'DENIED', 'EXPIRED', 'INVALID_KEY',
|
||||
const HTTP_METHODS = ['GET', 'POST', 'PUT', 'DELETE'];
|
||||
const DEFAULT_PAGE_SIZE = 20;
|
||||
|
||||
const getTodayString = (): string => {
|
||||
const d = new Date();
|
||||
const year = d.getFullYear();
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${year}-${month}-${day}`;
|
||||
const formatDate = (d: Date): string => {
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;
|
||||
};
|
||||
|
||||
const getToday = (): string => formatDate(new Date());
|
||||
const getTodayString = getToday;
|
||||
|
||||
const formatDateTime = (dateStr: string): string => {
|
||||
const d = new Date(dateStr);
|
||||
const year = d.getFullYear();
|
||||
@ -50,10 +49,10 @@ const RequestLogsPage = () => {
|
||||
|
||||
const [startDate, setStartDate] = useState(getTodayString());
|
||||
const [endDate, setEndDate] = useState(getTodayString());
|
||||
const [datePreset, setDatePreset] = useState('오늘');
|
||||
const [serviceId, setServiceId] = useState('');
|
||||
const [requestStatus, setRequestStatus] = useState('');
|
||||
const [requestMethod, setRequestMethod] = useState('');
|
||||
const [requestIp, setRequestIp] = useState('');
|
||||
|
||||
const [services, setServices] = useState<ServiceInfo[]>([]);
|
||||
const [result, setResult] = useState<PageResponse<RequestLog> | null>(null);
|
||||
@ -84,7 +83,6 @@ const RequestLogsPage = () => {
|
||||
serviceId: serviceId ? Number(serviceId) : undefined,
|
||||
requestStatus: requestStatus || undefined,
|
||||
requestMethod: requestMethod || undefined,
|
||||
requestIp: requestIp || undefined,
|
||||
page,
|
||||
size: DEFAULT_PAGE_SIZE,
|
||||
};
|
||||
@ -104,10 +102,10 @@ const RequestLogsPage = () => {
|
||||
const handleReset = () => {
|
||||
setStartDate(getTodayString());
|
||||
setEndDate(getTodayString());
|
||||
setDatePreset('오늘');
|
||||
setServiceId('');
|
||||
setRequestStatus('');
|
||||
setRequestMethod('');
|
||||
setRequestIp('');
|
||||
setCurrentPage(0);
|
||||
};
|
||||
|
||||
@ -169,45 +167,68 @@ const RequestLogsPage = () => {
|
||||
{/* Search Form */}
|
||||
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 mb-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
|
||||
<div>
|
||||
<div className="md:col-span-3">
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">기간</label>
|
||||
<div className="flex items-center gap-2 flex-wrap mb-2">
|
||||
{([
|
||||
{ label: '오늘', fn: () => { const t = getToday(); setStartDate(t); setEndDate(t); setDatePreset('오늘'); } },
|
||||
{ label: '어제', fn: () => { const d = new Date(); d.setDate(d.getDate() - 1); const y = formatDate(d); setStartDate(y); setEndDate(y); setDatePreset('어제'); } },
|
||||
{ label: '최근 7일', fn: () => { const d = new Date(); d.setDate(d.getDate() - 6); setStartDate(formatDate(d)); setEndDate(getToday()); setDatePreset('최근 7일'); } },
|
||||
{ label: '이번 달', fn: () => { const d = new Date(); setStartDate(`${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`); setEndDate(getToday()); setDatePreset('이번 달'); } },
|
||||
{ label: '지난 달', fn: () => { const d = new Date(); d.setMonth(d.getMonth() - 1); const s = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-01`; const e = new Date(d.getFullYear(), d.getMonth() + 1, 0); setStartDate(s); setEndDate(formatDate(e)); setDatePreset('지난 달'); } },
|
||||
{ label: '직접 선택', fn: () => { setDatePreset('직접 선택'); } },
|
||||
]).map((btn) => (
|
||||
<button
|
||||
key={btn.label}
|
||||
type="button"
|
||||
onClick={btn.fn}
|
||||
className={`px-3 py-1.5 text-xs font-medium rounded-lg border transition-colors ${
|
||||
datePreset === btn.label
|
||||
? 'bg-blue-50 dark:bg-blue-900/20 border-blue-300 dark:border-blue-700 text-blue-600 dark:text-blue-400'
|
||||
: 'border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-400 hover:bg-gray-50 dark:hover:bg-gray-700/50'
|
||||
}`}
|
||||
>
|
||||
{btn.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="date"
|
||||
value={startDate}
|
||||
onChange={(e) => setStartDate(e.target.value)}
|
||||
onChange={(e) => { setStartDate(e.target.value); setDatePreset('직접 선택'); }}
|
||||
className="flex-1 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
/>
|
||||
<span className="text-gray-500 dark:text-gray-400">~</span>
|
||||
<input
|
||||
type="date"
|
||||
value={endDate}
|
||||
onChange={(e) => setEndDate(e.target.value)}
|
||||
onChange={(e) => { setEndDate(e.target.value); setDatePreset('직접 선택'); }}
|
||||
className="flex-1 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-end gap-3 flex-wrap">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">서비스</label>
|
||||
<label className="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">서비스</label>
|
||||
<select
|
||||
value={serviceId}
|
||||
onChange={(e) => setServiceId(e.target.value)}
|
||||
className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
className="border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
{services.map((s) => (
|
||||
<option key={s.serviceId} value={s.serviceId}>
|
||||
{s.serviceName}
|
||||
</option>
|
||||
<option key={s.serviceId} value={s.serviceId}>{s.serviceName}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">상태</label>
|
||||
<label className="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">상태</label>
|
||||
<select
|
||||
value={requestStatus}
|
||||
onChange={(e) => setRequestStatus(e.target.value)}
|
||||
className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
className="border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
{REQUEST_STATUSES.map((s) => (
|
||||
@ -215,14 +236,12 @@ const RequestLogsPage = () => {
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">HTTP Method</label>
|
||||
<label className="block text-xs font-medium text-gray-500 dark:text-gray-400 mb-1">Method</label>
|
||||
<select
|
||||
value={requestMethod}
|
||||
onChange={(e) => setRequestMethod(e.target.value)}
|
||||
className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
className="border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
>
|
||||
<option value="">전체</option>
|
||||
{HTTP_METHODS.map((m) => (
|
||||
@ -230,17 +249,7 @@ const RequestLogsPage = () => {
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">IP</label>
|
||||
<input
|
||||
type="text"
|
||||
value={requestIp}
|
||||
onChange={(e) => setRequestIp(e.target.value)}
|
||||
placeholder="IP 주소"
|
||||
className="w-full border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 rounded-lg px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-end gap-2">
|
||||
<div className="flex items-end gap-2 ml-auto">
|
||||
<button
|
||||
onClick={() => handleSearch(0)}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg text-sm font-medium"
|
||||
|
||||
불러오는 중...
Reference in New Issue
Block a user