import React, { useState, useEffect } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Card, Typography, Button, Space, Modal, Form, Input, DatePicker, Select, Upload, message, Spin, Empty, Image, Tag, Divider, Popconfirm, Row, Col } from 'antd'; import { PlusOutlined, ArrowLeftOutlined, DeleteOutlined, CameraOutlined, CalendarOutlined, CloudOutlined } from '@ant-design/icons'; import axios from 'axios'; import dayjs from 'dayjs'; import { useAuthStore } from '../../store/authStore'; const { Title, Paragraph, Text } = Typography; const { TextArea } = Input; const { Option } = Select; // 天气选项 const WEATHER_OPTIONS = [ { value: 'sunny', label: '☀️ 晴', icon: '☀️' }, { value: 'cloudy', label: '⛅ 多云', icon: '⛅' }, { value: 'rainy', label: '🌧️ 雨', icon: '🌧️' }, { value: 'stormy', label: '⛈️ 雷暴', icon: '⛈️' }, { value: 'windy', label: '💨 大风', icon: '💨' }, ]; interface Log { id: number; log_date: string; weather: string; work_content: string; next_plan: string; issues: string; recorder_name: string; photos: Photo[]; created_at: string; } interface Photo { id: number; photo_url: string; photo_name: string; photo_type: string; file_size: number; created_at: string; } const ConstructionLog: React.FC = () => { const { id: projectId } = useParams<{ id: string }>(); const navigate = useNavigate(); const [isMobile, setIsMobile] = useState(false); const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(true); const [modalVisible, setModalVisible] = useState(false); const [submitting, setSubmitting] = useState(false); const [projectInfo, setProjectInfo] = useState(null); const [form] = Form.useForm(); const { user } = useAuthStore(); useEffect(() => { const checkMobile = () => setIsMobile(window.innerWidth <= 768); checkMobile(); window.addEventListener('resize', checkMobile); return () => window.removeEventListener('resize', checkMobile); }, []); useEffect(() => { if (projectId) { fetchLogs(); fetchProjectInfo(); } }, [projectId]); const fetchLogs = async () => { setLoading(true); try { const res = await axios.get(`/api/projects/${projectId}/construction-logs`); if (res.data.success) { setLogs(res.data.data); } } catch (error) { console.error('获取日志列表失败:', error); message.error('获取日志列表失败'); } finally { setLoading(false); } }; const fetchProjectInfo = async () => { try { const res = await axios.get(`/api/projects/${projectId}`); if (res.data.success) { setProjectInfo(res.data.data); } } catch (error) { console.error('获取项目信息失败:', error); } }; const handleSubmit = async () => { try { const values = await form.validateFields(); setSubmitting(true); const res = await axios.post(`/api/projects/${projectId}/construction-logs`, { log_date: values.log_date.format('YYYY-MM-DD'), weather: values.weather, work_content: values.work_content, photos: '', // 暂时为空,后续添加照片上传功能 }); if (res.data.success) { message.success('日志添加成功'); setModalVisible(false); form.resetFields(); fetchLogs(); } } catch (error) { console.error('添加日志失败:', error); message.error('添加日志失败'); } finally { setSubmitting(false); } }; const handleDeleteLog = async (logId: number) => { try { const res = await axios.delete(`/api/construction-logs/${logId}`); if (res.data.success) { message.success('日志删除成功'); fetchLogs(); } } catch (error) { console.error('删除日志失败:', error); message.error('删除日志失败'); } }; // 按日期分组 const groupedLogs = logs.reduce((acc, log) => { const month = dayjs(log.log_date).format('YYYY年MM月'); if (!acc[month]) { acc[month] = []; } acc[month].push(log); return acc; }, {} as Record); const getWeatherLabel = (value: string) => { const option = WEATHER_OPTIONS.find(o => o.value === value); return option ? option.label : value; }; const formatFileSize = (bytes: number) => { if (bytes < 1024) return bytes + ' B'; if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'; return (bytes / (1024 * 1024)).toFixed(1) + ' MB'; }; const renderLogCard = (log: Log) => ( {/* 日志头部 */}
{dayjs(log.log_date).format('MM月DD日')} {getWeatherLabel(log.weather)} 记录人: {log.recorder_name || '未知'} handleDeleteLog(log.id)} okText="确定" cancelText="取消" >
{/* 工作内容 */} {log.work_content && (
今日工作: {log.work_content}
)} {/* 明日计划 */} {log.next_plan && (
明日计划: {log.next_plan}
)} {/* 问题记录 */} {log.issues && (
问题记录: {log.issues}
)} {/* 照片展示 */} {log.photos && log.photos.length > 0 && (
施工照片 ({log.photos.length}张):
{log.photos.map(photo => (
} /> ))}
)}
); return (
{/* 页面头部 */}
{/* 日志列表 */} {loading ? (
) : logs.length === 0 ? ( ) : (
{Object.entries(groupedLogs).map(([month, monthLogs]) => (
{month} {monthLogs.map(log => renderLogCard(log))}
))}
)} {/* 底部添加按钮 */}
{/* 新增日志弹窗 */} setModalVisible(false)} confirmLoading={submitting} okText="提交" cancelText="取消" width={isMobile ? '95%' : 500} style={{ top: 20 }} >
current && current > dayjs().endOf('day')} />