// 项目管理分析页面 let expenditureTrendChart = null; let expenditureProportionChart = null; let projectRiskChart = null; let riskAnalysisChart = null; let civilSpecialtyChart = null; let electricalSpecialtyChart = null; // 页面初始化 $(document).ready(function () { // 等待layui加载完成 layui.use(['laydate', 'layer'], function () { initDateRange(); // 初始化项目信息模块的图表 initRiskAnalysisChart(); initCivilSpecialtyChart(); initElectricalSpecialtyChart(); // 初始化其他模块的图表 initExpenditureTrendChart(); initExpenditureProportionChart(); initProjectRiskChart(); initWarningTable(); // 窗口大小改变时重新调整图表 window.addEventListener('resize', debounce(() => { if (riskAnalysisChart) riskAnalysisChart.resize(); if (civilSpecialtyChart) civilSpecialtyChart.resize(); if (electricalSpecialtyChart) electricalSpecialtyChart.resize(); if (expenditureTrendChart) expenditureTrendChart.resize(); if (expenditureProportionChart) expenditureProportionChart.resize(); if (projectRiskChart) projectRiskChart.resize(); }, 300)); }); }); // 防抖函数 function debounce(fn, delay) { let t = null; return function () { clearTimeout(t); t = setTimeout(() => fn.apply(this, arguments), delay); }; } // 初始化日期范围选择器 function initDateRange() { const laydate = layui.laydate; laydate.render({ elem: '#dateRange', type: 'date', range: true, format: 'yyyy-MM-dd', value: getDefaultDateRange(), done: function (value) { // 日期选择完成后的回调 } }); } // 获取默认日期范围(最近7天) function getDefaultDateRange() { const end = new Date(); const start = new Date(); start.setDate(start.getDate() - 6); return formatDate(start) + ' ~ ' + formatDate(end); } // 格式化日期 function formatDate(date) { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return year + '-' + month + '-' + day; } // 查询数据 function queryData() { const dateRange = $('#dateRange').val(); if (!dateRange) { layui.layer.msg('请选择日期范围', { icon: 0 }); return; } // 这里可以调用API获取数据 // 目前使用模拟数据 loadData(dateRange); layui.layer.msg('查询成功', { icon: 1, time: 1000 }); } // 加载数据 function loadData(dateRange) { // 模拟数据加载 // 实际应该调用API updateCharts(); } // 初始化风险分析饼图 function initRiskAnalysisChart() { riskAnalysisChart = echarts.init(document.getElementById('riskAnalysisChart')); const option = { tooltip: { trigger: 'item', backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' }, formatter: '{b}: {c}个 ({d}%)' }, legend: { orient: 'vertical', right: 10, top: 'center', textStyle: { color: '#fff', fontSize: 12 }, itemWidth: 12, itemHeight: 8, itemGap: 10, formatter: function(name) { const item = option.series[0].data.find(d => d.name === name); return name + ' ' + (item ? item.value + '%' : ''); } }, series: [ { name: '风险分析', type: 'pie', radius: ['40%', '70%'], center: ['35%', '50%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 5, borderColor: 'rgba(13, 34, 37, 0.8)', borderWidth: 2 }, label: { show: false }, emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold', color: '#fff' } }, data: [ { value: 36, name: '二级风险', itemStyle: { color: '#4A90E2' } }, { value: 36, name: '三级风险', itemStyle: { color: '#1CFFA3' } }, { value: 15.6, name: '四级风险', itemStyle: { color: '#00FEFC' } }, { value: 8.4, name: '五级风险', itemStyle: { color: '#FF9C65' } } ] } ], graphic: [ { type: 'text', left: '35%', top: '75%', style: { text: '今日风险数量 60个', textAlign: 'center', fill: '#fff', fontSize: 13 } } ] }; riskAnalysisChart.setOption(option); } // 初始化土建专业折线图 function initCivilSpecialtyChart() { civilSpecialtyChart = echarts.init(document.getElementById('civilSpecialtyChart')); const dates = ['XXXX-XX-01', 'XXXX-XX-02', 'XXXX-XX-03', 'XXXX-XX-04', 'XXXX-XX-05', 'XXXX-XX-06', 'XXXX-XX-07', 'XXXX-XX-08']; const planned = [8, 9, 10, 12, 11, 13, 12, 14]; const actual = [6, 7, 8, 6, 9, 10, 11, 12]; const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'line' }, backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' }, formatter: function (params) { if (!params || !params.length) return ''; let html = `
${params[0].name}
`; params.forEach(p => { html += `
${p.seriesName} ${p.value}
`; }); return html; } }, legend: { data: ['计划', '实际'], top: 8, right: 20, textStyle: { color: '#fff', fontSize: 12 }, itemWidth: 12, itemHeight: 8, itemGap: 15 }, grid: { top: '20%', left: '8%', right: '6%', bottom: '15%' }, xAxis: { type: 'category', data: dates, axisLabel: { color: '#fff', fontSize: 10 }, axisLine: { lineStyle: { color: '#5A6E71' } }, axisTick: { show: false } }, yAxis: { type: 'value', min: 0, max: 20, axisLabel: { color: '#fff', fontSize: 10 }, axisLine: { lineStyle: { color: '#5A6E71' } }, splitLine: { lineStyle: { color: 'rgba(90, 110, 113, 0.3)', type: 'dashed' } } }, series: [ { name: '计划', type: 'line', data: planned, smooth: true, lineStyle: { width: 2, color: '#00FEFC' }, itemStyle: { color: '#00FEFC' }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(0, 254, 252, 0.3)' }, { offset: 1, color: 'rgba(0, 254, 252, 0.05)' } ]) } }, { name: '实际', type: 'line', data: actual, smooth: true, lineStyle: { width: 2, color: '#1CFFA3' }, itemStyle: { color: '#1CFFA3' }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(28, 255, 163, 0.3)' }, { offset: 1, color: 'rgba(28, 255, 163, 0.05)' } ]) } } ] }; civilSpecialtyChart.setOption(option); } // 初始化电气专业折线图 function initElectricalSpecialtyChart() { electricalSpecialtyChart = echarts.init(document.getElementById('electricalSpecialtyChart')); const dates = ['XXXX-XX-01', 'XXXX-XX-02', 'XXXX-XX-03', 'XXXX-XX-04', 'XXXX-XX-05', 'XXXX-XX-06', 'XXXX-XX-07', 'XXXX-XX-08']; const planned = [8, 9, 10, 12, 11, 13, 12, 14]; const actual = [6, 7, 8, 6, 9, 10, 11, 12]; const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'line' }, backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' }, formatter: function (params) { if (!params || !params.length) return ''; let html = `
${params[0].name}
`; params.forEach(p => { html += `
${p.seriesName} ${p.value}
`; }); return html; } }, legend: { data: ['计划', '实际'], top: 8, right: 20, textStyle: { color: '#fff', fontSize: 12 }, itemWidth: 12, itemHeight: 8, itemGap: 15 }, grid: { top: '20%', left: '8%', right: '6%', bottom: '15%' }, xAxis: { type: 'category', data: dates, axisLabel: { color: '#fff', fontSize: 10 }, axisLine: { lineStyle: { color: '#5A6E71' } }, axisTick: { show: false } }, yAxis: { type: 'value', min: 0, max: 20, axisLabel: { color: '#fff', fontSize: 10 }, axisLine: { lineStyle: { color: '#5A6E71' } }, splitLine: { lineStyle: { color: 'rgba(90, 110, 113, 0.3)', type: 'dashed' } } }, series: [ { name: '计划', type: 'line', data: planned, smooth: true, lineStyle: { width: 2, color: '#00FEFC' }, itemStyle: { color: '#00FEFC' }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(0, 254, 252, 0.3)' }, { offset: 1, color: 'rgba(0, 254, 252, 0.05)' } ]) } }, { name: '实际', type: 'line', data: actual, smooth: true, lineStyle: { width: 2, color: '#1CFFA3' }, itemStyle: { color: '#1CFFA3' }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(28, 255, 163, 0.3)' }, { offset: 1, color: 'rgba(28, 255, 163, 0.05)' } ]) } } ] }; electricalSpecialtyChart.setOption(option); } // 初始化项目支出趋势图表 function initExpenditureTrendChart() { expenditureTrendChart = echarts.init(document.getElementById('expenditureTrendChart')); const dates = ['XXXX-XX-01', 'XXXX-XX-02', 'XXXX-XX-03', 'XXXX-XX-04', 'XXXX-XX-05', 'XXXX-XX-06', 'XXXX-XX-07', 'XXXX-XX-08']; const expenditure = [48, 45, 42, 32, 35, 38, 30, 28]; const option = { tooltip: { trigger: 'axis', axisPointer: { type: 'line' }, backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' } }, grid: { top: '15%', left: '8%', right: '6%', bottom: '15%' }, xAxis: { type: 'category', data: dates, axisLabel: { color: '#fff', fontSize: 11 }, axisLine: { lineStyle: { color: '#5A6E71' } }, axisTick: { show: false } }, yAxis: { type: 'value', min: 0, max: 60, interval: 10, axisLabel: { color: '#fff', fontSize: 11 }, axisLine: { lineStyle: { color: '#5A6E71' } }, splitLine: { lineStyle: { color: 'rgba(90, 110, 113, 0.3)', type: 'dashed' } } }, series: [ { type: 'line', data: expenditure, smooth: true, lineStyle: { width: 2, color: '#00FEFC' }, itemStyle: { color: '#00FEFC' }, areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ { offset: 0, color: 'rgba(0, 254, 252, 0.4)' }, { offset: 1, color: 'rgba(0, 254, 252, 0.05)' } ]) } } ] }; expenditureTrendChart.setOption(option); } // 初始化项目支出占比图表(环形图) function initExpenditureProportionChart() { expenditureProportionChart = echarts.init(document.getElementById('expenditureProportionChart')); const option = { tooltip: { trigger: 'item', backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' }, formatter: '{b}: {d}%' }, legend: { bottom: 10, left: 'center', textStyle: { color: '#fff', fontSize: 12 }, itemWidth: 12, itemHeight: 8, itemGap: 15 }, series: [ { name: '支出占比', type: 'pie', radius: ['50%', '70%'], center: ['50%', '45%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 5, borderColor: 'rgba(13, 34, 37, 0.8)', borderWidth: 2 }, label: { show: true, formatter: '{b}\n{d}%', color: '#fff', fontSize: 12, fontWeight: 'bold' }, emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold' } }, data: [ { value: 20, name: '支出', itemStyle: { color: '#00FEFC' } }, { value: 80, name: '预算剩余', itemStyle: { color: '#FFFFFF' } } ] } ] }; expenditureProportionChart.setOption(option); } // 初始化项目风险图表 function initProjectRiskChart() { projectRiskChart = echarts.init(document.getElementById('projectRiskChart')); const option = { tooltip: { trigger: 'item', backgroundColor: 'rgba(19, 51, 55, 0.9)', borderColor: 'rgba(0, 254, 252, 0.5)', borderWidth: 1, textStyle: { color: '#fff' }, formatter: '{b}: {c}个 ({d}%)' }, legend: { orient: 'vertical', right: 10, top: 'center', textStyle: { color: '#fff', fontSize: 12 }, itemWidth: 12, itemHeight: 8, itemGap: 10, formatter: function(name) { const item = option.series[0].data.find(d => d.name === name); return name + ' ' + (item ? item.value + '%' : ''); } }, series: [ { name: '项目风险', type: 'pie', radius: ['40%', '70%'], center: ['35%', '50%'], avoidLabelOverlap: false, itemStyle: { borderRadius: 5, borderColor: 'rgba(13, 34, 37, 0.8)', borderWidth: 2 }, label: { show: false }, emphasis: { label: { show: true, fontSize: 14, fontWeight: 'bold', color: '#fff' } }, data: [ { value: 60, name: '二级风险', itemStyle: { color: '#4A90E2' } }, { value: 60, name: '三级风险', itemStyle: { color: '#1CFFA3' } }, { value: 26, name: '四级风险', itemStyle: { color: '#00FEFC' } }, { value: 14, name: '五级风险', itemStyle: { color: '#FF9C65' } } ] } ], graphic: [ { type: 'text', left: '35%', top: '75%', style: { text: '总风险数量 60个', textAlign: 'center', fill: '#fff', fontSize: 13 } } ] }; projectRiskChart.setOption(option); } // 初始化分析预警表格 function initWarningTable() { const warnings = [ { id: '01', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '02', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '03', time: 'XXXX-XX-XX', type: '成本', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '04', time: 'XXXX-XX-XX', type: '风险', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '05', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' } ]; renderWarningTable(warnings); } // 渲染分析预警表格 function renderWarningTable(warnings) { const tbody = $('#warningTableBody'); tbody.empty(); warnings.forEach(warning => { const row = ` ${warning.id} ${warning.time} ${warning.type} ${warning.content} ${warning.action} `; tbody.append(row); }); } // 筛选分析预警 let currentWarningFilter = 'all'; function filterWarning(type) { currentWarningFilter = type; // 更新标签状态 $('.warning-tab').removeClass('active'); $(`.warning-tab[data-type="${type}"]`).addClass('active'); // 重新渲染表格 const allWarnings = [ { id: '01', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '02', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '03', time: 'XXXX-XX-XX', type: '成本', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '04', time: 'XXXX-XX-XX', type: '风险', content: 'XXXXXXXXXXXXXX', action: '制定策略' }, { id: '05', time: 'XXXX-XX-XX', type: '进度', content: 'XXXXXXXXXXXXXX', action: '制定策略' } ]; const filteredWarnings = type === 'all' ? allWarnings : allWarnings.filter(item => item.type === type); renderWarningTable(filteredWarnings); } // 更新图表 function updateCharts() { // 这里可以重新加载图表数据 // 实际应该从API获取数据并更新图表 if (riskAnalysisChart) riskAnalysisChart.resize(); if (civilSpecialtyChart) civilSpecialtyChart.resize(); if (electricalSpecialtyChart) electricalSpecialtyChart.resize(); if (expenditureTrendChart) expenditureTrendChart.resize(); if (expenditureProportionChart) expenditureProportionChart.resize(); if (projectRiskChart) projectRiskChart.resize(); }