Notice
Recent Posts
Recent Comments
Link
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- dfs
- BFS
- docker
- typescript
- DP
- CI/CD
- Flask
- Infra
- 알고리즘
- rag
- VectoreStore
- monorepo
- javascirpt
- 파이썬
- React
- javascript
- LLM
- jenkins
- 프로그래머스
- build
- queue
- python
- Algorithm
- frontend
- modbus
- ansible
- turbo
- RDP
- Two Pointer
- AI
Archives
- Today
- Total
DM Log
[RDP 모니터링 프로젝트 #6] 운영 서버 - React 영상 재생 UI 구축 본문
개요
운영 서버에서 제공하는 flask API를 활용하여 React 환경에서 영상 조회 UI를 구축
- 서버 목록 조회
- 날짜 목록 조회
- 영상 파일 목록 조회
- 영상 재생 기능
초기 환경 구성 (CRA)
- React TypeScript 프로젝트 생성
npx create-react-app frontend --template typescript
cd frontend
npm install axios react-router-dom
- 폴더 구조
src/
├── api/
│ └── rdp.ts
├── components/
│ ├── ServerSelect.tsx
│ ├── DateSelect.tsx
│ ├── FileList.tsx
│ └── VideoPlayer.tsx
├── pages/
│ └── RdpPage.tsx
├── App.tsx
└── index.tsx
Conponent 및 Utill 환경 구성
- Page 생성 - src/pages/RdpPage.tsx
import React, { useEffect, useState } from "react";
import { fetchServers, fetchDates, fetchFileList } from "../api/rdp";
import ServerSelect from "../components/ServerSelect";
import DateSelect from "../components/DateSelect";
import FileList from "../components/FileList";
import VideoPlayer from "../components/VideoPlayer";
export default function RdpPage() {
const [servers, setServers] = useState<any[]>([]);
const [selectedServer, setSelectedServer] = useState("");
const [dates, setDates] = useState<string[]>([]);
const [files, setFiles] = useState<any[]>([]);
const [selectedFile, setSelectedFile] = useState<any>(null);
useEffect(() => {
fetchServers().then(setServers);
}, []);
const handleServer = (serverName: string) => {
setSelectedServer(serverName);
setSelectedFile(null);
fetchDates(serverName).then(setDates);
};
const handleDate = (date: string) => {
fetchFileList(selectedServer, date).then(setFiles);
};
return (
<div style={{ padding: 20 }}>
<h2>RDP 영상 재생</h2>
<ServerSelect servers={servers} onSelect={handleServer} />
<DateSelect dates={dates} onSelect={handleDate} />
<FileList files={files} onSelect={setSelectedFile} />
<VideoPlayer filepath={selectedFile?.filepath} />
</div>
);
}
- 라우팅 기반 App.tsx 생성 - src/App.tsx
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import RdpPage from "./pages/RdpPage";
export default function App() {
return (
<Router>
<Routes>
<Route path="/" element={<div>메인 페이지</div>} />
<Route path="/rdp" element={<RdpPage />} />
</Routes>
</Router>
);
}
- API통신 모듈 - src/api/rdp.ts
import axios from "axios";
export const API_BASE = "http://운영서버IP:5001/rdp";
export const fetchServers = async () => {
const res = await axios.get(`${API_BASE}/servers`);
return res.data;
};
export const fetchDates = async (server: string) => {
const res = await axios.get(`${API_BASE}/dates`, {
params: { server },
});
return res.data;
};
export const fetchFileList = async (server: string, date: string) => {
const res = await axios.get(`${API_BASE}/list`, {
params: { server, date },
});
return res.data;
};
- 서버 선택 UI - src/components/ServerSelect.tsx
interface Props {
servers: any[];
onSelect: (server: string) => void;
}
export default function ServerSelect({ servers, onSelect }: Props) {
return (
<div>
<h3>서버 선택</h3>
<select onChange={(e) => onSelect(e.target.value)}>
<option value="">선택하세요</option>
{servers.map((s) => (
<option key={s.name} value={s.name}>
{s.name} ({s.ip})
</option>
))}
</select>
</div>
);
}
- 날짜 선택 UI - src/components/DateSelect.tsx
interface Props {
dates: string[];
onSelect: (date: string) => void;
}
export default function DateSelect({ dates, onSelect }: Props) {
return (
<div>
<h3>날짜 선택</h3>
<select onChange={(e) => onSelect(e.target.value)}>
<option value="">선택하세요</option>
{dates.map((d) => (
<option key={d}>{d}</option>
))}
</select>
</div>
);
}
- 영상 파일 목록 UI - src/components/FileList.tsx
interface Props {
files: any[];
onSelect: (file: any) => void;
}
export default function FileList({ files, onSelect }: Props) {
return (
<div>
<h3>영상 파일 목록</h3>
<ul>
{files.map((f) => (
<li
key={f.id}
onClick={() => onSelect(f)}
style={{ cursor: "pointer" }}
>
{f.filename}
{f.uploaded === 0 && (
<span style={{ color: "red" }}> (전송 전)</span>
)}
</li>
))}
</ul>
</div>
);
}
- 영상 재생 UI - src/components/VideoPlayer.tsx
interface Props {
filepath: string;
}
export default function VideoPlayer({ filepath }: Props) {
if (!filepath) return null;
return (
<div>
<h3>영상 재생</h3>
<video
src={`http://운영서버IP:5001/rdp/video/${filepath}`}
controls
style={{ width: "100%", maxWidth: "800px" }}
/>
</div>
);
}'PJT > 영상 파일 재생 PJT' 카테고리의 다른 글
| [RDP 모니터링 프로젝트 #5] 운영 서버 - Flask API & SQLite 메타데이터 저장 (0) | 2025.11.30 |
|---|---|
| [RDP 모니터링 프로젝트 #4] Window Scheduler + SFTP 자동 전송 시스템 구축 (0) | 2025.11.30 |
| [RDP 모니터링 프로젝트 #3] 다중 RDP 접속 대응 및 세션별 PID 관리 전략 (0) | 2025.11.30 |
| [RDP 모니터링 프로젝트 #2] ffmpeg 기반 화면 녹화 Batch 스크립트 구현 (0) | 2025.11.30 |
| [RDP 모니터링 프로젝트 #1] Window Server - RDP 접속 이벤트 기반 녹화 구조 설계 (0) | 2025.11.30 |
