import React from 'react'; import {Spin} from 'antd'; const ProjectWarningView = ({projects = [], projectsDataRange = [], loading = false, onClick}) => { const warningFields = [ {key: 'new_team', label: '新班组', message: '存在新班组,请做好班组入场管理。'}, {key: 'new_homework_content', label: '新的作业内容', message: '存在新的作业内容,请加强现场管控。'}, { key: 'change_homework_method', label: '改变作业方法', message: '存在改变作业方法,请及时核查施工方案编审、方案交底及人员、机具准备情况。' }, { key: 'changes_geographical', label: '地理环境的变化', message: '存在作业环境的变化,请及时核查施工方案编审、方案交底及人员、机具准备情况。' }, {key: 'changes_meteorological', label: '气象环境的变化', message: '存在气象预警,请关注天气变化,做好应对措施。'}, {key: 'changes_social', label: '社会环境的变化', message: '存在社会环境变化,请合理安排作业计划,避免人员失控。'}, { key: 'changes_management', label: '管理要求的变化', message: '存在管理要求的变化,请加强现场巡查力度,严防无计划作业。' }, {key: 'changes_homework_plan', label: '作业计划的变化', message: '存在作业计划的变化,请做好施工力量配备。'}, {key: 'changes_management_personnel', label: '管理人员的变化', message: '存在管理人员的变化,请加强现场管控。'}, ]; const hasWarnings = (item) => { if (typeof item !== 'object') return false; if (item.new_members || item.new_high_altitude || item.new_hired_general) return true; return warningFields.some(({key}) => item[key]); }; const mismatchWarning = (item) => { if (typeof item !== 'object') return false; if (item.current_status !== '在施') return false; const progressText = item.current_progress || ''; const planText = item.next_week_plan || ''; // 识别当前进度中的“完成数/总数”结构,例如:325.5/620 const extractRates = (text) => { const matches = [...text.matchAll(/(\d+(\.\d+)?)\s*\/\s*(\d+(\.\d+)?)/g)]; return matches.map(match => { const done = parseFloat(match[1]); const total = parseFloat(match[3]); if (!isNaN(done) && !isNaN(total) && total > 0) { return done / total; } return null; }).filter(r => r !== null); }; const progressRates = extractRates(progressText); const hasLowProgress = !progressRates.some(rate => rate > 0.7 && rate != null); // 如果下周计划中包含关键作业,就说明任务已经安排了 const criticalTasks = [ '组塔', '导线展放' ]; const hasHeavyNextPlan = criticalTasks.some(task => planText.includes(task)); // 核心判断逻辑 return hasLowProgress && hasHeavyNextPlan; }; // 转成以项目类型为key的对象,方便查找 const rangeMap = projectsDataRange.reduce((acc, item) => { acc[item.project_type] = {min: item.p5, max: item.p95}; return acc; }, {}); function getRangeByProjectName(projectName) { if (typeof projectName !== 'string') return null; if (projectName.includes('变电工程')) { return rangeMap['变电工程']; } else if (projectName.includes('线路工程')) { return rangeMap['线路工程']; } else { return null; } } const projectsRangeWarning = (item) => { if (typeof item !== 'object') return false; if (item.current_status !== '在施') return false; const range = getRangeByProjectName(item.major_project_name); if (!range) return false; // 未知工程类型,不判断 if (item.participants_count == 0) return false; return !(item.participants_count > range.min && item.participants_count < range.max); } const productionPlanScaleWarning = (item) => { if (typeof item !== 'object') return false; if (item.current_status !== '在施') return false; if (!item.planned_completion_time) return false; const completionDate = new Date(item.planned_completion_time); const now = new Date(); const daysToCompletion = (completionDate - now) / (1000 * 60 * 60 * 24); if (daysToCompletion < 0 || daysToCompletion > 30) return false; // 仅判断“导线展放”类型 const scale = item.project_scale || ''; if (!scale.includes('导线')) return false; // 判断进度是否 < 80% const progressStr = item.current_progress || ''; const progressMatch = progressStr.match(/(\d+(\.\d+)?)%/); if (!progressMatch) return false; const progress = parseFloat(progressMatch[1]); return progress < 80; }; const filteredProjects = projects.filter(item => hasWarnings(item) || mismatchWarning(item) || projectsRangeWarning(item) || productionPlanScaleWarning(item) ); return (
工程预警
{!loading && ( <> {filteredProjects.length > 0 ? (
{filteredProjects.map((item, index) => (
onClick(item)} onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateY(-6px) scale(1.02)'; e.currentTarget.style.boxShadow = '0 12px 24px rgba(0,0,0,0.15)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateY(0) scale(1)'; e.currentTarget.style.boxShadow = '0 6px 15px rgba(0,0,0,0.07)'; }} title={typeof item === 'string' ? item : item.sub_project_name || '未命名项目'} >
{typeof item === 'string' ? item : item.sub_project_name || '未命名项目'}
{(item.new_members || item.new_high_altitude || item.new_hired_general) && (
新人: 存在新人员,请做好人员“面对面”核实。
)} {warningFields.map(({key, label, message}) => item[key] ? (
{label}: {message}
) : null )} {mismatchWarning(item) && (
工程进展与下周作业计划不匹配,请注意。
)} {projectsRangeWarning(item) && (
工程参建人数与作业内容不匹配,请注意。
)} {productionPlanScaleWarning(item) && (
投产计划与当前工程进度不匹配,请注意。
)}
))}
) : (
暂无项目预警
)} )}
); }; export default ProjectWarningView;