diff --git a/src/App.js b/src/App.js index d232743..9b10bc7 100755 --- a/src/App.js +++ b/src/App.js @@ -1,10 +1,12 @@ import React from 'react'; -import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; +import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import { AuthProvider } from './context/AuthContext'; import Login from './pages/Login'; import AircraftList from './pages/AircraftList'; import AircraftDetail from './pages/AircraftDetail'; import PrivateRoute from './components/PrivateRoute'; +import Navbar from './components/Navbar'; +import Home from './pages/Home'; import './App.css'; function App() { @@ -12,6 +14,7 @@ function App() {
+ } /> } /> - } /> + } />
diff --git a/src/components/Navbar.css b/src/components/Navbar.css new file mode 100755 index 0000000..3ca6e96 --- /dev/null +++ b/src/components/Navbar.css @@ -0,0 +1,90 @@ +.navbar { + background: white; + box-shadow: 0 2px 8px rgba(0,0,0,0.1); + position: sticky; + top: 0; + z-index: 1000; +} + +.navbar-inner { + max-width: 1200px; + margin: 0 auto; + padding: 12px 20px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.logo { + margin-right: 16px; + color: #1890ff; + text-decoration: none; + font-weight: 600; +} + +.navbar-left { + display: flex; + align-items: center; + gap: 8px; +} + +.nav-item { + position: relative; + padding: 8px 10px; +} + +.nav-label { + color: #333; + cursor: default; +} + +.nav-item:hover .dropdown { + display: block; +} + +.dropdown { + display: none; + position: absolute; + top: 36px; + left: 0; + background: white; + border: 1px solid #e8e8e8; + box-shadow: 0 4px 16px rgba(0,0,0,0.1); + border-radius: 6px; + min-width: 160px; + padding: 6px 0; +} + +.dropdown-item { + display: block; + padding: 8px 12px; + color: #333; + text-decoration: none; +} + +.dropdown-item:hover { + background: #f5f5f5; +} + +.navbar-right { + display: flex; + align-items: center; + gap: 12px; +} + +.search-input { + padding: 8px 12px; + border: 1px solid #d9d9d9; + border-radius: 4px; +} + +.user-area { + display: flex; + align-items: center; + gap: 10px; +} + +.username { + color: #666; +} + diff --git a/src/components/Navbar.js b/src/components/Navbar.js new file mode 100755 index 0000000..a09afe0 --- /dev/null +++ b/src/components/Navbar.js @@ -0,0 +1,88 @@ +import React, { useState } from 'react'; +import { useNavigate, Link } from 'react-router-dom'; +import { useAuth } from '../context/AuthContext'; +import './Navbar.css'; + +const Navbar = () => { + const navigate = useNavigate(); + const { user, logout } = useAuth(); + const [search, setSearch] = useState(''); + + const handleLoginClick = () => { + navigate('/login'); + }; + + const handleLogoutClick = () => { + logout(); + navigate('/'); + }; + + const handleSearchKeyDown = (e) => { + if (e.key === 'Enter') { + if (user) { + navigate('/aircraft', { state: { searchTerm: search } }); + } else { + navigate('/login'); + } + } + }; + + return ( + + ); +}; + +export default Navbar; diff --git a/src/pages/AircraftDetail.js b/src/pages/AircraftDetail.js index 3d83928..f0b25d0 100755 --- a/src/pages/AircraftDetail.js +++ b/src/pages/AircraftDetail.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import axios from 'axios'; @@ -13,18 +13,7 @@ const AircraftDetail = () => { const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); - useEffect(() => { - fetchAircraftDetail(); - fetchPdfMaterials(); - }, [id]); - - useEffect(() => { - if (id) { - fetchPdfMaterials(); - } - }, [searchTerm, id]); - - const fetchAircraftDetail = async () => { + const fetchAircraftDetail = useCallback(async () => { try { setLoading(true); const response = await axios.get(`/api/aircraft/${id}`); @@ -40,9 +29,9 @@ const AircraftDetail = () => { } finally { setLoading(false); } - }; + }, [id, logout, navigate]); - const fetchPdfMaterials = async () => { + const fetchPdfMaterials = useCallback(async () => { try { const response = await axios.get(`/api/pdf/aircraft/${id}`, { params: { search: searchTerm } @@ -53,7 +42,20 @@ const AircraftDetail = () => { } catch (error) { console.error('获取PDF资料失败:', error); } - }; + }, [id, searchTerm]); + + useEffect(() => { + fetchAircraftDetail(); + fetchPdfMaterials(); + }, [fetchAircraftDetail, fetchPdfMaterials]); + + useEffect(() => { + if (id) { + fetchPdfMaterials(); + } + }, [id, searchTerm, fetchPdfMaterials]); + + const handleViewPdf = async (materialId) => { try { @@ -90,17 +92,12 @@ const AircraftDetail = () => { return (
-
-
- -

机型详情

+
+
+ +

机型详情

-
- -
{aircraft.code}
diff --git a/src/pages/AircraftList.js b/src/pages/AircraftList.js index b64254a..93bead4 100755 --- a/src/pages/AircraftList.js +++ b/src/pages/AircraftList.js @@ -1,5 +1,5 @@ -import React, { useState, useEffect } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React, { useState, useEffect, useCallback } from 'react'; +import { useNavigate, useLocation } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import axios from 'axios'; import './AircraftList.css'; @@ -7,15 +7,13 @@ import './AircraftList.css'; const AircraftList = () => { const [aircrafts, setAircrafts] = useState([]); const [loading, setLoading] = useState(true); - const [searchTerm, setSearchTerm] = useState(''); - const { user, logout } = useAuth(); + const location = useLocation(); + const initialSearch = location.state?.searchTerm || ''; + const [searchTerm, setSearchTerm] = useState(initialSearch); + const { logout } = useAuth(); const navigate = useNavigate(); - useEffect(() => { - fetchAircrafts(); - }, [searchTerm]); - - const fetchAircrafts = async () => { + const fetchAircrafts = useCallback(async () => { try { setLoading(true); const response = await axios.get('/api/aircraft/list', { @@ -33,7 +31,11 @@ const AircraftList = () => { } finally { setLoading(false); } - }; + }, [searchTerm, logout, navigate]); + + useEffect(() => { + fetchAircrafts(); + }, [fetchAircrafts]); const handleAircraftClick = (id) => { navigate(`/aircraft/${id}`); @@ -41,19 +43,8 @@ const AircraftList = () => { return (
-
-
-

机型信息管理系统

-
- 欢迎,{user?.name || user?.username} - -
-
-
-
+

机型信息管理系统

{ + const [active, setActive] = useState(0); + + useEffect(() => { + const timer = setInterval(() => { + setActive((prev) => (prev + 1) % slidesData.length); + }, 4000); + return () => clearInterval(timer); + }, []); + + const prevSlide = () => { + setActive((prev) => (prev - 1 + slidesData.length) % slidesData.length); + }; + + const nextSlide = () => { + setActive((prev) => (prev + 1) % slidesData.length); + }; + + return ( +
+
+
+

机型信息平台

+

欢迎访问主页,无需登录即可浏览导航与新闻

+
+ +
+ + +
+ {slidesData.map((s, idx) => ( +
+
+

{s.title}

+

{s.description}

+
+
+ ))} +
+ + + +
+ {slidesData.map((_, idx) => ( + setActive(idx)} + /> + ))} +
+
+
+
+ ); +}; + +export default Home;