import React, { useState, useEffect } from 'react'; import { Card, Typography, Button, Space, Tag, Progress, Empty, Spin, message, Row, Col, Divider } from 'antd'; import { FileTextOutlined, CameraOutlined, ScheduleOutlined, PlusOutlined, ReloadOutlined } from '@ant-design/icons'; import { useNavigate } from 'react-router-dom'; import apiClient from '../../utils/request'; import dayjs from 'dayjs'; import { useAuthStore } from '../../store/authStore'; import { useLanguageStore } from '../../store/languageStore'; const { Title, Paragraph, Text } = Typography; const WEATHER_ICONS: Record = { sunny: '☀️', cloudy: '⛅', rainy: '🌧️', stormy: '⛈️', windy: '💨', }; interface Project { id: number; project_code: string; name: string; customer_name: string; status: string; start_date: string; expected_end_date: string; contract_amount: number; currency: string; manager_name: string; progress_percentage: number; latest_log?: { id: number; log_date: string; weather: string; work_content: string; }; } const ConstructionList: React.FC = () => { const [isMobile, setIsMobile] = useState(false); const [projects, setProjects] = useState([]); const [loading, setLoading] = useState(true); const navigate = useNavigate(); const { user } = useAuthStore(); const { t, currentLanguage } = useLanguageStore(); const STATUS_CONFIG: Record = { pending: { color: 'default', text: t('construction.pendingStart') }, active: { color: 'processing', text: t('construction.underConstruction') }, completed: { color: 'success', text: t('construction.completed') }, suspended: { color: 'warning', text: t('construction.paused') }, cancelled: { color: 'error', text: t('construction.cancelled') }, }; useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth <= 768); checkMobile(); window.addEventListener('resize', checkMobile); return () => window.removeEventListener('resize', checkMobile); }, []); useEffect(() => { fetchProjects(); }, []); const fetchProjects = async () => { setLoading(true); try { const res = await apiClient.get('/construction/my-projects'); if (res.data.success) { setProjects(res.data.data); } } catch (error) { console.error('获取项目列表失败:', error); message.error(t('construction.getListFailed')); } finally { setLoading(false); } }; const formatCurrency = (amount: number, currency: string = 'CNY') => { const symbols: Record = { CNY: '¥', USD: '$', LAK: '₭', THB: '฿', }; const symbol = symbols[currency] || '¥'; return `${symbol}${(amount || 0).toLocaleString('zh-CN', { minimumFractionDigits: 0 })}`; }; const isToday = (dateStr: string) => { return dayjs(dateStr).isSame(dayjs(), 'day'); }; const getWeatherLabel = (weather: string) => { const icon = WEATHER_ICONS[weather] || ''; const textMap: Record = { sunny: t('construction.sunny'), cloudy: t('construction.cloudy'), rainy: t('construction.rain'), stormy: t('construction.thunderstorm'), windy: t('construction.windy'), }; return `${icon} ${textMap[weather] || weather}`; }; const renderProjectCard = (project: Project) => { const statusConfig = STATUS_CONFIG[project.status] || STATUS_CONFIG.pending; const hasTodayLog = project.latest_log && isToday(project.latest_log.log_date); return (
🎯 {project.name}
{t('construction.customerLabel')}{project.customer_name || t('common.notSet')}
{statusConfig.text}
{t('construction.progress')} {Math.round((project.progress_percentage || 0))}%
{project.status === 'active' && (
{hasTodayLog ? ( <> {t('construction.todayLog')}{project.latest_log?.work_content?.substring(0, 30)}... ) : ( <> ⚠️ {t('construction.todayLogEmpty')} )}
)}
); }; return (
{t('construction.management')}
{t('construction.description')}
{loading ? (
{t('common.loading')}
) : projects.length === 0 ? ( {t('construction.contactAdmin')} ) : (
{t('construction.myProjects')} ({projects.length}) {projects.map(project => renderProjectCard(project))}
)}
); }; export default ConstructionList;