2025-10-21 13:46:32 +08:00
|
|
|
|
let table, layer, form, laydate;
|
2026-01-24 14:23:35 +08:00
|
|
|
|
let avgTasksChart = null;
|
|
|
|
|
|
let equipmentUsageChart = null;
|
|
|
|
|
|
let bidCode = parent.parent.$('#bidPro').val();
|
|
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 获取当天日期
|
|
|
|
|
|
function getTodayDate() {
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const year = now.getFullYear();
|
|
|
|
|
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
|
|
|
|
const day = String(now.getDate()).padStart(2, '0');
|
|
|
|
|
|
return year + '-' + month + '-' + day;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当月第一天和最后一天(保留用于其他功能)
|
2026-01-24 14:23:35 +08:00
|
|
|
|
function getCurrentMonthRange() {
|
|
|
|
|
|
const now = new Date();
|
|
|
|
|
|
const year = now.getFullYear();
|
|
|
|
|
|
const month = now.getMonth();
|
|
|
|
|
|
|
|
|
|
|
|
// 当月第一天
|
|
|
|
|
|
const firstDay = new Date(year, month, 1);
|
|
|
|
|
|
const startDate = year + '-' + String(month + 1).padStart(2, '0') + '-' + String(firstDay.getDate()).padStart(2, '0');
|
|
|
|
|
|
|
|
|
|
|
|
// 当月最后一天
|
|
|
|
|
|
const lastDay = new Date(year, month + 1, 0);
|
|
|
|
|
|
const endDate = year + '-' + String(month + 1).padStart(2, '0') + '-' + String(lastDay.getDate()).padStart(2, '0');
|
|
|
|
|
|
|
|
|
|
|
|
return { startDate, endDate };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
const today = getTodayDate();
|
2026-01-24 14:23:35 +08:00
|
|
|
|
let queryParams = {
|
|
|
|
|
|
projectId: bidCode,
|
2026-01-24 18:55:45 +08:00
|
|
|
|
startTestDay: today,
|
|
|
|
|
|
endTestDay: today,
|
|
|
|
|
|
startTime: today,
|
|
|
|
|
|
endTime: today,
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
2025-10-17 14:57:09 +08:00
|
|
|
|
|
2025-10-21 13:46:32 +08:00
|
|
|
|
layui.use(["layer", "table", "form", "laydate"], function () {
|
2025-10-17 14:57:09 +08:00
|
|
|
|
layer = layui.layer;
|
|
|
|
|
|
table = layui.table;
|
|
|
|
|
|
form = layui.form;
|
2025-10-21 13:46:32 +08:00
|
|
|
|
laydate = layui.laydate;
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 响应成功后的拦截器
|
|
|
|
|
|
$.ajaxSetup({
|
|
|
|
|
|
beforeSend: function (xhr, options) {
|
|
|
|
|
|
var originalSuccess = options.success;
|
|
|
|
|
|
options.success = function (data, textStatus, jqXhr) {
|
|
|
|
|
|
data = modifyResponseData(data);
|
|
|
|
|
|
originalSuccess.apply(this, arguments);
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
2025-10-21 13:46:32 +08:00
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化页面
|
|
|
|
|
|
initPage();
|
|
|
|
|
|
// 初始化日期范围选择器
|
|
|
|
|
|
initDateRangePicker();
|
2025-10-17 14:57:09 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化页面
|
|
|
|
|
|
function initPage() {
|
|
|
|
|
|
initPersonnelTables();
|
2026-01-24 17:14:53 +08:00
|
|
|
|
getTop5Personnel();
|
|
|
|
|
|
getBottom5Personnel();
|
|
|
|
|
|
getTradeProportionAndAvgTasks();
|
|
|
|
|
|
getEquipmentUsageAndFailureRank();
|
|
|
|
|
|
getEquipmentFailureRank();
|
2026-01-24 14:23:35 +08:00
|
|
|
|
initTradeProportion();
|
|
|
|
|
|
initAvgTasksChart();
|
|
|
|
|
|
initEquipmentUsageChart();
|
|
|
|
|
|
initEquipmentFailureList();
|
|
|
|
|
|
initWarningTable();
|
|
|
|
|
|
initMockData();
|
2026-01-24 19:13:29 +08:00
|
|
|
|
initFileUploadHandler();
|
2025-10-21 13:46:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 获取人员数据中的班组利用率排名前五名的
|
|
|
|
|
|
function getTop5Personnel() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/selectTopList'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateTop5PersonnelTable(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取后5名人员数据
|
|
|
|
|
|
function getBottom5Personnel() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/selectDownList'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateBottom5PersonnelTable(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取各工种任务占比和人均任务数
|
|
|
|
|
|
function getTradeProportionAndAvgTasks() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/getWorkTypeRate'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateTradeProportion(data);
|
|
|
|
|
|
updateAvgTasksChart(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取设备使用率
|
|
|
|
|
|
function getEquipmentUsageAndFailureRank() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/getWeeksDevData'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateEquipmentUsageChart(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取设备故障排名
|
|
|
|
|
|
function getEquipmentFailureRank() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/getDevErrTop'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateEquipmentFailureList(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取工程进度
|
|
|
|
|
|
function getEngineeringProgress() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/getProProgress'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateEngineeringProgress(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
getEngineeringProgress()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新工程进度展示(取 data[0] 的 planProgress、progress)
|
|
|
|
|
|
function updateEngineeringProgress(data) {
|
|
|
|
|
|
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
const item = data[0];
|
|
|
|
|
|
const planProgress = parseFloat(item.planProgress || 0);
|
|
|
|
|
|
const progress = parseFloat(item.progress || 0);
|
|
|
|
|
|
|
|
|
|
|
|
$('#plannedProgressText').text(planProgress.toFixed(1) + '%');
|
|
|
|
|
|
$('#actualProgressText').text(progress.toFixed(1) + '%');
|
|
|
|
|
|
|
|
|
|
|
|
// 进度条宽度归一化,两者之和为 100%
|
|
|
|
|
|
const total = planProgress + progress;
|
|
|
|
|
|
const planPercent = total > 0 ? (planProgress / total * 100) : 50;
|
|
|
|
|
|
const actualPercent = total > 0 ? (progress / total * 100) : 50;
|
|
|
|
|
|
|
|
|
|
|
|
$('#actualProgressFill').css('width', actualPercent + '%');
|
|
|
|
|
|
$('#plannedProgressFill').css('width', planPercent + '%');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取分析预警
|
|
|
|
|
|
function getAnalysisWarning() {
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/getWarnList'
|
|
|
|
|
|
+ '?bidCode=' + (bidCode || '')
|
|
|
|
|
|
+ '&startTime=' + (queryParams.startTime || '')
|
|
|
|
|
|
+ '&endTime=' + (queryParams.endTime || '');
|
|
|
|
|
|
ajaxRequestGet(url, 'GET', true, function () { }, function (result) {
|
|
|
|
|
|
let data = [];
|
|
|
|
|
|
if (result && result.data && Array.isArray(result.data)) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
} else if (result && Array.isArray(result)) {
|
|
|
|
|
|
data = result;
|
|
|
|
|
|
} else if (result && result.rows && Array.isArray(result.rows)) {
|
|
|
|
|
|
data = result.rows;
|
|
|
|
|
|
}
|
|
|
|
|
|
updateAnalysisWarningTable(data);
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
getAnalysisWarning()
|
|
|
|
|
|
|
|
|
|
|
|
// 更新分析预警表格(data 直接渲染)
|
|
|
|
|
|
function updateAnalysisWarningTable(data) {
|
|
|
|
|
|
if (!table) return;
|
|
|
|
|
|
table.reload('warningTable', {
|
|
|
|
|
|
data: data || []
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 防抖函数
|
|
|
|
|
|
function debounce(func, wait) {
|
|
|
|
|
|
let timeout;
|
|
|
|
|
|
return function executedFunction(...args) {
|
|
|
|
|
|
const later = () => {
|
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
func(...args);
|
|
|
|
|
|
};
|
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
timeout = setTimeout(later, wait);
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2025-10-18 16:58:04 +08:00
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化日期范围选择器
|
|
|
|
|
|
function initDateRangePicker() {
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 设置初始显示值为当天范围
|
2026-01-24 14:23:35 +08:00
|
|
|
|
const initialValue = queryParams.startTestDay + ' ~ ' + queryParams.endTestDay;
|
|
|
|
|
|
$('#dateRange').val(initialValue);
|
2025-10-18 16:58:04 +08:00
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 使用范围选择器,单个输入框显示日期范围
|
|
|
|
|
|
laydate.render({
|
|
|
|
|
|
elem: '#dateRange',
|
|
|
|
|
|
type: 'date',
|
|
|
|
|
|
range: true,
|
|
|
|
|
|
format: 'yyyy-MM-dd',
|
|
|
|
|
|
theme: 'dark',
|
|
|
|
|
|
value: queryParams.startTestDay + ' - ' + queryParams.endTestDay,
|
|
|
|
|
|
done: function (value, date, endDate) {
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 重置为当天日期的函数
|
|
|
|
|
|
const resetToToday = function () {
|
|
|
|
|
|
const today = getTodayDate();
|
|
|
|
|
|
queryParams.startTestDay = today;
|
|
|
|
|
|
queryParams.endTestDay = today;
|
|
|
|
|
|
queryParams.startTime = today;
|
|
|
|
|
|
queryParams.endTime = today;
|
|
|
|
|
|
$('#dateRange').val(today + ' ~ ' + today);
|
2026-01-24 14:23:35 +08:00
|
|
|
|
refreshAllModules();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
if (value && value.trim() !== '') {
|
|
|
|
|
|
const dates = value.split(' - ');
|
|
|
|
|
|
if (dates.length === 2) {
|
|
|
|
|
|
const startDate = dates[0].trim();
|
|
|
|
|
|
const endDateStr = dates[1].trim();
|
|
|
|
|
|
|
|
|
|
|
|
$('#dateRange').val(startDate + ' ~ ' + endDateStr);
|
|
|
|
|
|
|
|
|
|
|
|
queryParams.startTestDay = startDate;
|
|
|
|
|
|
queryParams.endTestDay = endDateStr;
|
2026-01-24 17:14:53 +08:00
|
|
|
|
queryParams.startTime = startDate;
|
|
|
|
|
|
queryParams.endTime = endDateStr;
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
refreshAllModules();
|
|
|
|
|
|
} else {
|
2026-01-24 18:55:45 +08:00
|
|
|
|
resetToToday();
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2026-01-24 18:55:45 +08:00
|
|
|
|
resetToToday();
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新所有模块数据
|
|
|
|
|
|
function refreshAllModules() {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
getTop5Personnel();
|
|
|
|
|
|
getBottom5Personnel();
|
|
|
|
|
|
getTradeProportionAndAvgTasks();
|
|
|
|
|
|
getEquipmentUsageAndFailureRank();
|
|
|
|
|
|
getEquipmentFailureRank();
|
2026-01-24 14:23:35 +08:00
|
|
|
|
if (avgTasksChart) {
|
|
|
|
|
|
initAvgTasksChart();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (equipmentUsageChart) {
|
|
|
|
|
|
initEquipmentUsageChart();
|
|
|
|
|
|
}
|
|
|
|
|
|
if (table) {
|
|
|
|
|
|
table.reload('warningTable');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化人员数据表格(前5名和后5名)
|
|
|
|
|
|
function initPersonnelTables() {
|
|
|
|
|
|
// 前5名表格
|
|
|
|
|
|
table.render({
|
|
|
|
|
|
elem: '#top5PersonnelTable',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
id: 'top5PersonnelTable',
|
|
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
skin: 'line',
|
|
|
|
|
|
page: false,
|
|
|
|
|
|
height: 'full',
|
|
|
|
|
|
cols: [[
|
|
|
|
|
|
{ type: 'numbers', title: '序号', width: '10%', align: 'center' },
|
2026-01-24 17:14:53 +08:00
|
|
|
|
{ field: 'workType', title: '专业', width: '15%', align: 'center' },
|
|
|
|
|
|
{ field: 'teamName', title: '班组', width: '20%', align: 'center' },
|
2026-01-24 14:23:35 +08:00
|
|
|
|
{ field: 'teamLeader', title: '班组负责人', width: '18%', align: 'center' },
|
2026-01-24 17:14:53 +08:00
|
|
|
|
{ field: 'teamPeople', title: '班组人数', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'dutyPeople', title: '当日到岗', width: '12%', align: 'center' },
|
2026-01-24 14:23:35 +08:00
|
|
|
|
{
|
2026-01-24 17:14:53 +08:00
|
|
|
|
field: 'userRate',
|
2026-01-24 14:23:35 +08:00
|
|
|
|
title: '利用率',
|
|
|
|
|
|
width: '13%',
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
templet: function (d) {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
const rate = d.userRate || '0.00%';
|
|
|
|
|
|
return rate;
|
2025-10-18 16:58:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
]]
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 后5名表格
|
|
|
|
|
|
table.render({
|
|
|
|
|
|
elem: '#bottom5PersonnelTable',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
id: 'bottom5PersonnelTable',
|
|
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
skin: 'line',
|
|
|
|
|
|
page: false,
|
|
|
|
|
|
height: 'full',
|
|
|
|
|
|
cols: [[
|
|
|
|
|
|
{ type: 'numbers', title: '序号', width: '10%', align: 'center' },
|
2026-01-24 17:14:53 +08:00
|
|
|
|
{ field: 'workType', title: '专业', width: '15%', align: 'center' },
|
|
|
|
|
|
{ field: 'teamName', title: '班组', width: '20%', align: 'center' },
|
2026-01-24 14:23:35 +08:00
|
|
|
|
{ field: 'teamLeader', title: '班组负责人', width: '18%', align: 'center' },
|
2026-01-24 17:14:53 +08:00
|
|
|
|
{ field: 'teamPeople', title: '班组人数', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'dutyPeople', title: '当日到岗', width: '12%', align: 'center' },
|
2026-01-24 14:23:35 +08:00
|
|
|
|
{
|
2026-01-24 17:14:53 +08:00
|
|
|
|
field: 'userRate',
|
2026-01-24 14:23:35 +08:00
|
|
|
|
title: '利用率',
|
|
|
|
|
|
width: '13%',
|
|
|
|
|
|
align: 'center',
|
|
|
|
|
|
templet: function (d) {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
const rate = d.userRate || '0.00%';
|
|
|
|
|
|
return rate;
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]]
|
|
|
|
|
|
});
|
2025-10-18 16:58:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 更新前5名人员表格数据
|
|
|
|
|
|
function updateTop5PersonnelTable(data) {
|
|
|
|
|
|
if (!table || !data || !Array.isArray(data)) return;
|
|
|
|
|
|
|
|
|
|
|
|
table.reload('top5PersonnelTable', {
|
|
|
|
|
|
data: data
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新后5名人员表格数据
|
|
|
|
|
|
function updateBottom5PersonnelTable(data) {
|
|
|
|
|
|
if (!table || !data || !Array.isArray(data)) return;
|
|
|
|
|
|
|
|
|
|
|
|
table.reload('bottom5PersonnelTable', {
|
|
|
|
|
|
data: data
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化各工种任务占比(六边形卡片)
|
|
|
|
|
|
function initTradeProportion() {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 初始化为空,等待接口数据
|
|
|
|
|
|
const container = document.getElementById('tradeProportionContainer');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新各工种任务占比(六边形卡片)
|
|
|
|
|
|
function updateTradeProportion(data) {
|
|
|
|
|
|
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
|
|
|
|
const container = document.getElementById('tradeProportionContainer');
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算总任务数
|
|
|
|
|
|
const totalTasks = data.reduce((sum, item) => {
|
|
|
|
|
|
const taskNum = parseFloat(item.taskNum || 0);
|
|
|
|
|
|
return sum + taskNum;
|
|
|
|
|
|
}, 0);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算每个工种的占比
|
|
|
|
|
|
const proportionData = data.map(function (item) {
|
|
|
|
|
|
const taskNum = parseFloat(item.taskNum || 0);
|
|
|
|
|
|
const percentage = totalTasks > 0 ? (taskNum / totalTasks * 100).toFixed(2) : 0;
|
|
|
|
|
|
return {
|
|
|
|
|
|
value: parseFloat(percentage),
|
|
|
|
|
|
label: item.workType || ''
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
const container = document.getElementById('tradeProportionContainer');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
const html = proportionData.map(function (item) {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
return `
|
|
|
|
|
|
<div class="trade-proportion-box">
|
|
|
|
|
|
<div class="trade-proportion-value">${item.value}%</div>
|
|
|
|
|
|
<div class="trade-proportion-label">${item.label}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html;
|
2025-10-17 14:57:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化各工种人均任务数柱状图
|
|
|
|
|
|
function initAvgTasksChart() {
|
|
|
|
|
|
const chartDom = document.getElementById('avgTasksChart');
|
|
|
|
|
|
if (!chartDom) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (avgTasksChart) {
|
|
|
|
|
|
avgTasksChart.dispose();
|
2025-10-17 14:57:09 +08:00
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
avgTasksChart = echarts.init(chartDom);
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 初始化为空数据
|
2025-10-17 14:57:09 +08:00
|
|
|
|
const option = {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
backgroundColor: 'transparent',
|
2025-10-17 14:57:09 +08:00
|
|
|
|
tooltip: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
axisPointer: { type: 'shadow' },
|
|
|
|
|
|
backgroundColor: 'rgba(13, 34, 37, 0.95)',
|
|
|
|
|
|
borderColor: 'rgba(6, 189, 221, 0.8)',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
borderRadius: 4,
|
|
|
|
|
|
padding: [12, 16],
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
2025-10-18 16:58:04 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
formatter: function (params) {
|
|
|
|
|
|
if (!params || !params.length) return '';
|
|
|
|
|
|
const name = params[0].name || '';
|
|
|
|
|
|
const value = params[0].value || 0;
|
|
|
|
|
|
return `${name}<br/>人均任务数: ${value}`;
|
|
|
|
|
|
}
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
left: '10%',
|
|
|
|
|
|
right: '10%',
|
|
|
|
|
|
bottom: '15%',
|
|
|
|
|
|
top: '10%',
|
|
|
|
|
|
containLabel: true
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'category',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
2025-10-17 14:57:09 +08:00
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: 'rgba(255, 255, 255, 0.3)',
|
|
|
|
|
|
type: 'dashed'
|
|
|
|
|
|
}
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisTick: { show: false }
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'value',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
2025-10-17 14:57:09 +08:00
|
|
|
|
axisLine: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
show: false
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
splitLine: {
|
|
|
|
|
|
lineStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: 'rgba(255, 255, 255, 0.15)',
|
|
|
|
|
|
type: 'dashed'
|
|
|
|
|
|
}
|
2025-10-18 16:58:04 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisTick: { show: false }
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
2026-01-24 14:23:35 +08:00
|
|
|
|
name: '人均任务数',
|
|
|
|
|
|
type: 'bar',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
barWidth: '40%',
|
2025-10-17 14:57:09 +08:00
|
|
|
|
itemStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
color: '#00FFB8'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 0.5,
|
|
|
|
|
|
color: '#00D4FF'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1,
|
|
|
|
|
|
color: '#00A8FF'
|
|
|
|
|
|
}]),
|
|
|
|
|
|
borderRadius: [2, 2, 0, 0]
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
label: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'top',
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2025-10-18 16:58:04 +08:00
|
|
|
|
};
|
2025-10-17 14:57:09 +08:00
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
avgTasksChart.setOption(option);
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式调整
|
|
|
|
|
|
window.addEventListener('resize', debounce(function () {
|
|
|
|
|
|
if (avgTasksChart) {
|
|
|
|
|
|
avgTasksChart.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300));
|
2025-10-17 14:57:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 更新各工种人均任务数柱状图
|
|
|
|
|
|
function updateAvgTasksChart(data) {
|
|
|
|
|
|
if (!avgTasksChart || !data || !Array.isArray(data) || data.length === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提取工种类型和任务数
|
|
|
|
|
|
const categories = data.map(item => item.workType || '');
|
|
|
|
|
|
const taskNums = data.map(item => parseFloat(item.taskNum || 0));
|
|
|
|
|
|
|
|
|
|
|
|
// 计算y轴最大值(向上取整到最近的10的倍数)
|
|
|
|
|
|
const maxValue = Math.max(...taskNums, 0);
|
|
|
|
|
|
const yAxisMax = maxValue > 0 ? Math.ceil(maxValue / 10) * 10 : 10;
|
|
|
|
|
|
const interval = Math.ceil(yAxisMax / 5);
|
|
|
|
|
|
|
|
|
|
|
|
avgTasksChart.setOption({
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
data: categories
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
max: yAxisMax,
|
|
|
|
|
|
interval: interval
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
data: taskNums
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化各设备使用率折线图
|
|
|
|
|
|
function initEquipmentUsageChart() {
|
|
|
|
|
|
const chartDom = document.getElementById('equipmentUsageChart');
|
|
|
|
|
|
if (!chartDom) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (equipmentUsageChart) {
|
|
|
|
|
|
equipmentUsageChart.dispose();
|
2025-10-17 14:57:09 +08:00
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
equipmentUsageChart = echarts.init(chartDom);
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 初始化为空数据
|
2025-10-17 14:57:09 +08:00
|
|
|
|
const option = {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
backgroundColor: 'transparent',
|
2025-10-17 14:57:09 +08:00
|
|
|
|
tooltip: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
trigger: 'axis',
|
|
|
|
|
|
backgroundColor: 'rgba(13, 34, 37, 0.95)',
|
|
|
|
|
|
borderColor: 'rgba(6, 189, 221, 0.8)',
|
|
|
|
|
|
borderWidth: 1,
|
|
|
|
|
|
borderRadius: 4,
|
|
|
|
|
|
padding: [12, 16],
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: ['入场天数', '使用天数'],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
top: '5%',
|
|
|
|
|
|
right: '5%',
|
|
|
|
|
|
textStyle: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
2025-10-18 16:58:04 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
itemWidth: 12,
|
|
|
|
|
|
itemHeight: 12
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
grid: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
left: '10%',
|
|
|
|
|
|
right: '10%',
|
|
|
|
|
|
bottom: '15%',
|
|
|
|
|
|
top: '20%',
|
|
|
|
|
|
containLabel: true
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
xAxis: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'category',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
2025-10-17 14:57:09 +08:00
|
|
|
|
axisLine: {
|
|
|
|
|
|
lineStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: 'rgba(255, 255, 255, 0.3)',
|
|
|
|
|
|
type: 'dashed'
|
|
|
|
|
|
}
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisTick: { show: false }
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'value',
|
|
|
|
|
|
min: 0,
|
|
|
|
|
|
axisLabel: {
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
2025-10-17 14:57:09 +08:00
|
|
|
|
axisLine: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
show: false
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
splitLine: {
|
|
|
|
|
|
lineStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: 'rgba(255, 255, 255, 0.15)',
|
|
|
|
|
|
type: 'dashed'
|
|
|
|
|
|
}
|
2025-10-18 16:58:04 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
axisTick: { show: false }
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
2026-01-24 17:14:53 +08:00
|
|
|
|
name: '入场天数',
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'line',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: [],
|
2025-10-17 14:57:09 +08:00
|
|
|
|
itemStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: '#00FFB8'
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
lineStyle: {
|
|
|
|
|
|
width: 2,
|
|
|
|
|
|
color: '#00FFB8'
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
symbol: 'circle',
|
|
|
|
|
|
symbolSize: 6,
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
color: 'rgba(0, 255, 184, 0.3)'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1,
|
|
|
|
|
|
color: 'rgba(0, 255, 184, 0.05)'
|
|
|
|
|
|
}])
|
|
|
|
|
|
}
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
2026-01-24 17:14:53 +08:00
|
|
|
|
name: '使用天数',
|
2026-01-24 14:23:35 +08:00
|
|
|
|
type: 'line',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
data: [],
|
2025-10-17 14:57:09 +08:00
|
|
|
|
itemStyle: {
|
2026-01-24 14:23:35 +08:00
|
|
|
|
color: '#50E3C2'
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
lineStyle: {
|
|
|
|
|
|
width: 2,
|
|
|
|
|
|
color: '#50E3C2'
|
2025-10-17 14:57:09 +08:00
|
|
|
|
},
|
2026-01-24 14:23:35 +08:00
|
|
|
|
symbol: 'circle',
|
|
|
|
|
|
symbolSize: 6,
|
|
|
|
|
|
areaStyle: {
|
|
|
|
|
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
|
|
|
|
|
offset: 0,
|
|
|
|
|
|
color: 'rgba(80, 227, 194, 0.3)'
|
|
|
|
|
|
}, {
|
|
|
|
|
|
offset: 1,
|
|
|
|
|
|
color: 'rgba(80, 227, 194, 0.05)'
|
|
|
|
|
|
}])
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2025-10-18 16:58:04 +08:00
|
|
|
|
};
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
equipmentUsageChart.setOption(option);
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式调整
|
|
|
|
|
|
window.addEventListener('resize', debounce(function () {
|
|
|
|
|
|
if (equipmentUsageChart) {
|
|
|
|
|
|
equipmentUsageChart.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 更新各设备使用率折线图
|
|
|
|
|
|
function updateEquipmentUsageChart(data) {
|
|
|
|
|
|
if (!equipmentUsageChart || !data || !Array.isArray(data) || data.length === 0) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提取设备名称、入场天数和使用天数
|
|
|
|
|
|
const categories = data.map(item => item.devName || '');
|
|
|
|
|
|
const usedDayData = data.map(item => parseFloat(item.usedDay || 0));
|
|
|
|
|
|
const usedNumData = data.map(item => parseFloat(item.usedNum || 0));
|
|
|
|
|
|
|
|
|
|
|
|
// 计算y轴最大值(向上取整到最近的10的倍数)
|
|
|
|
|
|
const maxValue = Math.max(...usedDayData, ...usedNumData, 0);
|
|
|
|
|
|
const yAxisMax = maxValue > 0 ? Math.ceil(maxValue / 10) * 10 : 10;
|
|
|
|
|
|
const interval = Math.ceil(yAxisMax / 5);
|
|
|
|
|
|
|
|
|
|
|
|
equipmentUsageChart.setOption({
|
|
|
|
|
|
xAxis: {
|
|
|
|
|
|
data: categories
|
|
|
|
|
|
},
|
|
|
|
|
|
yAxis: {
|
|
|
|
|
|
max: yAxisMax,
|
|
|
|
|
|
interval: interval
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '入场天数',
|
|
|
|
|
|
data: usedDayData
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '使用天数',
|
|
|
|
|
|
data: usedNumData
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化设备故障排名列表
|
|
|
|
|
|
function initEquipmentFailureList() {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 初始化为空,等待接口数据
|
|
|
|
|
|
const container = document.getElementById('equipmentFailureList');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新设备故障排名列表
|
|
|
|
|
|
function updateEquipmentFailureList(data) {
|
|
|
|
|
|
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
|
|
|
|
const container = document.getElementById('equipmentFailureList');
|
|
|
|
|
|
if (container) {
|
|
|
|
|
|
container.innerHTML = '';
|
|
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
|
|
|
|
|
const container = document.getElementById('equipmentFailureList');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
|
|
|
|
const html = data.map(function (item) {
|
2026-01-24 17:14:53 +08:00
|
|
|
|
const devName = item.devName || '';
|
2026-01-26 10:47:02 +08:00
|
|
|
|
const remark = item.errNum || '0';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
return `
|
|
|
|
|
|
<div class="failure-item">
|
2026-01-24 17:14:53 +08:00
|
|
|
|
<span class="failure-equipment">${devName}</span>
|
|
|
|
|
|
<span class="failure-count">累计故障${remark}次</span>
|
2026-01-24 14:23:35 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 17:14:53 +08:00
|
|
|
|
// 初始化分析预警表格(无分页)
|
2026-01-24 14:23:35 +08:00
|
|
|
|
function initWarningTable() {
|
|
|
|
|
|
table.render({
|
|
|
|
|
|
elem: '#warningTable',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
id: 'warningTable',
|
|
|
|
|
|
data: [],
|
2026-01-24 14:23:35 +08:00
|
|
|
|
skin: 'line',
|
|
|
|
|
|
page: false,
|
|
|
|
|
|
height: 'full',
|
|
|
|
|
|
cols: [[
|
|
|
|
|
|
{ type: 'numbers', title: '序号', width: '10%', align: 'center' },
|
2026-01-24 17:14:53 +08:00
|
|
|
|
{ field: 'txTime', title: '预警时间', width: '20%', align: 'center' },
|
|
|
|
|
|
{ field: 'content', title: '预警内容', width: '50%', align: 'left' },
|
2026-01-24 14:23:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
title: '操作',
|
2026-01-24 17:14:53 +08:00
|
|
|
|
width: '20%',
|
2026-01-24 14:23:35 +08:00
|
|
|
|
align: 'center',
|
|
|
|
|
|
templet: function (d) {
|
2026-01-24 19:13:29 +08:00
|
|
|
|
// 将完整的 warning 对象数据编码后传递
|
|
|
|
|
|
const warningData = encodeURIComponent(JSON.stringify({
|
|
|
|
|
|
id: d.id || '',
|
|
|
|
|
|
measureData: d.measureData || '',
|
|
|
|
|
|
filePath: d.filePath || ''
|
|
|
|
|
|
}));
|
|
|
|
|
|
return '<a href="javascript:void(0)" style="color: #00FFB8;" onclick="formulateStrategy(\'' + warningData + '\')">制定策略</a>';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
]]
|
2025-10-17 14:57:09 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
|
2026-01-24 19:13:29 +08:00
|
|
|
|
// 制定策略相关变量
|
|
|
|
|
|
let currentWarningId = null;
|
|
|
|
|
|
let selectedFile = null;
|
|
|
|
|
|
let originalFilePath = null; // 保存原始文件路径
|
|
|
|
|
|
|
|
|
|
|
|
// 打开制定策略弹框
|
|
|
|
|
|
function formulateStrategy(warningDataStr) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 解析传递过来的 warning 数据
|
|
|
|
|
|
const warningData = JSON.parse(decodeURIComponent(warningDataStr));
|
|
|
|
|
|
currentWarningId = warningData.id || '';
|
|
|
|
|
|
selectedFile = null;
|
|
|
|
|
|
originalFilePath = warningData.filePath || null;
|
|
|
|
|
|
|
|
|
|
|
|
// 回显应对措施
|
|
|
|
|
|
const measureData = warningData.measureData || '';
|
|
|
|
|
|
$('#measureDataInput').val(measureData);
|
|
|
|
|
|
|
|
|
|
|
|
// 回显文件路径
|
|
|
|
|
|
$('#fileInput').val('');
|
|
|
|
|
|
if (originalFilePath) {
|
|
|
|
|
|
// 从文件路径中提取文件名
|
|
|
|
|
|
const fileName = originalFilePath.split('/').pop() || originalFilePath.split('\\').pop() || '已上传文件';
|
|
|
|
|
|
$('#fileInfo').html('<span style="color: #00FFB8;">已上传文件: ' + fileName + '</span> <span style="color: rgba(255,255,255,0.6); margin-left: 10px;">(点击上传文件可替换)</span>');
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$('#fileInfo').text('');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示弹框
|
|
|
|
|
|
$('#strategyModal').addClass('show');
|
|
|
|
|
|
} catch (e) {
|
|
|
|
|
|
console.error('解析预警数据失败:', e);
|
|
|
|
|
|
// 如果解析失败,使用旧的方式(兼容性处理)
|
|
|
|
|
|
currentWarningId = warningDataStr;
|
|
|
|
|
|
selectedFile = null;
|
|
|
|
|
|
originalFilePath = null;
|
|
|
|
|
|
$('#measureDataInput').val('');
|
|
|
|
|
|
$('#fileInput').val('');
|
|
|
|
|
|
$('#fileInfo').text('');
|
|
|
|
|
|
$('#strategyModal').addClass('show');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭制定策略弹框
|
|
|
|
|
|
function closeStrategyModal() {
|
|
|
|
|
|
$('#strategyModal').removeClass('show');
|
|
|
|
|
|
currentWarningId = null;
|
|
|
|
|
|
selectedFile = null;
|
|
|
|
|
|
originalFilePath = null;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置表单
|
|
|
|
|
|
$('#measureDataInput').val('');
|
|
|
|
|
|
$('#fileInput').val('');
|
|
|
|
|
|
$('#fileInfo').text('');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化文件选择处理(在 layui 初始化后)
|
|
|
|
|
|
function initFileUploadHandler() {
|
|
|
|
|
|
$('#fileInput').on('change', function (e) {
|
|
|
|
|
|
const file = e.target.files[0];
|
|
|
|
|
|
if (file) {
|
|
|
|
|
|
// 检查文件大小(20MB = 20 * 1024 * 1024 字节)
|
|
|
|
|
|
const maxSize = 20 * 1024 * 1024;
|
|
|
|
|
|
if (file.size > maxSize) {
|
|
|
|
|
|
if (layer) {
|
|
|
|
|
|
layer.msg('文件大小不能超过20MB', { icon: 2 });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('文件大小不能超过20MB');
|
|
|
|
|
|
}
|
|
|
|
|
|
$(this).val('');
|
|
|
|
|
|
selectedFile = null;
|
|
|
|
|
|
$('#fileInfo').text('');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 检查文件格式
|
|
|
|
|
|
const allowedExtensions = ['.doc', '.docx', '.pdf', '.jpg', '.png'];
|
|
|
|
|
|
const fileName = file.name.toLowerCase();
|
|
|
|
|
|
const isValidFormat = allowedExtensions.some(ext => fileName.endsWith(ext));
|
|
|
|
|
|
|
|
|
|
|
|
if (!isValidFormat) {
|
|
|
|
|
|
if (layer) {
|
|
|
|
|
|
layer.msg('不支持的文件格式,请上传 .doc .docx .pdf .jpg .png 格式的文件', { icon: 2 });
|
|
|
|
|
|
} else {
|
|
|
|
|
|
alert('不支持的文件格式,请上传 .doc .docx .pdf .jpg .png 格式的文件');
|
|
|
|
|
|
}
|
|
|
|
|
|
$(this).val('');
|
|
|
|
|
|
selectedFile = null;
|
|
|
|
|
|
$('#fileInfo').text('');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
selectedFile = file;
|
|
|
|
|
|
// 如果选择了新文件,清除原始文件路径标记
|
|
|
|
|
|
originalFilePath = null;
|
|
|
|
|
|
$('#fileInfo').html('<span style="color: #00FFB8;">已选择文件: ' + file.name + ' (' + formatFileSize(file.size) + ')</span>');
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化文件大小
|
|
|
|
|
|
function formatFileSize(bytes) {
|
|
|
|
|
|
if (bytes === 0) return '0 Bytes';
|
|
|
|
|
|
const k = 1024;
|
|
|
|
|
|
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
|
|
|
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
|
|
return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 提交制定策略
|
|
|
|
|
|
function submitStrategy() {
|
|
|
|
|
|
const measureData = $('#measureDataInput').val().trim();
|
|
|
|
|
|
|
|
|
|
|
|
// 验证应对措施必填
|
|
|
|
|
|
if (!measureData) {
|
|
|
|
|
|
layer.msg('请输入应对措施', { icon: 2 });
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建 FormData
|
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
|
formData.append('measureData', measureData);
|
|
|
|
|
|
|
|
|
|
|
|
// 传递预警ID(必传字段)
|
|
|
|
|
|
formData.append('id', currentWarningId || '');
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有新选择的文件,添加到 FormData
|
|
|
|
|
|
if (selectedFile) {
|
|
|
|
|
|
formData.append('file', selectedFile);
|
|
|
|
|
|
} else if (originalFilePath) {
|
|
|
|
|
|
// 如果没有选择新文件,但有原始文件路径,传递原始文件路径(如果需要保留原文件)
|
|
|
|
|
|
// 注意:根据后端接口需求,可能需要传递 filePath 字段
|
|
|
|
|
|
formData.append('filePath', originalFilePath);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 发送 POST 请求
|
|
|
|
|
|
const url = commonUrl + 'screen/largeScreen/sjNewOverall/uploadFile';
|
|
|
|
|
|
|
|
|
|
|
|
$.ajax({
|
|
|
|
|
|
url: url,
|
|
|
|
|
|
type: 'POST',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
"authorization": sessionStorage.getItem("zhgd_token"),
|
|
|
|
|
|
"decrypt": 'decrypt'
|
|
|
|
|
|
},
|
|
|
|
|
|
data: formData,
|
|
|
|
|
|
processData: false,
|
|
|
|
|
|
contentType: false,
|
|
|
|
|
|
beforeSend: function () {
|
|
|
|
|
|
layer.load(2);
|
|
|
|
|
|
},
|
|
|
|
|
|
success: function (result) {
|
|
|
|
|
|
layer.closeAll('loading');
|
|
|
|
|
|
// 由于使用了 ajaxSetup 拦截器,result 已经被 modifyResponseData 处理过了
|
|
|
|
|
|
const response = result;
|
|
|
|
|
|
|
|
|
|
|
|
if (response && (response.code === 200 || response.success || response.status === 200)) {
|
|
|
|
|
|
layer.msg('提交成功', { icon: 1 });
|
|
|
|
|
|
closeStrategyModal();
|
|
|
|
|
|
// 刷新预警列表
|
|
|
|
|
|
getAnalysisWarning();
|
|
|
|
|
|
} else {
|
|
|
|
|
|
layer.msg(response.msg || response.message || '提交失败,请重试', { icon: 2 });
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
error: function (xhr, status, error) {
|
|
|
|
|
|
layer.closeAll('loading');
|
|
|
|
|
|
layer.msg('提交失败,请检查网络连接', { icon: 2 });
|
|
|
|
|
|
console.error('提交失败:', error);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化模拟数据(后续替换为真实接口数据)
|
|
|
|
|
|
function initMockData() {
|
|
|
|
|
|
// 人员数据表格使用layui table的url自动加载
|
|
|
|
|
|
// 其他模块数据已在各自的init函数中初始化
|
|
|
|
|
|
}
|