vb
This commit is contained in:
@@ -6,7 +6,7 @@ import ProductDetail from './pages/ProductDetail';
|
||||
import Payment from './pages/Payment';
|
||||
import AIServices from './pages/AIServices';
|
||||
import ServiceDetail from './pages/ServiceDetail';
|
||||
import ARExperience from './pages/ARExperience';
|
||||
import VBCourses from './pages/VBCourses';
|
||||
import MyOrders from './pages/MyOrders';
|
||||
import 'antd/dist/reset.css';
|
||||
import './App.css';
|
||||
@@ -19,7 +19,7 @@ function App() {
|
||||
<Route path="/" element={<Home />} />
|
||||
<Route path="/services" element={<AIServices />} />
|
||||
<Route path="/services/:id" element={<ServiceDetail />} />
|
||||
<Route path="/ar" element={<ARExperience />} />
|
||||
<Route path="/courses" element={<VBCourses />} />
|
||||
<Route path="/my-orders" element={<MyOrders />} />
|
||||
<Route path="/product/:id" element={<ProductDetail />} />
|
||||
<Route path="/payment/:orderId" element={<Payment />} />
|
||||
|
||||
@@ -19,7 +19,7 @@ export const confirmPayment = (orderId) => api.post(`/orders/${orderId}/confirm_
|
||||
export const getServices = () => api.get('/services/');
|
||||
export const getServiceDetail = (id) => api.get(`/services/${id}/`);
|
||||
export const createServiceOrder = (data) => api.post('/service-orders/', data);
|
||||
export const getARServices = () => api.get('/ar/');
|
||||
export const getVBCourses = () => api.get('/courses/');
|
||||
|
||||
export const sendSms = (data) => api.post('/auth/send-sms/', data);
|
||||
export const queryMyOrders = (data) => api.post('/orders/my_orders/', data);
|
||||
|
||||
@@ -34,9 +34,9 @@ const Layout = ({ children }) => {
|
||||
label: 'AI 服务',
|
||||
},
|
||||
{
|
||||
key: '/ar',
|
||||
key: '/courses',
|
||||
icon: <EyeOutlined />,
|
||||
label: 'AR 体验',
|
||||
label: 'VB 课程',
|
||||
},
|
||||
{
|
||||
key: '/my-orders',
|
||||
|
||||
@@ -1,28 +1,27 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Button, Typography, Spin, Row, Col, Empty } from 'antd';
|
||||
import { ScanOutlined } from '@ant-design/icons';
|
||||
import { getARServices } from '../api';
|
||||
import { Button, Typography, Spin, Row, Col, Empty, Tag } from 'antd';
|
||||
import { ReadOutlined, ClockCircleOutlined, UserOutlined, BookOutlined } from '@ant-design/icons';
|
||||
import { getVBCourses } from '../api';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
const ARExperience = () => {
|
||||
const [scanning, setScanning] = useState(true);
|
||||
const [arServices, setArServices] = useState([]);
|
||||
const VBCourses = () => {
|
||||
const [courses, setCourses] = useState([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchAR = async () => {
|
||||
const fetchCourses = async () => {
|
||||
try {
|
||||
const res = await getARServices();
|
||||
setArServices(res.data);
|
||||
const res = await getVBCourses();
|
||||
setCourses(res.data);
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch AR services:", error);
|
||||
console.error("Failed to fetch VB Courses:", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
fetchAR();
|
||||
fetchCourses();
|
||||
}, []);
|
||||
|
||||
if (loading) return <div style={{ textAlign: 'center', padding: 100 }}><Spin size="large" /></div>;
|
||||
@@ -31,20 +30,20 @@ const ARExperience = () => {
|
||||
<div style={{ padding: '40px 0', minHeight: '80vh', position: 'relative' }}>
|
||||
<div style={{ textAlign: 'center', marginBottom: 60, position: 'relative', zIndex: 2 }}>
|
||||
<Title level={1} style={{ color: '#fff', letterSpacing: 4 }}>
|
||||
AR <span style={{ color: '#00f0ff' }}>UNIVERSE</span>
|
||||
VB <span style={{ color: '#00f0ff' }}>CODING COURSES</span>
|
||||
</Title>
|
||||
<Paragraph style={{ color: '#aaa', fontSize: 18, maxWidth: 600, margin: '0 auto' }}>
|
||||
探索全息增强现实体验。请佩戴您的设备,或使用移动端摄像头扫描空间。
|
||||
探索 Vibe Coding 软件与硬件课程,开启您的编程之旅。
|
||||
</Paragraph>
|
||||
</div>
|
||||
|
||||
{arServices.length === 0 ? (
|
||||
{courses.length === 0 ? (
|
||||
<div style={{ textAlign: 'center', marginTop: 100, zIndex: 2, position: 'relative' }}>
|
||||
<Empty description={<span style={{ color: '#666' }}>暂无 AR 体验内容</span>} />
|
||||
<Empty description={<span style={{ color: '#666' }}>暂无课程内容</span>} />
|
||||
</div>
|
||||
) : (
|
||||
<Row gutter={[32, 32]} justify="center" style={{ padding: '0 20px', position: 'relative', zIndex: 2 }}>
|
||||
{arServices.map((item, index) => (
|
||||
{courses.map((item, index) => (
|
||||
<Col xs={24} md={12} lg={8} key={item.id}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 30 }}
|
||||
@@ -57,20 +56,35 @@ const ARExperience = () => {
|
||||
border: '1px solid rgba(0,240,255,0.2)',
|
||||
borderRadius: 12,
|
||||
overflow: 'hidden',
|
||||
height: '100%'
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<div style={{ height: 200, background: '#000', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<div style={{ height: 200, background: '#000', overflow: 'hidden', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
|
||||
{item.display_cover_image ? (
|
||||
<img src={item.display_cover_image} alt={item.title} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
|
||||
) : (
|
||||
<ScanOutlined style={{ fontSize: 40, color: '#333' }} />
|
||||
<ReadOutlined style={{ fontSize: 40, color: '#333' }} />
|
||||
)}
|
||||
<div style={{ position: 'absolute', top: 10, right: 10, display: 'flex', gap: '5px' }}>
|
||||
{item.tag && (
|
||||
<Tag color="volcano" style={{ marginRight: 0 }}>{item.tag}</Tag>
|
||||
)}
|
||||
<Tag color={item.course_type === 'hardware' ? 'purple' : 'cyan'}>
|
||||
{item.course_type_display || (item.course_type === 'hardware' ? '硬件课程' : '软件课程')}
|
||||
</Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ padding: 20 }}>
|
||||
<h3 style={{ color: '#fff', fontSize: 20 }}>{item.title}</h3>
|
||||
<p style={{ color: '#888', marginBottom: 20, minHeight: 44 }}>{item.description}</p>
|
||||
<div style={{ padding: 20, flex: 1, display: 'flex', flexDirection: 'column' }}>
|
||||
<h3 style={{ color: '#fff', fontSize: 20, marginBottom: 10 }}>{item.title}</h3>
|
||||
<div style={{ color: '#888', marginBottom: 15, fontSize: 14 }}>
|
||||
<span style={{ marginRight: 15 }}><UserOutlined /> {item.instructor}</span>
|
||||
<span style={{ marginRight: 15 }}><ClockCircleOutlined /> {item.duration}</span>
|
||||
<span><BookOutlined /> {item.lesson_count} 课时</span>
|
||||
</div>
|
||||
<p style={{ color: '#aaa', marginBottom: 20, flex: 1 }}>{item.description}</p>
|
||||
<Button type="primary" block ghost style={{ borderColor: '#00f0ff', color: '#00f0ff' }}>
|
||||
启动体验
|
||||
开始学习
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -108,4 +122,4 @@ const ARExperience = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export default ARExperience;
|
||||
export default VBCourses;
|
||||
Reference in New Issue
Block a user