hb_zhgd_screen/js/pages/newDataAnalysis/resourceRateAnalysis.js

797 lines
27 KiB
JavaScript
Raw Normal View History

2025-10-13 09:33:54 +08:00
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');
});