增加登录显示的页面和修改bug
This commit is contained in:
19
src/App.js
19
src/App.js
@@ -3,6 +3,9 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
|
||||
import { AuthProvider } from './context/AuthContext';
|
||||
import Login from './pages/Login';
|
||||
import ProductDetail from './pages/ProductDetail';
|
||||
import DevGuide from './pages/DevGuide';
|
||||
import Training from './pages/Training';
|
||||
import PrivateRoute from './components/PrivateRoute';
|
||||
import Navbar from './components/Navbar';
|
||||
import Home from './pages/Home';
|
||||
import './App.css';
|
||||
@@ -16,6 +19,22 @@ function App() {
|
||||
<Route path="/login" element={<Login />} />
|
||||
|
||||
<Route path="/product/:series/:sub/:idx" element={<ProductDetail />} />
|
||||
<Route
|
||||
path="/dev"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<DevGuide />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/training"
|
||||
element={
|
||||
<PrivateRoute>
|
||||
<Training />
|
||||
</PrivateRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="/" element={<Home />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
|
||||
@@ -231,23 +231,17 @@ const Navbar = () => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* <div className="nav-item">
|
||||
<span className="nav-label">解决方案</span>
|
||||
<div className="dropdown">
|
||||
<Link to="/" className="dropdown-item">解决方案A</Link>
|
||||
<Link to="/" className="dropdown-item">解决方案B</Link>
|
||||
<Link to="/" className="dropdown-item">解决方案C</Link>
|
||||
{user && (
|
||||
<div className="nav-item">
|
||||
<span className="nav-label" onClick={() => navigate('/dev')}>开发指南</span>
|
||||
</div>
|
||||
</div> */}
|
||||
)}
|
||||
|
||||
{/* <div className="nav-item">
|
||||
<span className="nav-label">行业</span>
|
||||
<div className="dropdown">
|
||||
<Link to="/" className="dropdown-item">民航</Link>
|
||||
<Link to="/" className="dropdown-item">通航</Link>
|
||||
<Link to="/" className="dropdown-item">研发制造</Link>
|
||||
{user && (
|
||||
<div className="nav-item">
|
||||
<span className="nav-label" onClick={() => navigate('/training')}>培训资料</span>
|
||||
</div>
|
||||
</div> */}
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="navbar-right">
|
||||
|
||||
12
src/pages/DevGuide.js
Normal file
12
src/pages/DevGuide.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
const DevGuide = () => {
|
||||
return (
|
||||
<div style={{ maxWidth: 1200, margin: '0 auto', padding: '20px' }}>
|
||||
<h1 style={{ margin: 0, padding: '12px 0', color: '#111' }}>开发指南</h1>
|
||||
<p style={{ color: '#333' }}>API、SDK、示例代码等开发资源的统一入口。</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DevGuide;
|
||||
@@ -34,7 +34,7 @@ const Home = () => {
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setActive((prev) => (prev + 1) % slidesData.length);
|
||||
}, 4000);
|
||||
}, 5000);
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ const Login = () => {
|
||||
|
||||
const result = await login(username, password);
|
||||
|
||||
if (result.success) {
|
||||
navigate('/');
|
||||
} else {
|
||||
setError(result.error);
|
||||
}
|
||||
if (result.success) {
|
||||
navigate('/');
|
||||
} else {
|
||||
setError(result.error);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
@@ -66,7 +66,7 @@ const Login = () => {
|
||||
</button>
|
||||
</form>
|
||||
<div className="login-hint">
|
||||
<p>默认账号:admin / admin123</p>
|
||||
<p>测试账号:admin / admin123</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -50,9 +50,9 @@
|
||||
.pd-panel-body { background: #fff; padding: 12px 0; }
|
||||
.pd-panel.expanded { border: 1px dashed #bfbfbf; border-radius: 6px; }
|
||||
.pd-panel.expanded .pd-panel-header { padding: 12px 14px; border-bottom: none; }
|
||||
.image-row { display: flex; justify-content: center; align-items: center; gap: 40px; padding: 12px; }
|
||||
.image-row { display: flex; justify-content: center; align-items: center; gap: 40px; padding: 12px; background: #f5f5f5; }
|
||||
.image-row img { height: 420px; width: auto; object-fit: contain; display: block; }
|
||||
.size-carousel { position: relative; background: #fff; overflow: hidden; width: 100%; min-height: 420px; border-radius: 0; }
|
||||
.size-carousel { position: relative; background: #f5f5f5; overflow: hidden; width: 100%; min-height: 420px; border-radius: 0; }
|
||||
.size-slides { display: grid; grid-template-columns: 100%; }
|
||||
.size-slide { opacity: 0; transition: opacity 0.3s ease; display: none; }
|
||||
.size-slide.active { opacity: 1; display: block; }
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useParams, useLocation } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
import './ProductDetail.css';
|
||||
|
||||
const ProductDetail = () => {
|
||||
@@ -14,7 +15,7 @@ const ProductDetail = () => {
|
||||
const [specsLoading, setSpecsLoading] = useState(false);
|
||||
const [imgOpen, setImgOpen] = useState(true);
|
||||
const [highlightsOpen, setHighlightsOpen] = useState(false);
|
||||
const [compareOpen, setCompareOpen] = useState(true);
|
||||
const [compareOpen, setCompareOpen] = useState(false);
|
||||
const [promoOpen, setPromoOpen] = useState(false);
|
||||
const [faqOpen, setFaqOpen] = useState(false);
|
||||
const [reviewOpen, setReviewOpen] = useState(false);
|
||||
@@ -56,11 +57,11 @@ const ProductDetail = () => {
|
||||
if (data.data.length && typeof data.data[0]?.title === 'string' && Array.isArray(data.data[0]?.rows)) {
|
||||
setSections(data.data);
|
||||
setSpecs([]);
|
||||
setExpanded(Object.fromEntries(data.data.map((_, i) => [i, true])));
|
||||
setExpanded(Object.fromEntries(data.data.map((_, i) => [i, false])));
|
||||
} else {
|
||||
setSections([{ title: '参数', rows: data.data }]);
|
||||
setSpecs(data.data);
|
||||
setExpanded({ 0: true });
|
||||
setExpanded({ 0: false });
|
||||
}
|
||||
}
|
||||
} catch {}
|
||||
@@ -75,7 +76,7 @@ const ProductDetail = () => {
|
||||
if (images.length <= 1) return;
|
||||
const timer = setInterval(() => {
|
||||
setActive((prev) => (prev + 1) % images.length);
|
||||
}, 4000);
|
||||
}, 5000);
|
||||
return () => clearInterval(timer);
|
||||
}, [images.length]);
|
||||
|
||||
@@ -95,7 +96,7 @@ const ProductDetail = () => {
|
||||
return (
|
||||
<div className="product-detail-page">
|
||||
<div className="container">
|
||||
<div className="pd-title">{product.name}{product.desc ? ` | ${product.desc}` : ''}</div>
|
||||
<div className="pd-title">{product.name}</div>
|
||||
<div className="section-narrow">
|
||||
<div className="pd-list">
|
||||
<button className="pd-list-item" onClick={() => setImgOpen(!imgOpen)}>
|
||||
@@ -228,6 +229,35 @@ const DocsList = ({ series, sub }) => {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
|
||||
const handleDownload = async (d) => {
|
||||
try {
|
||||
const res = await axios.get(d.url, { responseType: 'blob' });
|
||||
const blob = new Blob([res.data], { type: res.data.type || 'application/octet-stream' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = d.name || (String(d.url).split('/').pop() || '下载文件');
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
a.remove();
|
||||
URL.revokeObjectURL(url);
|
||||
} catch (e) {
|
||||
setError('下载失败或文件不存在');
|
||||
}
|
||||
};
|
||||
|
||||
const handleOpen = async (d) => {
|
||||
try {
|
||||
const res = await axios.get(d.url, { responseType: 'blob' });
|
||||
const blob = new Blob([res.data], { type: 'application/pdf' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
window.open(url, '_blank');
|
||||
setTimeout(() => URL.revokeObjectURL(url), 60000);
|
||||
} catch (e) {
|
||||
window.open(d.url, '_blank');
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
const fetchDocs = async () => {
|
||||
try {
|
||||
@@ -259,11 +289,23 @@ const DocsList = ({ series, sub }) => {
|
||||
<ul className="docs-list">
|
||||
{docs.map((d) => (
|
||||
<li key={d.url} className="docs-item">
|
||||
<a href={`${d.url}`} target="_blank" rel="noreferrer" className="docs-link">
|
||||
{d.name}
|
||||
</a>
|
||||
{String(d.url || '').toLowerCase().endsWith('.pdf') ? (
|
||||
<a
|
||||
href={`${d.url}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="docs-link"
|
||||
onClick={(e) => { e.preventDefault(); handleOpen(d); }}
|
||||
>
|
||||
{d.name}
|
||||
</a>
|
||||
) : (
|
||||
<a href={`${d.url}`} target="_blank" rel="noreferrer" className="docs-link">
|
||||
{d.name}
|
||||
</a>
|
||||
)}
|
||||
<span className="docs-size">{(d.size / 1024 / 1024).toFixed(2)}MB</span>
|
||||
<a href={`${d.url}`} download className="docs-download">下载</a>
|
||||
<button type="button" className="docs-download" onClick={() => handleDownload(d)}>下载</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
12
src/pages/Training.js
Normal file
12
src/pages/Training.js
Normal file
@@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
|
||||
const Training = () => {
|
||||
return (
|
||||
<div style={{ maxWidth: 1200, margin: '0 auto', padding: '20px' }}>
|
||||
<h1 style={{ margin: 0, padding: '12px 0', color: '#111' }}>培训资料</h1>
|
||||
<p style={{ color: '#333' }}>课程、教材、视频等培训资源的统一入口。</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Training;
|
||||
Reference in New Issue
Block a user