创赢未来评分系统 - 初始化提交(移除大文件)

This commit is contained in:
爽哒哒
2026-03-18 22:28:45 +08:00
commit f26d35da66
315 changed files with 36043 additions and 0 deletions

View File

@@ -0,0 +1,283 @@
import React, { useEffect, useState } from 'react';
import { useParams, useNavigate, useSearchParams, useLocation } from 'react-router-dom';
import { Typography, Button, Spin, Empty, Descriptions, Tag, Row, Col, Modal, Form, Input, message, Statistic } from 'antd';
import { ArrowLeftOutlined, ClockCircleOutlined, GiftOutlined, ShoppingCartOutlined } from '@ant-design/icons';
import { getServiceDetail, createServiceOrder } from '../api';
import { useAuth } from '../context/AuthContext';
import { motion } from 'framer-motion';
const { Title, Paragraph } = Typography;
const ServiceDetail = () => {
const { id } = useParams();
const navigate = useNavigate();
const location = useLocation();
const [searchParams] = useSearchParams();
const { user, showLoginModal } = useAuth();
const [service, setService] = useState(null);
const [loading, setLoading] = useState(true);
const [isModalOpen, setIsModalOpen] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [form] = Form.useForm();
// 优先从 URL 获取,如果没有则从 localStorage 获取
const refCode = searchParams.get('ref') || localStorage.getItem('ref_code');
useEffect(() => {
console.log('[ServiceDetail] Current ref_code:', refCode);
}, [refCode]);
useEffect(() => {
const fetchDetail = async () => {
try {
const response = await getServiceDetail(id);
setService(response.data);
} catch (error) {
console.error("Failed to fetch service detail:", error);
} finally {
setLoading(false);
}
};
fetchDetail();
}, [id]);
useEffect(() => {
if (isModalOpen && user && user.phone_number) {
form.setFieldsValue({
phone_number: user.phone_number
});
}
}, [isModalOpen, user, form]);
const handlePurchase = async (values) => {
setSubmitting(true);
try {
const orderData = {
service: service.id,
customer_name: values.customer_name,
company_name: values.company_name,
phone_number: values.phone_number,
email: values.email,
requirements: values.requirements,
ref_code: refCode
};
await createServiceOrder(orderData);
message.success('需求已提交,我们的销售顾问将尽快与您联系!');
setIsModalOpen(false);
} catch (error) {
console.error(error);
message.error('提交失败,请重试');
} finally {
setSubmitting(false);
}
};
if (loading) {
return (
<div style={{ textAlign: 'center', padding: '100px 0' }}>
<Spin size="large" />
<div style={{ marginTop: 20 }}>Loading...</div>
</div>
);
}
if (!service) {
return (
<div style={{ textAlign: 'center', padding: '100px 0' }}>
<Empty description="Service not found" />
<Button type="primary" onClick={() => navigate('/services')} style={{ marginTop: 20 }}>
Return to Services
</Button>
</div>
);
}
return (
<div style={{ padding: '20px 0' }}>
<Button
type="text"
icon={<ArrowLeftOutlined />}
style={{ color: '#fff', marginBottom: 20 }}
onClick={() => navigate('/services')}
>
返回服务列表
</Button>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<Row gutter={[40, 40]}>
<Col xs={24} md={16}>
<div style={{ textAlign: 'left', marginBottom: 40 }}>
<Title level={1} style={{ color: '#fff' }}>
{service.title}
</Title>
<Paragraph style={{ color: '#888', fontSize: 18 }}>
{service.description}
</Paragraph>
<div style={{
marginTop: 30,
background: 'rgba(255,255,255,0.03)',
padding: '24px',
borderRadius: 16,
border: '1px solid rgba(255,255,255,0.08)',
backdropFilter: 'blur(10px)',
boxShadow: '0 8px 32px rgba(0,0,0,0.2)'
}}>
<Title level={4} style={{ color: '#fff', marginBottom: 20, display: 'flex', alignItems: 'center' }}>
<div style={{ width: 4, height: 18, background: service.color, marginRight: 10, borderRadius: 2 }} />
服务详情
</Title>
<Descriptions
column={1}
labelStyle={{ color: '#888', fontWeight: 'normal' }}
contentStyle={{ color: '#fff', fontWeight: '500' }}
>
<Descriptions.Item label={<span style={{ display: 'flex', alignItems: 'center' }}><ClockCircleOutlined style={{ marginRight: 8, color: service.color }} /> 交付周期</span>}>
{service.delivery_time || '待沟通'}
</Descriptions.Item>
<Descriptions.Item label={<span style={{ display: 'flex', alignItems: 'center' }}><GiftOutlined style={{ marginRight: 8, color: service.color }} /> 交付内容</span>}>
{service.delivery_content || '根据需求定制'}
</Descriptions.Item>
</Descriptions>
</div>
</div>
{service.display_detail_image ? (
<div style={{
width: '100%',
maxWidth: '900px',
margin: '0 auto',
background: '#111',
borderRadius: 12,
overflow: 'hidden',
boxShadow: `0 10px 40px ${service.color}22`,
border: `1px solid ${service.color}33`
}}>
<img
src={service.display_detail_image}
alt={service.title}
style={{ width: '100%', display: 'block', height: 'auto' }}
/>
</div>
) : (
<div style={{ textAlign: 'center', padding: 100, background: '#111', borderRadius: 12, color: '#666' }}>
暂无详情图片
</div>
)}
</Col>
<Col xs={24} md={8}>
<div style={{ position: 'sticky', top: 100 }}>
<div style={{
background: '#1f1f1f',
padding: 30,
borderRadius: 16,
border: `1px solid ${service.color}44`,
boxShadow: `0 0 20px ${service.color}11`
}}>
<Title level={3} style={{ color: '#fff', marginTop: 0 }}>服务报价</Title>
<div style={{ display: 'flex', alignItems: 'baseline', marginBottom: 20 }}>
<span style={{ fontSize: 36, color: service.color, fontWeight: 'bold' }}>¥{service.price}</span>
<span style={{ color: '#888', marginLeft: 8 }}>/ {service.unit} </span>
</div>
<div style={{ marginBottom: 25, display: 'flex', flexWrap: 'wrap', gap: '10px' }}>
{service.features_list && service.features_list.map((feat, i) => (
<Tag
key={i}
style={{
margin: 0,
padding: '4px 12px',
background: `${service.color}11`,
color: service.color,
border: `1px solid ${service.color}66`,
borderRadius: '6px',
fontSize: '14px',
backdropFilter: 'blur(4px)',
whiteSpace: 'normal',
height: 'auto',
textAlign: 'left'
}}
>
{feat}
</Tag>
))}
</div>
<Button
type="primary"
size="large"
block
icon={<ShoppingCartOutlined />}
style={{
height: 50,
background: service.color,
borderColor: service.color,
color: '#000',
fontWeight: 'bold'
}}
onClick={() => {
if (!user) {
message.info('请先登录后再进行咨询');
showLoginModal();
return;
}
setIsModalOpen(true);
}}
>
立即咨询 / 购买
</Button>
<p style={{ color: '#666', marginTop: 15, fontSize: 12, textAlign: 'center' }}>
* 具体价格可能因需求复杂度而异提交需求后我们将提供详细报价单
</p>
</div>
</div>
</Col>
</Row>
</motion.div>
{/* Purchase Modal */}
<Modal
title={`咨询/购买 - ${service.title}`}
open={isModalOpen}
onCancel={() => setIsModalOpen(false)}
footer={null}
destroyOnHidden
>
<p style={{ marginBottom: 20, color: '#666' }}>请填写您的联系方式和需求我们的技术顾问将在 24 小时内与您联系</p>
<Form
form={form}
layout="vertical"
onFinish={handlePurchase}
>
<Form.Item label="您的姓名" name="customer_name" rules={[{ required: true, message: '请输入姓名' }]}>
<Input placeholder="例如:张经理" />
</Form.Item>
<Form.Item label="公司/机构名称" name="company_name">
<Input placeholder="例如:某某科技有限公司" />
</Form.Item>
<Form.Item label="联系电话" name="phone_number" rules={[{ required: true, message: '请输入电话' }]}>
<Input placeholder="13800000000" />
</Form.Item>
<Form.Item label="电子邮箱" name="email" rules={[{ type: 'email' }]}>
<Input placeholder="example@company.com" />
</Form.Item>
<Form.Item label="需求描述" name="requirements">
<Input.TextArea rows={4} placeholder="请简单描述您的业务场景或具体需求..." />
</Form.Item>
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 10, marginTop: 20 }}>
<Button onClick={() => setIsModalOpen(false)}>取消</Button>
<Button type="primary" htmlType="submit" loading={submitting}>提交需求</Button>
</div>
</Form>
</Modal>
</div>
);
};
export default ServiceDetail;