236 lines
9.1 KiB
JavaScript
236 lines
9.1 KiB
JavaScript
import React, { useEffect, useState } from 'react';
|
||
import { Row, Col, Typography, Button, Spin } from 'antd';
|
||
import { motion } from 'framer-motion';
|
||
import {
|
||
RightOutlined,
|
||
SearchOutlined,
|
||
DatabaseOutlined,
|
||
ThunderboltOutlined,
|
||
CheckCircleOutlined,
|
||
CloudServerOutlined
|
||
} from '@ant-design/icons';
|
||
import { getServices } from '../api';
|
||
import { useNavigate } from 'react-router-dom';
|
||
|
||
const { Title, Paragraph } = Typography;
|
||
|
||
const AIServices = () => {
|
||
const [services, setServices] = useState([]);
|
||
const [loading, setLoading] = useState(true);
|
||
const navigate = useNavigate();
|
||
|
||
useEffect(() => {
|
||
const fetchServices = async () => {
|
||
try {
|
||
const response = await getServices();
|
||
setServices(response.data);
|
||
} catch (error) {
|
||
console.error("Failed to fetch services:", error);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
fetchServices();
|
||
}, []);
|
||
|
||
if (loading) {
|
||
return (
|
||
<div style={{ textAlign: 'center', padding: '100px 0' }}>
|
||
<Spin size="large" />
|
||
<div style={{ marginTop: 20 }}>Loading services...</div>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
return (
|
||
<div style={{ padding: '20px 0' }}>
|
||
<div style={{ textAlign: 'center', marginBottom: 60 }}>
|
||
<motion.div
|
||
initial={{ scale: 0.8, opacity: 0 }}
|
||
animate={{ scale: 1, opacity: 1 }}
|
||
transition={{ duration: 0.8 }}
|
||
>
|
||
<Title level={1} style={{ color: '#fff', fontSize: 'clamp(2rem, 4vw, 3rem)' }}>
|
||
AI 全栈<span style={{ color: '#00f0ff', textShadow: '0 0 10px rgba(0,240,255,0.5)' }}>解决方案</span>
|
||
</Title>
|
||
</motion.div>
|
||
<Paragraph style={{ color: '#888', maxWidth: 700, margin: '0 auto', fontSize: 16 }}>
|
||
从数据处理到模型部署,我们为您提供一站式 AI 基础设施服务。
|
||
</Paragraph>
|
||
</div>
|
||
|
||
<Row gutter={[32, 32]} justify="center">
|
||
{services.map((item, index) => (
|
||
<Col xs={24} md={8} key={item.id}>
|
||
<motion.div
|
||
initial={{ opacity: 0, x: -50 }}
|
||
animate={{ opacity: 1, x: 0 }}
|
||
transition={{ delay: index * 0.2, duration: 0.5 }}
|
||
whileHover={{ scale: 1.03 }}
|
||
onClick={() => navigate(`/services/${item.id}`)}
|
||
style={{ cursor: 'pointer' }}
|
||
>
|
||
<div
|
||
className="glass-panel"
|
||
style={{
|
||
padding: 30,
|
||
height: '100%',
|
||
position: 'relative',
|
||
overflow: 'hidden',
|
||
border: `1px solid ${item.color}33`,
|
||
boxShadow: `0 0 20px ${item.color}11`
|
||
}}
|
||
>
|
||
{/* HUD 装饰线 */}
|
||
<div style={{ position: 'absolute', top: 0, left: 0, width: 20, height: 2, background: item.color }} />
|
||
<div style={{ position: 'absolute', top: 0, left: 0, width: 2, height: 20, background: item.color }} />
|
||
<div style={{ position: 'absolute', bottom: 0, right: 0, width: 20, height: 2, background: item.color }} />
|
||
<div style={{ position: 'absolute', bottom: 0, right: 0, width: 2, height: 20, background: item.color }} />
|
||
|
||
<div style={{ marginBottom: 20, display: 'flex', alignItems: 'center' }}>
|
||
<div style={{
|
||
width: 60, height: 60,
|
||
borderRadius: '50%',
|
||
background: `${item.color}22`,
|
||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
marginRight: 15,
|
||
overflow: 'hidden'
|
||
}}>
|
||
{item.display_icon ? (
|
||
<img src={item.display_icon} alt={item.title} style={{ width: '60%', height: '60%', objectFit: 'contain' }} />
|
||
) : (
|
||
<div style={{ width: 30, height: 30, background: item.color, borderRadius: '50%' }} />
|
||
)}
|
||
</div>
|
||
<h3 style={{ margin: 0, fontSize: 22, color: '#fff' }}>{item.title}</h3>
|
||
</div>
|
||
|
||
<p style={{ color: '#ccc', lineHeight: 1.6, minHeight: 60 }}>{item.description}</p>
|
||
|
||
<div style={{ marginTop: 20 }}>
|
||
{item.features_list && item.features_list.map((feat, i) => (
|
||
<div key={i} style={{
|
||
display: 'flex', alignItems: 'center', marginBottom: 8, color: item.color
|
||
}}>
|
||
<div style={{ width: 6, height: 6, background: item.color, marginRight: 10, borderRadius: '50%' }} />
|
||
{feat}
|
||
</div>
|
||
))}
|
||
</div>
|
||
|
||
<Button
|
||
type="link"
|
||
style={{ padding: 0, marginTop: 20, color: '#fff' }}
|
||
icon={<RightOutlined />}
|
||
onClick={(e) => {
|
||
e.stopPropagation();
|
||
navigate(`/services/${item.id}`);
|
||
}}
|
||
>
|
||
了解更多
|
||
</Button>
|
||
</div>
|
||
</motion.div>
|
||
</Col>
|
||
))}
|
||
</Row>
|
||
|
||
{/* 动态流程图优化 */}
|
||
<motion.div
|
||
initial={{ opacity: 0 }}
|
||
whileInView={{ opacity: 1 }}
|
||
viewport={{ once: true }}
|
||
transition={{ duration: 1 }}
|
||
style={{
|
||
marginTop: 100,
|
||
padding: '60px 20px',
|
||
background: 'linear-gradient(180deg, rgba(0,0,0,0) 0%, rgba(0,185,107,0.05) 100%)',
|
||
borderRadius: 30,
|
||
border: '1px solid rgba(255,255,255,0.05)',
|
||
position: 'relative',
|
||
overflow: 'hidden'
|
||
}}
|
||
>
|
||
<div style={{ position: 'absolute', top: -50, right: -50, width: 200, height: 200, background: 'radial-gradient(circle, rgba(0,240,255,0.1) 0%, transparent 70%)', filter: 'blur(30px)' }} />
|
||
|
||
<Title level={2} style={{ color: '#fff', marginBottom: 60, textAlign: 'center' }}>
|
||
<span className="neon-text-green">服务流程</span>
|
||
</Title>
|
||
|
||
<Row justify="center" gutter={[0, 40]} style={{ position: 'relative' }}>
|
||
{[
|
||
{ title: '需求分析', icon: <SearchOutlined />, desc: '深度沟通需求' },
|
||
{ title: '数据准备', icon: <DatabaseOutlined />, desc: '高效数据处理' },
|
||
{ title: '模型训练', icon: <ThunderboltOutlined />, desc: '高性能算力' },
|
||
{ title: '测试验证', icon: <CheckCircleOutlined />, desc: '多维精度测试' },
|
||
{ title: '私有化部署', icon: <CloudServerOutlined />, desc: '全栈落地部署' }
|
||
].map((step, i) => (
|
||
<Col key={i} xs={24} sm={12} md={4}>
|
||
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', position: 'relative' }}>
|
||
<motion.div
|
||
initial={{ scale: 0, opacity: 0 }}
|
||
whileInView={{ scale: 1, opacity: 1 }}
|
||
transition={{ delay: i * 0.2, type: 'spring', stiffness: 100 }}
|
||
whileHover={{ y: -10 }}
|
||
style={{
|
||
width: 80,
|
||
height: 80,
|
||
borderRadius: '24px',
|
||
background: 'rgba(255, 255, 255, 0.03)',
|
||
border: '1px solid rgba(0, 185, 107, 0.3)',
|
||
display: 'flex',
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
fontSize: 32,
|
||
color: '#00b96b',
|
||
marginBottom: 20,
|
||
boxShadow: '0 8px 32px rgba(0,0,0,0.4)',
|
||
backdropFilter: 'blur(10px)',
|
||
zIndex: 2
|
||
}}
|
||
>
|
||
{step.icon}
|
||
</motion.div>
|
||
|
||
<motion.div
|
||
initial={{ opacity: 0, y: 10 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: i * 0.2 + 0.3 }}
|
||
>
|
||
<div style={{ color: '#fff', fontSize: 18, fontWeight: 'bold', marginBottom: 8 }}>{step.title}</div>
|
||
<div style={{ color: '#666', fontSize: 12 }}>{step.desc}</div>
|
||
</motion.div>
|
||
|
||
{/* 连接线 */}
|
||
{i < 4 && (
|
||
<div className="process-line" style={{
|
||
position: 'absolute',
|
||
top: 40,
|
||
right: '-50%',
|
||
width: '100%',
|
||
height: '2px',
|
||
background: 'linear-gradient(90deg, #1890ff33, #1890ff00)',
|
||
zIndex: 1,
|
||
display: 'none'
|
||
}} />
|
||
)}
|
||
</div>
|
||
</Col>
|
||
))}
|
||
</Row>
|
||
|
||
<style>{`
|
||
@media (min-width: 768px) {
|
||
.process-line { display: block !important; }
|
||
}
|
||
.neon-text-green {
|
||
text-shadow: 0 0 10px rgba(0, 185, 107, 0.5);
|
||
}
|
||
`}</style>
|
||
</motion.div>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default AIServices;
|