hb_zhgd_screen/js/pages/newDataAnalysis/resourceRateAnalysis.js

797 lines
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

let table, layer, form;
let utilizationChart = null, trendsChart = null;
let isAnimating = false; // 防止重复动画的标志位
// 模拟数据
const mockData = {
// 总体统计数据
overallStats: {
totalRate: 85.2,
personnelRate: 88.5,
equipmentRate: 82.3,
materialRate: 84.8
},
// 资源概览数据
resourceOverview: {
personnel: { count: 126, rate: 88.5 },
equipment: { count: 42, rate: 82.3 },
material: { count: 89, rate: 84.8 },
energy: { count: 76, rate: 91.2 }
},
// 资源详细列表
resourceDetails: [
{ type: '人员', name: '土建班组A', status: 'active', rate: 92.5, assessment: '优秀' },
{ type: '人员', name: '钢筋班组B', status: 'working', rate: 88.2, assessment: '良好' },
{ type: '人员', name: '混凝土班组C', status: 'rest', rate: 85.7, assessment: '良好' },
{ type: '设备', name: '塔吊001', status: 'running', rate: 89.3, assessment: '优秀' },
{ type: '设备', name: '挖掘机002', status: 'normal', rate: 78.6, assessment: '一般' },
{ type: '设备', name: '混凝土泵车', status: 'maintenance', rate: 76.4, assessment: '一般' },
{ type: '设备', name: '起重机003', status: 'offline', rate: 0, assessment: '较差' },
{ type: '材料', name: '钢筋', status: 'sufficient', rate: 91.2, assessment: '优秀' },
{ type: '材料', name: '混凝土', status: 'normal', rate: 83.5, assessment: '良好' },
{ type: '材料', name: '砂石料', status: 'low_stock', rate: 79.8, assessment: '一般' },
{ type: '材料', name: '水泥', status: 'critical', rate: 65.2, assessment: '较差' },
{ type: '能源', name: '电力系统', status: 'stable', rate: 93.1, assessment: '优秀' },
{ type: '能源', name: '柴油储备', status: 'high_consumption', rate: 88.4, assessment: '良好' },
{ type: '能源', name: '天然气', status: 'available', rate: 85.6, assessment: '良好' },
{ type: '能源', name: '备用电源', status: 'standby', rate: 100, assessment: '优秀' }
],
// 利用率分布数据
utilizationData: [
{ name: '人员', value: 88.5, color: '#16baaa' },
{ name: '设备', value: 82.3, color: '#20d3c2' },
{ name: '材料', value: 84.8, color: '#25e5d0' },
{ name: '能源', value: 91.2, color: '#2af0dd' }
],
// 趋势数据最近7天
trendsData: {
dates: ['2024-01-15', '2024-01-16', '2024-01-17', '2024-01-18', '2024-01-19', '2024-01-20', '2024-01-21'],
personnel: [85.2, 87.1, 88.5, 89.2, 88.8, 87.9, 88.5],
equipment: [78.9, 80.3, 82.1, 81.7, 82.3, 83.1, 82.3],
material: [82.1, 83.5, 84.2, 84.8, 85.1, 84.6, 84.8],
energy: [89.5, 90.2, 91.2, 90.8, 91.5, 91.0, 91.2]
},
// 优化建议
optimizationSuggestions: [
{
title: '设备调度优化',
description: '挖掘机002利用率偏低建议调整作业计划提高设备运转效率',
priority: '高优先级'
},
{
title: '材料库存管理',
description: '砂石料库存不足,建议提前采购补充,避免影响施工进度',
priority: '中优先级'
},
{
title: '人员配置调整',
description: '土建班组A效率突出建议增加人员配置或分配更多任务',
priority: '中优先级'
},
{
title: '能源消耗监控',
description: '柴油消耗偏高,建议检查设备运行状态,优化燃油使用',
priority: '低优先级'
},
{
title: '设备维护计划',
description: '混凝土泵车正在维护中,建议制定预防性维护计划减少停机时间',
priority: '高优先级'
}
]
};
// 页面初始化
layui.use(['layer', 'table', 'form'], function () {
layer = layui.layer;
table = layui.table;
form = layui.form;
// 初始化粒子背景
initParticles();
// 模拟加载延迟
setTimeout(() => {
// 隐藏加载动画
$('#loadingOverlay').fadeOut(500);
// 初始化页面数据
initPageData();
// 初始化图表
initCharts();
// 启动数据更新定时器
startDataRefresh();
}, 2000);
});
// 初始化粒子背景
function initParticles() {
if (typeof particlesJS !== 'undefined') {
particlesJS('particles-js', {
"particles": {
"number": {
"value": 80,
"density": {
"enable": true,
"value_area": 800
}
},
"color": {
"value": "#16baaa"
},
"shape": {
"type": "circle",
"stroke": {
"width": 0,
"color": "#000000"
}
},
"opacity": {
"value": 0.5,
"random": false,
"anim": {
"enable": false,
"speed": 1,
"opacity_min": 0.1,
"sync": false
}
},
"size": {
"value": 3,
"random": true,
"anim": {
"enable": false,
"speed": 40,
"size_min": 0.1,
"sync": false
}
},
"line_linked": {
"enable": true,
"distance": 150,
"color": "#16baaa",
"opacity": 0.4,
"width": 1
},
"move": {
"enable": true,
"speed": 2,
"direction": "none",
"random": false,
"straight": false,
"out_mode": "out",
"bounce": false,
"attract": {
"enable": false,
"rotateX": 600,
"rotateY": 1200
}
}
},
"interactivity": {
"detect_on": "canvas",
"events": {
"onhover": {
"enable": true,
"mode": "repulse"
},
"onclick": {
"enable": true,
"mode": "push"
},
"resize": true
},
"modes": {
"grab": {
"distance": 400,
"line_linked": {
"opacity": 1
}
},
"bubble": {
"distance": 400,
"size": 40,
"duration": 2,
"opacity": 8,
"speed": 3
},
"repulse": {
"distance": 200,
"duration": 0.4
},
"push": {
"particles_nb": 4
},
"remove": {
"particles_nb": 2
}
}
},
"retina_detect": true
});
}
}
// 初始化页面数据
function initPageData() {
// 直接设置初始值,不使用动画
const stats = mockData.overallStats;
$('#totalRate').text(stats.totalRate.toFixed(1) + '%');
$('#personnelRate').text(stats.personnelRate.toFixed(1) + '%');
$('#equipmentRate').text(stats.equipmentRate.toFixed(1) + '%');
$('#materialRate').text(stats.materialRate.toFixed(1) + '%');
// 设置资源概览初始值
const overview = mockData.resourceOverview;
$('#personnelCount').text(overview.personnel.count);
$('#equipmentCount').text(overview.equipment.count);
$('#materialCount').text(overview.material.count);
$('#energyCount').text(overview.energy.count + '%');
// 更新资源详细表格
updateResourceTable();
// 更新优化建议
updateOptimizationSuggestions();
}
// 更新头部统计数据
function updateHeaderStats() {
const stats = mockData.overallStats;
// 获取当前值如果不存在则从0开始
const currentTotal = parseFloat($('#totalRate').text()) || 0;
const currentPersonnel = parseFloat($('#personnelRate').text()) || 0;
const currentEquipment = parseFloat($('#equipmentRate').text()) || 0;
const currentMaterial = parseFloat($('#materialRate').text()) || 0;
animateValue('totalRate', currentTotal, stats.totalRate, '%');
animateValue('personnelRate', currentPersonnel, stats.personnelRate, '%');
animateValue('equipmentRate', currentEquipment, stats.equipmentRate, '%');
animateValue('materialRate', currentMaterial, stats.materialRate, '%');
}
// 数值动画函数
function animateValue(elementId, start, end, suffix = '') {
const element = document.getElementById(elementId);
if (!element) return;
// 如果起始值无效设为0
if (isNaN(start) || start < 0) start = 0;
if (isNaN(end)) return;
// 如果数值相同,直接设置,不需要动画
if (Math.abs(end - start) < 0.1) {
element.textContent = end.toFixed(1) + suffix;
return;
}
const range = end - start;
const duration = 1000; // 动画持续时间(毫秒)
const startTime = Date.now();
const animate = () => {
const now = Date.now();
const elapsed = now - startTime;
const progress = Math.min(elapsed / duration, 1);
// 使用缓动函数
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
const current = start + (range * easeOutQuart);
element.textContent = current.toFixed(1) + suffix;
if (progress < 1) {
requestAnimationFrame(animate);
} else {
element.textContent = end.toFixed(1) + suffix;
}
};
animate();
}
// 更新资源概览
function updateResourceOverview() {
const overview = mockData.resourceOverview;
// 获取当前值如果不存在则从0开始
const currentPersonnel = parseInt($('#personnelCount').text()) || 0;
const currentEquipment = parseInt($('#equipmentCount').text()) || 0;
const currentMaterial = parseInt($('#materialCount').text()) || 0;
const currentEnergy = parseInt($('#energyCount').text()) || 0;
animateValue('personnelCount', currentPersonnel, overview.personnel.count);
animateValue('equipmentCount', currentEquipment, overview.equipment.count);
animateValue('materialCount', currentMaterial, overview.material.count);
animateValue('energyCount', currentEnergy, overview.energy.count, '%');
}
// 更新资源详细表格
function updateResourceTable() {
const tableBody = $('#resourceTableBody');
tableBody.empty();
mockData.resourceDetails.forEach((item, index) => {
const assessmentClass = getAssessmentClass(item.assessment);
const statusClass = getStatusClass(item.status);
const row = `
<tr class="table-row-animate" style="animation-delay: ${index * 0.1}s;">
<td>${item.type}</td>
<td>${item.name}</td>
<td><span class="${statusClass}">${translateStatus(item.status)}</span></td>
<td><span class="rate-value">${item.rate}%</span></td>
<td><span class="${assessmentClass}">${item.assessment}</span></td>
</tr>
`;
tableBody.append(row);
});
}
// 获取效率评估样式类
function getAssessmentClass(assessment) {
switch(assessment) {
case '优秀': return 'assessment-excellent';
case '良好': return 'assessment-good';
case '一般': return 'assessment-normal';
default: return '';
}
}
// 获取状态样式类
function getStatusClass(status) {
// 处理英文状态和中英文对照状态
const lowerStatus = status.toLowerCase();
// 正常/良好状态
if (lowerStatus.includes('active') || lowerStatus.includes('normal') || lowerStatus.includes('sufficient') ||
lowerStatus.includes('running') || lowerStatus.includes('working') || lowerStatus.includes('available') ||
lowerStatus.includes('stable') || lowerStatus.includes('good') ||
status.includes('工作中') || status.includes('运行中') || status.includes('充足') ||
status.includes('正常') || status.includes('可用') || status.includes('稳定')) {
return 'status-active';
}
// 警告/异常状态
else if (lowerStatus.includes('rest') || lowerStatus.includes('maintenance') || lowerStatus.includes('low') ||
lowerStatus.includes('high_consumption') || lowerStatus.includes('low_stock') || lowerStatus.includes('warning') ||
lowerStatus.includes('critical') || lowerStatus.includes('offline') || lowerStatus.includes('error') ||
lowerStatus.includes('unavailable') || lowerStatus.includes('unstable') || lowerStatus.includes('poor') ||
status.includes('休息中') || status.includes('维护中') || status.includes('库存低') || status.includes('偏高') ||
status.includes('警告') || status.includes('紧急') || status.includes('离线') || status.includes('故障') ||
status.includes('不可用') || status.includes('不稳定') || status.includes('较差')) {
return 'status-warning';
}
// 默认状态
return 'status-normal';
}
// 状态中英文对照
function translateStatus(status) {
const statusMap = {
'active': '运行中',
'normal': '正常',
'sufficient': '充足',
'rest': '休息中',
'maintenance': '维护中',
'low_stock': '库存不足',
'high_consumption': '消耗偏高',
'offline': '离线',
'error': '故障',
'warning': '警告',
'good': '良好',
'poor': '较差',
'working': '工作中',
'running': '运行中',
'idle': '空闲',
'standby': '待机',
'busy': '繁忙',
'available': '可用',
'unavailable': '不可用',
'critical': '紧急',
'low': '偏低',
'high': '偏高',
'stable': '稳定',
'unstable': '不稳定'
};
// 检查是否为纯英文状态(不包含中文字符)
const isEnglishOnly = /^[a-zA-Z_\-\s]+$/.test(status);
if (isEnglishOnly) {
const lowerStatus = status.toLowerCase().trim();
// 如果是英文状态,返回中文翻译+英文原文
if (statusMap[lowerStatus]) {
return `${statusMap[lowerStatus]} (${status})`;
} else {
// 如果没有对应翻译,但是是英文,则添加提示
return `${status} (英文状态)`;
}
}
// 如果已经是中文或混合文本,直接返回
return status;
}
// 更新优化建议
function updateOptimizationSuggestions() {
const container = $('#optimizationList');
container.empty();
mockData.optimizationSuggestions.forEach((suggestion, index) => {
const priorityClass = getPriorityClass(suggestion.priority);
const iconClass = getPriorityIcon(suggestion.priority);
const item = `
<div class="optimization-item animate__animated animate__fadeInUp" style="animation-delay: ${index * 0.1}s;">
<div class="optimization-title">
<i class="${iconClass}"></i>
${suggestion.title}
<span class="optimization-priority ${priorityClass}">${suggestion.priority}</span>
</div>
<div class="optimization-desc">${suggestion.description}</div>
</div>
`;
container.append(item);
});
}
// 获取优先级样式类
function getPriorityClass(priority) {
switch(priority) {
case '高优先级': return 'priority-high';
case '中优先级': return 'priority-medium';
case '低优先级': return 'priority-low';
default: return '';
}
}
// 获取优先级图标
function getPriorityIcon(priority) {
switch(priority) {
case '高优先级': return 'fas fa-exclamation-triangle priority-icon-high';
case '中优先级': return 'fas fa-info-circle priority-icon-medium';
case '低优先级': return 'fas fa-check-circle priority-icon-low';
default: return 'fas fa-circle';
}
}
// 初始化图表
function initCharts() {
initUtilizationChart();
initTrendsChart();
}
// 初始化利用率分布图表
function initUtilizationChart() {
const chartDom = document.getElementById('utilizationChart');
utilizationChart = echarts.init(chartDom);
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(22, 186, 170, 0.9)',
borderColor: '#16baaa',
textStyle: {
color: '#fff'
}
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center',
textStyle: {
color: '#16baaa',
fontSize: 12
}
},
series: [
{
name: '资源利用率',
type: 'pie',
radius: ['40%', '70%'],
center: ['65%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 8,
borderColor: '#0a1e2b',
borderWidth: 2
},
label: {
show: true,
position: 'outside',
color: '#8cc8c1',
fontSize: 11,
formatter: '{b}: {c}%'
},
emphasis: {
label: {
show: true,
fontSize: 12,
fontWeight: 'bold',
color: '#16baaa'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(22, 186, 170, 0.5)'
}
},
data: mockData.utilizationData.map(item => ({
name: item.name,
value: item.value,
itemStyle: {
color: item.color
}
}))
}
]
};
utilizationChart.setOption(option);
}
// 初始化趋势图表
function initTrendsChart() {
const chartDom = document.getElementById('trendsChart');
trendsChart = echarts.init(chartDom);
const option = {
backgroundColor: 'transparent',
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(22, 186, 170, 0.9)',
borderColor: '#16baaa',
textStyle: {
color: '#fff'
},
axisPointer: {
type: 'cross',
lineStyle: {
color: '#16baaa'
}
}
},
legend: {
data: ['人员', '设备', '材料', '能源'],
textStyle: {
color: '#16baaa'
},
top: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: mockData.trendsData.dates.map(date => date.substring(5)),
axisLine: {
lineStyle: {
color: '#16baaa'
}
},
axisTick: {
lineStyle: {
color: '#16baaa'
}
},
axisLabel: {
color: '#8cc8c1'
}
},
yAxis: {
type: 'value',
min: 70,
max: 95,
axisLine: {
lineStyle: {
color: '#16baaa'
}
},
axisTick: {
lineStyle: {
color: '#16baaa'
}
},
axisLabel: {
color: '#8cc8c1',
formatter: '{value}%'
},
splitLine: {
lineStyle: {
color: 'rgba(22, 186, 170, 0.2)'
}
}
},
series: [
{
name: '人员',
type: 'line',
smooth: true,
data: mockData.trendsData.personnel,
lineStyle: {
color: '#16baaa',
width: 2
},
itemStyle: {
color: '#16baaa'
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: 'rgba(22, 186, 170, 0.3)' },
{ offset: 1, color: 'rgba(22, 186, 170, 0.1)' }
])
}
},
{
name: '设备',
type: 'line',
smooth: true,
data: mockData.trendsData.equipment,
lineStyle: {
color: '#20d3c2',
width: 2
},
itemStyle: {
color: '#20d3c2'
}
},
{
name: '材料',
type: 'line',
smooth: true,
data: mockData.trendsData.material,
lineStyle: {
color: '#25e5d0',
width: 2
},
itemStyle: {
color: '#25e5d0'
}
},
{
name: '能源',
type: 'line',
smooth: true,
data: mockData.trendsData.energy,
lineStyle: {
color: '#2af0dd',
width: 2
},
itemStyle: {
color: '#2af0dd'
}
}
]
};
trendsChart.setOption(option);
}
// 启动数据刷新定时器
function startDataRefresh() {
setInterval(() => {
// 模拟数据更新
updateMockData();
updatePageData();
updateCharts();
}, 60000); // 每60秒更新一次减少频率
}
// 更新模拟数据
function updateMockData() {
// 随机更新一些数据,但变化幅度较小
const variation = 2; // 最大变化幅度
mockData.overallStats.totalRate = Math.round((mockData.overallStats.totalRate + (Math.random() - 0.5) * variation) * 10) / 10;
mockData.overallStats.personnelRate = Math.round((mockData.overallStats.personnelRate + (Math.random() - 0.5) * variation) * 10) / 10;
mockData.overallStats.equipmentRate = Math.round((mockData.overallStats.equipmentRate + (Math.random() - 0.5) * variation) * 10) / 10;
mockData.overallStats.materialRate = Math.round((mockData.overallStats.materialRate + (Math.random() - 0.5) * variation) * 10) / 10;
// 限制数值范围
mockData.overallStats.totalRate = Math.max(75, Math.min(95, mockData.overallStats.totalRate));
mockData.overallStats.personnelRate = Math.max(75, Math.min(95, mockData.overallStats.personnelRate));
mockData.overallStats.equipmentRate = Math.max(70, Math.min(90, mockData.overallStats.equipmentRate));
mockData.overallStats.materialRate = Math.max(75, Math.min(95, mockData.overallStats.materialRate));
// 同步更新资源概览数据
mockData.resourceOverview.personnel.rate = mockData.overallStats.personnelRate;
mockData.resourceOverview.equipment.rate = mockData.overallStats.equipmentRate;
mockData.resourceOverview.material.rate = mockData.overallStats.materialRate;
}
// 更新页面数据
function updatePageData() {
if (isAnimating) return; // 如果正在动画中,跳过更新
isAnimating = true;
updateHeaderStats();
updateResourceOverview();
// 1.5秒后重置动画标志
setTimeout(() => {
isAnimating = false;
}, 1500);
}
// 更新图表数据
function updateCharts() {
if (utilizationChart) {
// 更新利用率分布图
mockData.utilizationData[0].value = mockData.overallStats.personnelRate;
mockData.utilizationData[1].value = mockData.overallStats.equipmentRate;
mockData.utilizationData[2].value = mockData.overallStats.materialRate;
utilizationChart.setOption({
series: [{
data: mockData.utilizationData.map(item => ({
name: item.name,
value: parseFloat(item.value.toFixed(1)),
itemStyle: {
color: item.color
}
}))
}]
});
}
}
// 窗口大小改变时重新调整图表
window.addEventListener('resize', function() {
if (utilizationChart) {
utilizationChart.resize();
}
if (trendsChart) {
trendsChart.resize();
}
});
// 添加状态和评估样式
$(document).ready(function() {
$('<style>').prop('type', 'text/css').html(`
.status-active { color: #16baaa; font-weight: bold; }
.status-warning { color: #ffa726; font-weight: bold; }
.status-normal { color: #8cc8c1; }
.assessment-excellent { color: #16baaa; font-weight: bold; }
.assessment-good { color: #20d3c2; font-weight: bold; }
.assessment-normal { color: #ffa726; font-weight: bold; }
.priority-high { color: #ff5722; }
.priority-medium { color: #ffa726; }
.priority-low { color: #4caf50; }
.priority-icon-high { color: #ff5722; margin-right: 5px; animation: blink 1s infinite; }
.priority-icon-medium { color: #ffa726; margin-right: 5px; }
.priority-icon-low { color: #4caf50; margin-right: 5px; }
.rate-value {
color: #20d3c2;
font-weight: bold;
text-shadow: 0 0 5px rgba(32, 211, 194, 0.5);
}
.table-row-animate {
animation: slideInFromLeft 0.5s ease forwards;
opacity: 0;
transform: translateX(-20px);
}
@keyframes slideInFromLeft {
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0.3; }
}
`).appendTo('head');
});