Initial commit: IT센터 출입자관리시스템 (ACS)

방문자 사전신청·승인, 입·출입 체크인/아웃, QR 배지, 재실현황,
블랙리스트, 대시보드 통계, 방문 리포트(엑셀)까지 7단계 전 기능 구현.

- backend: Spring Boot 3.4.5 / Java 21 (JDK 26 빌드), 세션 인증, JPA, H2/PostgreSQL, POI, ZXing, Flyway
- frontend: React 19 / Vite 6 / TypeScript
- infra: Docker Compose (db·app·web nginx), Flyway V1__init, Python 사용자 시드
- docs: 워크플로우 / 시퀀스 다이어그램(Mermaid) / 이슈·유의사항

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
unknown
2026-07-03 08:59:41 +09:00
commit f0c30d8005
130 changed files with 8884 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
import React, { useState } from 'react';
import { reportDownloadUrl } from '../api';
function todayISO(): string {
return new Date().toISOString().slice(0, 10);
}
function monthAgoISO(): string {
const d = new Date();
d.setMonth(d.getMonth() - 1);
return d.toISOString().slice(0, 10);
}
export const ReportPage: React.FC = () => {
const [from, setFrom] = useState(monthAgoISO());
const [to, setTo] = useState(todayISO());
const onDownload = () => {
// Trigger a download in-place via a temporary anchor. Using window.open left
// a blank tab behind (the .xlsx response has no HTML to render). The anchor's
// download attribute makes the browser save the file without navigating away.
// Same-origin, so the session cookie is sent automatically (dev proxy / nginx).
const a = document.createElement('a');
a.href = reportDownloadUrl(from, to);
a.download = `visits_${from}_${to}.xlsx`;
document.body.appendChild(a);
a.click();
a.remove();
};
return (
<div>
<div className="page-head"><h2> </h2></div>
<div className="card">
<p className="muted"> (.xlsx) . ( )</p>
<div className="report-row">
<label className="field">
<span></span>
<input type="date" value={from} onChange={(e) => setFrom(e.target.value)} />
</label>
<label className="field">
<span></span>
<input type="date" value={to} onChange={(e) => setTo(e.target.value)} />
</label>
<button className="btn-primary" onClick={onDownload}> </button>
</div>
</div>
</div>
);
};