2026-01-24 14:23:35 +08:00
|
|
|
|
let table, layer, form, laydate;
|
|
|
|
|
|
let delayDistributionChart = null;
|
|
|
|
|
|
let bidCode = parent.parent.$('#bidPro').val();
|
2026-01-24 18:55:45 +08:00
|
|
|
|
let modalKeyword = '';
|
|
|
|
|
|
let modalTaskStatus = '';
|
|
|
|
|
|
let modalQueryParams = {
|
|
|
|
|
|
projectId: bidCode,
|
|
|
|
|
|
startTestDay: '',
|
|
|
|
|
|
endTestDay: '',
|
|
|
|
|
|
taskStatus: ''
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当天日期
|
|
|
|
|
|
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
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 获取当月第一天和最后一天(保留用于其他功能)
|
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,
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
layui.use(["layer", "table", "form", "laydate"], function () {
|
|
|
|
|
|
layer = layui.layer;
|
|
|
|
|
|
table = layui.table;
|
|
|
|
|
|
form = layui.form;
|
|
|
|
|
|
laydate = layui.laydate;
|
|
|
|
|
|
|
|
|
|
|
|
// 响应成功后的拦截器
|
|
|
|
|
|
$.ajaxSetup({
|
|
|
|
|
|
beforeSend: function (xhr, options) {
|
|
|
|
|
|
var originalSuccess = options.success;
|
|
|
|
|
|
options.success = function (data, textStatus, jqXhr) {
|
|
|
|
|
|
data = modifyResponseData(data);
|
|
|
|
|
|
originalSuccess.apply(this, arguments);
|
|
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化页面
|
|
|
|
|
|
initPage();
|
|
|
|
|
|
// 初始化日期范围选择器
|
|
|
|
|
|
initDateRangePicker();
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 获取左上角近七天用电趋势
|
|
|
|
|
|
function getElectricTrend() {
|
2026-01-27 18:06:23 +08:00
|
|
|
|
const url = commonUrl + "screen/worker/analysis/summary?projectId=" + bidCode + "&startTestDay=" + '' + "&endTestDay=" + '';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
ajaxRequestGet(url, "GET", true, function () {
|
|
|
|
|
|
|
|
|
|
|
|
}, function (result) {
|
|
|
|
|
|
console.log(result, '近七天用电趋势');
|
|
|
|
|
|
if (result) {
|
|
|
|
|
|
updateElectricTrendData(result.data);
|
|
|
|
|
|
}
|
|
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新近七天用电趋势数据
|
|
|
|
|
|
function updateElectricTrendData(data) {
|
|
|
|
|
|
const totalCount = data.totalCount || 0;
|
|
|
|
|
|
const finishedCount = data.finishedCount || 0;
|
|
|
|
|
|
const processingCount = data.processingCount || 0;
|
|
|
|
|
|
const notStartedCount = data.notStartedCount || 0;
|
|
|
|
|
|
const delayCount = data.delayCount || 0;
|
|
|
|
|
|
|
|
|
|
|
|
// 更新中心的任务总数
|
|
|
|
|
|
$('#totalTasks').text(totalCount);
|
|
|
|
|
|
|
|
|
|
|
|
// 计算百分比(保留2位小数)
|
|
|
|
|
|
const calculatePercent = function (count, total) {
|
|
|
|
|
|
if (total === 0) return '0.00';
|
|
|
|
|
|
return ((count / total) * 100).toFixed(2);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 更新四个方向的显示:数量 + 百分比
|
|
|
|
|
|
const finishedPercent = calculatePercent(finishedCount, totalCount);
|
|
|
|
|
|
$('#completedPercent').text(finishedCount + ' ' + finishedPercent + '%');
|
|
|
|
|
|
|
|
|
|
|
|
const processingPercent = calculatePercent(processingCount, totalCount);
|
|
|
|
|
|
$('#inProgressPercent').text(processingCount + ' ' + processingPercent + '%');
|
|
|
|
|
|
|
|
|
|
|
|
const notStartedPercent = calculatePercent(notStartedCount, totalCount);
|
|
|
|
|
|
$('#notStartedPercent').text(notStartedCount + ' ' + notStartedPercent + '%');
|
|
|
|
|
|
|
|
|
|
|
|
const delayPercent = calculatePercent(delayCount, totalCount);
|
|
|
|
|
|
$('#delayedPercent').text(delayCount + ' ' + delayPercent + '%');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取右上角月工种任务分布
|
|
|
|
|
|
function getTaskDistribution() {
|
2026-01-27 18:06:23 +08:00
|
|
|
|
const url = commonUrl + "screen/worker/analysis/gzsummary?projectId=" + bidCode + "&startTestDay=" + '' + "&endTestDay=" + '';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
ajaxRequestGet(url, "GET", true, function () {
|
|
|
|
|
|
|
|
|
|
|
|
}, function (result) {
|
|
|
|
|
|
console.log(result, '月工种任务分布');
|
2026-01-24 18:55:45 +08:00
|
|
|
|
let data = result;
|
|
|
|
|
|
if (result && result.data) {
|
|
|
|
|
|
data = result.data;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (data) {
|
|
|
|
|
|
// 更新顶部两个指标
|
|
|
|
|
|
const totalPerson = data.totalPerson || 0;
|
|
|
|
|
|
const totalTask = data.totalTask || 0;
|
|
|
|
|
|
$('#taskPersonnel').text(totalPerson);
|
|
|
|
|
|
$('#avgTasks').text(totalTask);
|
|
|
|
|
|
|
|
|
|
|
|
// 处理 taskCountByWorkType 对象
|
|
|
|
|
|
const taskCountByWorkType = data.taskCountByWorkType || {};
|
|
|
|
|
|
const jobTypeList = Object.keys(taskCountByWorkType).map(key => ({
|
|
|
|
|
|
name: key,
|
|
|
|
|
|
value: '人均' + (taskCountByWorkType[key] || 0) + '任务'
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
updateJobTypeDistribution(jobTypeList);
|
|
|
|
|
|
}
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取左下角月任务延期排名top5
|
|
|
|
|
|
function getTaskDelayRanking() {
|
2026-01-27 18:06:23 +08:00
|
|
|
|
const url = commonUrl + "screen/worker/analysis/delay/person?projectId=" + bidCode + "&startTestDay=" + '' + "&endTestDay=" + '';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
ajaxRequestGet(url, "GET", true, function () {
|
|
|
|
|
|
|
|
|
|
|
|
}, function (result) {
|
|
|
|
|
|
console.log(result, '月任务延期排名top5');
|
2026-01-24 18:55:45 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换数据格式:{ userName, delayCount } -> { name, count }
|
|
|
|
|
|
const formattedData = data.map(item => ({
|
|
|
|
|
|
name: item.userName || '',
|
|
|
|
|
|
count: parseInt(item.delayCount) || 0
|
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
|
|
updateDelayRanking(formattedData);
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取下方中间的月任务延期分布
|
|
|
|
|
|
function getTaskDelayDistribution() {
|
2026-01-27 18:06:23 +08:00
|
|
|
|
const url = commonUrl + "screen/worker/analysis/delay/workType?projectId=" + bidCode + "&startTestDay=" + '' + "&endTestDay=" + '';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
ajaxRequestGet(url, "GET", true, function () {
|
|
|
|
|
|
|
|
|
|
|
|
}, function (result) {
|
|
|
|
|
|
console.log(result, '月任务延期分布');
|
2026-01-24 18:55:45 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 转换数据格式并计算百分比
|
|
|
|
|
|
const totalDelayCount = data.reduce((sum, item) => sum + (parseInt(item.delayCount) || 0), 0);
|
|
|
|
|
|
const formattedData = data.map(item => {
|
|
|
|
|
|
const delayCount = parseInt(item.delayCount) || 0;
|
|
|
|
|
|
const percentage = totalDelayCount > 0 ? ((delayCount / totalDelayCount) * 100).toFixed(2) : 0;
|
|
|
|
|
|
return {
|
|
|
|
|
|
name: item.workType || '',
|
|
|
|
|
|
value: parseFloat(percentage)
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
updateDelayDistributionChart(formattedData);
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取右下方分析预警
|
|
|
|
|
|
function getAnalysisWarning() {
|
2026-01-27 18:06:23 +08:00
|
|
|
|
const url = commonUrl + "screen/worker/analysis/yujingdetail?projectId=" + bidCode + "&startTestDay=" + '' + "&endTestDay=" + '';
|
2026-01-24 14:23:35 +08:00
|
|
|
|
ajaxRequestGet(url, "GET", true, function () {
|
|
|
|
|
|
|
|
|
|
|
|
}, function (result) {
|
|
|
|
|
|
console.log(result, '分析预警');
|
2026-01-24 18:55:45 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
updateWarningList(data);
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}, aqEnnable);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取数据(在页面初始化时调用)
|
|
|
|
|
|
// getElectricTrend();
|
|
|
|
|
|
// getTaskDistribution();
|
|
|
|
|
|
// getTaskDelayRanking();
|
|
|
|
|
|
// getTaskDelayDistribution();
|
|
|
|
|
|
// getAnalysisWarning();
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化页面
|
|
|
|
|
|
function initPage() {
|
|
|
|
|
|
initDelayDistributionChart();
|
|
|
|
|
|
initMockData();
|
|
|
|
|
|
// 调用接口获取真实数据
|
|
|
|
|
|
getElectricTrend();
|
|
|
|
|
|
getTaskDistribution();
|
|
|
|
|
|
getTaskDelayRanking();
|
|
|
|
|
|
getTaskDelayDistribution();
|
|
|
|
|
|
getAnalysisWarning();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 防抖函数
|
|
|
|
|
|
function debounce(func, wait) {
|
|
|
|
|
|
let timeout;
|
|
|
|
|
|
return function executedFunction(...args) {
|
|
|
|
|
|
const later = () => {
|
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
func(...args);
|
|
|
|
|
|
};
|
|
|
|
|
|
clearTimeout(timeout);
|
|
|
|
|
|
timeout = setTimeout(later, wait);
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化日期范围选择器
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
|
|
// 使用范围选择器,单个输入框显示日期范围
|
|
|
|
|
|
laydate.render({
|
|
|
|
|
|
elem: '#dateRange',
|
|
|
|
|
|
type: 'date',
|
|
|
|
|
|
range: true, // 启用范围选择
|
|
|
|
|
|
format: 'yyyy-MM-dd',
|
|
|
|
|
|
theme: 'dark',
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 默认值使用当天范围
|
2026-01-24 14:23:35 +08:00
|
|
|
|
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;
|
|
|
|
|
|
$('#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();
|
|
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 在单个输入框中显示日期范围(格式:2026-01-15 ~ 2026-01-15)
|
2026-01-24 14:23:35 +08:00
|
|
|
|
$('#dateRange').val(startDate + ' ~ ' + endDateStr);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新查询参数
|
|
|
|
|
|
queryParams.startTestDay = startDate;
|
|
|
|
|
|
queryParams.endTestDay = endDateStr;
|
|
|
|
|
|
|
|
|
|
|
|
// 日期变化后,重新调用所有模块接口
|
|
|
|
|
|
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() {
|
|
|
|
|
|
// 重新调用所有接口
|
|
|
|
|
|
getElectricTrend();
|
|
|
|
|
|
getTaskDistribution();
|
|
|
|
|
|
getTaskDelayRanking();
|
|
|
|
|
|
getTaskDelayDistribution();
|
|
|
|
|
|
getAnalysisWarning();
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 注意:不再重新初始化图表,而是通过各自的更新函数来更新
|
2026-01-24 14:23:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化月任务延期分布饼图
|
|
|
|
|
|
function initDelayDistributionChart() {
|
|
|
|
|
|
const chartDom = document.getElementById('delayDistributionChart');
|
|
|
|
|
|
if (!chartDom) return;
|
|
|
|
|
|
|
|
|
|
|
|
if (delayDistributionChart) {
|
|
|
|
|
|
delayDistributionChart.dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
delayDistributionChart = echarts.init(chartDom);
|
|
|
|
|
|
|
|
|
|
|
|
// 模拟数据 - 后续替换为真实接口数据
|
|
|
|
|
|
const data = [
|
|
|
|
|
|
{ value: 15.87, name: '架子工' },
|
|
|
|
|
|
{ value: 26.50, name: '高空作业工' },
|
|
|
|
|
|
{ value: 23.14, name: 'XX工' },
|
|
|
|
|
|
{ value: 20.50, name: 'XX工' },
|
|
|
|
|
|
{ value: 10.28, name: 'XX工' }
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const option = {
|
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
|
tooltip: {
|
|
|
|
|
|
trigger: 'item',
|
|
|
|
|
|
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
|
|
|
|
|
|
},
|
|
|
|
|
|
formatter: function (params) {
|
|
|
|
|
|
return `${params.name}<br/>${params.value}%`;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
legend: {
|
|
|
|
|
|
show: false
|
|
|
|
|
|
},
|
|
|
|
|
|
series: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: '月任务延期分布',
|
|
|
|
|
|
type: 'pie',
|
|
|
|
|
|
radius: ['40%', '70%'],
|
|
|
|
|
|
center: ['50%', '50%'],
|
|
|
|
|
|
avoidLabelOverlap: false,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
borderRadius: 4,
|
|
|
|
|
|
borderColor: 'transparent',
|
|
|
|
|
|
borderWidth: 0
|
|
|
|
|
|
},
|
|
|
|
|
|
label: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
position: 'outside',
|
|
|
|
|
|
formatter: function (params) {
|
|
|
|
|
|
return params.name + ': ' + params.value + '%';
|
|
|
|
|
|
},
|
|
|
|
|
|
color: '#FFFFFF',
|
|
|
|
|
|
fontSize: 12
|
|
|
|
|
|
},
|
|
|
|
|
|
labelLine: {
|
|
|
|
|
|
show: true,
|
|
|
|
|
|
lineStyle: {
|
|
|
|
|
|
color: 'rgba(255, 255, 255, 0.5)'
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
data: data.map(function (item, index) {
|
|
|
|
|
|
const colors = [
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#00FFD4' },
|
|
|
|
|
|
{ offset: 1, color: '#00A8FF' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#FF9C65' },
|
|
|
|
|
|
{ offset: 1, color: '#FFD700' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#50E3C2' },
|
|
|
|
|
|
{ offset: 1, color: '#00D4FF' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#87CEEB' },
|
|
|
|
|
|
{ offset: 1, color: '#4A90E2' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#FF6B6B' },
|
|
|
|
|
|
{ offset: 1, color: '#FF8E53' }
|
|
|
|
|
|
])
|
|
|
|
|
|
];
|
|
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: colors[index % colors.length]
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
delayDistributionChart.setOption(option);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新图例
|
|
|
|
|
|
updateDelayLegend(data);
|
|
|
|
|
|
|
|
|
|
|
|
// 响应式调整
|
|
|
|
|
|
window.addEventListener('resize', debounce(function () {
|
|
|
|
|
|
if (delayDistributionChart) {
|
|
|
|
|
|
delayDistributionChart.resize();
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 300));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新延期分布图例
|
|
|
|
|
|
function updateDelayLegend(data) {
|
|
|
|
|
|
const legendContainer = document.getElementById('delayLegend');
|
|
|
|
|
|
if (!legendContainer) return;
|
|
|
|
|
|
|
|
|
|
|
|
const colors = ['#00FFD4', '#FF9C65', '#50E3C2', '#87CEEB', '#FF6B6B'];
|
|
|
|
|
|
const legendHtml = data.map(function (item, index) {
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="legend-item">
|
|
|
|
|
|
<span class="legend-dot" style="background-color: ${colors[index % colors.length]}"></span>
|
|
|
|
|
|
<span class="legend-label">${item.name}</span>
|
|
|
|
|
|
<span class="legend-value">${item.value}%</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
legendContainer.innerHTML = legendHtml;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 更新月任务延期分布饼图
|
|
|
|
|
|
function updateDelayDistributionChart(data) {
|
|
|
|
|
|
if (!delayDistributionChart) {
|
|
|
|
|
|
initDelayDistributionChart();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!data || data.length === 0) {
|
|
|
|
|
|
// 如果没有数据,使用空数组
|
|
|
|
|
|
delayDistributionChart.setOption({
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
data: []
|
|
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
updateDelayLegend([]);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const colors = [
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#00FFD4' },
|
|
|
|
|
|
{ offset: 1, color: '#00A8FF' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#FF9C65' },
|
|
|
|
|
|
{ offset: 1, color: '#FFD700' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#50E3C2' },
|
|
|
|
|
|
{ offset: 1, color: '#00D4FF' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#87CEEB' },
|
|
|
|
|
|
{ offset: 1, color: '#4A90E2' }
|
|
|
|
|
|
]),
|
|
|
|
|
|
new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
|
|
|
|
|
{ offset: 0, color: '#FF6B6B' },
|
|
|
|
|
|
{ offset: 1, color: '#FF8E53' }
|
|
|
|
|
|
])
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const chartData = data.map(function (item, index) {
|
|
|
|
|
|
return {
|
|
|
|
|
|
...item,
|
|
|
|
|
|
itemStyle: {
|
|
|
|
|
|
color: colors[index % colors.length]
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
delayDistributionChart.setOption({
|
|
|
|
|
|
series: [{
|
|
|
|
|
|
data: chartData
|
|
|
|
|
|
}]
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 更新图例
|
|
|
|
|
|
updateDelayLegend(data);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化模拟数据(后续替换为真实接口数据)
|
|
|
|
|
|
function initMockData() {
|
|
|
|
|
|
// 模块1:任务统计
|
|
|
|
|
|
updateTaskStatistics({
|
|
|
|
|
|
total: 233,
|
|
|
|
|
|
completed: 47,
|
|
|
|
|
|
inProgress: 47,
|
|
|
|
|
|
notStarted: 47,
|
|
|
|
|
|
delayed: 47
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// 模块2:工种任务分布
|
|
|
|
|
|
updateJobTypeDistribution([
|
|
|
|
|
|
{ name: '挖掘机', value: '人均2.5任务' },
|
|
|
|
|
|
{ name: '滤油机', value: '人均2.0任务' },
|
|
|
|
|
|
{ name: '架子工', value: '人均1.8任务' },
|
|
|
|
|
|
{ name: '高空作业工', value: '人均1.5任务' },
|
|
|
|
|
|
{ name: 'XX工', value: '人均1.2任务' }
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// 模块3:延期排名TOP5
|
|
|
|
|
|
updateDelayRanking([
|
|
|
|
|
|
{ name: '李铮辉', count: 15 },
|
|
|
|
|
|
{ name: '何颖顾', count: 12 },
|
|
|
|
|
|
{ name: '张三', count: 10 },
|
|
|
|
|
|
{ name: '李四', count: 8 },
|
|
|
|
|
|
{ name: '王五', count: 6 }
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
|
|
// 模块5:分析预警
|
|
|
|
|
|
initWarningList();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新任务统计(模块1)
|
|
|
|
|
|
function updateTaskStatistics(data) {
|
|
|
|
|
|
const total = data.total || 0;
|
|
|
|
|
|
const completed = data.completed || 0;
|
|
|
|
|
|
const inProgress = data.inProgress || 0;
|
|
|
|
|
|
const notStarted = data.notStarted || 0;
|
|
|
|
|
|
const delayed = data.delayed || 0;
|
|
|
|
|
|
|
|
|
|
|
|
$('#totalTasks').text(total);
|
|
|
|
|
|
$('#completedTasks').text(completed);
|
|
|
|
|
|
$('#inProgressTasks').text(inProgress);
|
|
|
|
|
|
$('#notStartedTasks').text(notStarted);
|
|
|
|
|
|
$('#delayedTasks').text(delayed);
|
|
|
|
|
|
|
|
|
|
|
|
// 更新百分比
|
|
|
|
|
|
const totalCount = total || 1;
|
|
|
|
|
|
$('.hexagon-top .hexagon-percent').text(Math.round((completed / totalCount) * 100) + '%');
|
|
|
|
|
|
$('.hexagon-left .hexagon-percent').text(Math.round((inProgress / totalCount) * 100) + '%');
|
|
|
|
|
|
$('.hexagon-right .hexagon-percent').text(Math.round((notStarted / totalCount) * 100) + '%');
|
|
|
|
|
|
$('.hexagon-bottom .hexagon-percent').text(Math.round((delayed / totalCount) * 100) + '%');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新工种任务分布(模块2)
|
|
|
|
|
|
function updateJobTypeDistribution(data) {
|
|
|
|
|
|
const container = document.getElementById('jobTypeList');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
|
|
|
|
const html = data.map(function (item) {
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="job-type-item">
|
|
|
|
|
|
<span class="job-type-name">${item.name}</span>
|
|
|
|
|
|
<span class="job-type-value">${item.value}</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新延期排名(模块3)
|
|
|
|
|
|
function updateDelayRanking(data) {
|
|
|
|
|
|
const container = document.getElementById('delayRankingList');
|
|
|
|
|
|
if (!container) return;
|
|
|
|
|
|
|
|
|
|
|
|
const maxCount = data.length > 0 ? Math.max(...data.map(item => item.count)) : 1;
|
|
|
|
|
|
|
|
|
|
|
|
const html = data.map(function (item, index) {
|
|
|
|
|
|
const percentage = (item.count / maxCount) * 100;
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="delay-ranking-item">
|
|
|
|
|
|
<div class="ranking-number">${index + 1}</div>
|
|
|
|
|
|
<div class="ranking-name">${item.name}</div>
|
|
|
|
|
|
<div class="ranking-count">延期${item.count}次</div>
|
|
|
|
|
|
<div class="ranking-bar-container">
|
|
|
|
|
|
<div class="ranking-bar" style="width: ${percentage}%"></div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 18:55:45 +08:00
|
|
|
|
// 更新警告列表(模块5)
|
|
|
|
|
|
function updateWarningList(warnings) {
|
|
|
|
|
|
if (!warnings || warnings.length === 0) {
|
|
|
|
|
|
const $warningList = $('#warningList');
|
|
|
|
|
|
$warningList.html('<div class="warning-item"><div class="warning-text" style="text-align:center;color:rgba(255,255,255,0.5);">暂无预警数据</div></div>');
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const warningItemsHtml = warnings.map(function (warning) {
|
|
|
|
|
|
// 格式化日期:如果有txTime则显示,否则不显示日期
|
|
|
|
|
|
const dateStr = warning.txTime ? warning.txTime + ' ' : '';
|
|
|
|
|
|
const content = warning.content || '';
|
|
|
|
|
|
const fullText = dateStr + content;
|
|
|
|
|
|
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="warning-item">
|
|
|
|
|
|
<div class="warning-icon"></div>
|
|
|
|
|
|
<div class="warning-text" title="${fullText}">
|
|
|
|
|
|
${fullText}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
const $warningList = $('#warningList');
|
|
|
|
|
|
$warningList.html(warningItemsHtml);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否需要滚动
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
const $container = $warningList.parent();
|
|
|
|
|
|
const $listElement = $warningList[0];
|
|
|
|
|
|
|
|
|
|
|
|
if (!$listElement) return;
|
|
|
|
|
|
|
|
|
|
|
|
const contentHeight = $listElement.scrollHeight;
|
|
|
|
|
|
const containerHeight = $container.height();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果内容高度超过容器高度,启用无缝滚动
|
|
|
|
|
|
if (contentHeight > containerHeight) {
|
|
|
|
|
|
const duplicatedHtml = warningItemsHtml + warningItemsHtml;
|
|
|
|
|
|
$warningList.html(duplicatedHtml);
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
const newContentHeight = $listElement.scrollHeight;
|
|
|
|
|
|
const singleListHeight = newContentHeight / 2;
|
|
|
|
|
|
|
|
|
|
|
|
$warningList.addClass('warning-list-scroll');
|
|
|
|
|
|
|
|
|
|
|
|
const animationDuration = Math.max(25, Math.ceil(singleListHeight / 25));
|
|
|
|
|
|
|
|
|
|
|
|
$warningList.css({
|
|
|
|
|
|
'animation': `scrollWarning ${animationDuration}s linear infinite`,
|
|
|
|
|
|
'animation-fill-mode': 'forwards'
|
|
|
|
|
|
});
|
|
|
|
|
|
}, 200);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$warningList.addClass('warning-list-scroll');
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 500);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 打开任务详情弹框
|
|
|
|
|
|
function openTaskDetailModal(taskStatus) {
|
|
|
|
|
|
const modal = $('#taskDetailModal');
|
|
|
|
|
|
modal.addClass('show');
|
|
|
|
|
|
|
|
|
|
|
|
// 保存当前选中的taskStatus
|
|
|
|
|
|
modalTaskStatus = taskStatus || '';
|
|
|
|
|
|
modalQueryParams.taskStatus = modalTaskStatus;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置关键字输入框
|
|
|
|
|
|
modalKeyword = '';
|
|
|
|
|
|
$('#modalKeywordInput').val('');
|
|
|
|
|
|
|
|
|
|
|
|
// 同步弹框查询参数
|
|
|
|
|
|
modalQueryParams.startTestDay = queryParams.startTestDay;
|
|
|
|
|
|
modalQueryParams.endTestDay = queryParams.endTestDay;
|
|
|
|
|
|
|
|
|
|
|
|
// 延迟初始化表格,确保弹框完全显示后再渲染表格
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
initModalTaskDetailTable();
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭任务详情弹框
|
|
|
|
|
|
function closeTaskDetailModal() {
|
|
|
|
|
|
const modal = $('#taskDetailModal');
|
|
|
|
|
|
modal.removeClass('show');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化弹框内任务详情表格
|
|
|
|
|
|
function initModalTaskDetailTable() {
|
|
|
|
|
|
table.render({
|
|
|
|
|
|
elem: '#modalTaskDetailTable',
|
|
|
|
|
|
id: 'modalTaskDetailTable',
|
|
|
|
|
|
url: commonUrl + 'screen/worker/analysis/detail',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
decrypt: 'decrypt',
|
|
|
|
|
|
Authorization: token
|
|
|
|
|
|
},
|
|
|
|
|
|
method: 'GET',
|
|
|
|
|
|
where: {
|
|
|
|
|
|
projectId: bidCode,
|
2026-01-27 18:06:23 +08:00
|
|
|
|
startTestDay: '',
|
|
|
|
|
|
endTestDay: '',
|
2026-01-24 18:55:45 +08:00
|
|
|
|
taskStatus: modalTaskStatus || '',
|
|
|
|
|
|
keyword: modalKeyword || ''
|
|
|
|
|
|
},
|
|
|
|
|
|
skin: 'line',
|
|
|
|
|
|
page: {
|
|
|
|
|
|
layout: ['prev', 'page', 'next', 'count', 'skip'],
|
|
|
|
|
|
groups: 5,
|
|
|
|
|
|
limit: 10,
|
|
|
|
|
|
limits: [10, 20, 30, 50]
|
|
|
|
|
|
},
|
|
|
|
|
|
height: 'full',
|
|
|
|
|
|
request: {
|
|
|
|
|
|
pageName: 'pageNum',
|
|
|
|
|
|
limitName: 'pageSize'
|
|
|
|
|
|
},
|
|
|
|
|
|
response: {
|
|
|
|
|
|
statusName: 'code',
|
|
|
|
|
|
statusCode: 200,
|
|
|
|
|
|
msgName: 'msg',
|
|
|
|
|
|
countName: 'total',
|
|
|
|
|
|
dataName: 'rows'
|
|
|
|
|
|
},
|
|
|
|
|
|
cols: [[
|
|
|
|
|
|
{ type: 'numbers', title: '序号', width: '8%', align: 'center' },
|
|
|
|
|
|
{ field: 'userName', title: '姓名', width: '10%', align: 'center' },
|
|
|
|
|
|
{ field: 'teamName', title: '所属班组', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'workContent', title: '工作内容', width: '18%', align: 'center' },
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'taskStatus', title: '任务状态', width: '10%', align: 'center', templet: function (d) {
|
|
|
|
|
|
// taskStatus: 1-已完成, 2-进行中, 3-未开始, 4-延期
|
|
|
|
|
|
const statusMap = {
|
|
|
|
|
|
'1': '<span style="color: #00FFB8;">已完成</span>',
|
|
|
|
|
|
'2': '<span style="color: #FFC857;">进行中</span>',
|
|
|
|
|
|
'3': '<span style="color: #6BB9F0;">未开始</span>',
|
|
|
|
|
|
'4': '<span style="color: #FF6B6B;">延期</span>'
|
|
|
|
|
|
};
|
|
|
|
|
|
return statusMap[d.taskStatus] || d.taskStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ field: 'planStartTime', title: '计划开始时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'planEndTime', title: '计划完成时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'actualEndTime', title: '实际完成时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'isDelay', title: '是否延期', width: '8%', align: 'center', templet: function (d) {
|
|
|
|
|
|
return d.isDelay === '1' || d.isDelay === 1 || d.isDelay === '是' ?
|
|
|
|
|
|
'<span style="color: #FF6B6B;">是</span>' :
|
|
|
|
|
|
'<span style="color: #00FFB8;">否</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ field: 'delayDays', title: '延期天数', width: '8%', align: 'center' }
|
|
|
|
|
|
]]
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 弹框内查询记录
|
|
|
|
|
|
function queryModalRecords() {
|
|
|
|
|
|
modalKeyword = $('#modalKeywordInput').val() || '';
|
|
|
|
|
|
|
|
|
|
|
|
// 重新加载表格
|
|
|
|
|
|
table.reload('modalTaskDetailTable', {
|
|
|
|
|
|
where: {
|
|
|
|
|
|
projectId: bidCode,
|
|
|
|
|
|
startTestDay: modalQueryParams.startTestDay,
|
|
|
|
|
|
endTestDay: modalQueryParams.endTestDay,
|
|
|
|
|
|
taskStatus: modalTaskStatus || '',
|
|
|
|
|
|
keyword: modalKeyword
|
|
|
|
|
|
},
|
|
|
|
|
|
page: {
|
|
|
|
|
|
curr: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-01-24 14:23:35 +08:00
|
|
|
|
// 初始化警告列表(模块5)
|
|
|
|
|
|
function initWarningList() {
|
|
|
|
|
|
// 模拟警告数据 - 后续替换为真实接口数据
|
|
|
|
|
|
const warnings = [
|
|
|
|
|
|
{ date: '2026-01-15', message: '张三本月出现3次任务延期,请关注该人员,建议定期开展技能培训与考核,确保施工进度。' },
|
|
|
|
|
|
{ date: '2026-01-13', message: '张三本月出现3次任务延期,请关注该人员,建议定期开展技能培训与考核,确保施工进度。' },
|
|
|
|
|
|
{ date: '2026-01-12', message: '张三本月出现3次任务延期,请关注该人员,建议定期开展技能培训与考核,确保施工进度。' }
|
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
|
|
const warningItemsHtml = warnings.map(function (warning) {
|
|
|
|
|
|
const fullText = `${warning.date} ${warning.message}`;
|
|
|
|
|
|
return `
|
|
|
|
|
|
<div class="warning-item">
|
|
|
|
|
|
<div class="warning-icon"></div>
|
|
|
|
|
|
<div class="warning-text" title="${fullText}">
|
|
|
|
|
|
${fullText}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
`;
|
|
|
|
|
|
}).join('');
|
|
|
|
|
|
|
|
|
|
|
|
const $warningList = $('#warningList');
|
|
|
|
|
|
$warningList.html(warningItemsHtml);
|
|
|
|
|
|
|
|
|
|
|
|
// 检查是否需要滚动
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
const $container = $warningList.parent();
|
|
|
|
|
|
const $listElement = $warningList[0];
|
|
|
|
|
|
|
|
|
|
|
|
if (!$listElement) return;
|
|
|
|
|
|
|
|
|
|
|
|
const contentHeight = $listElement.scrollHeight;
|
|
|
|
|
|
const containerHeight = $container.height();
|
|
|
|
|
|
|
|
|
|
|
|
// 如果内容高度超过容器高度,启用无缝滚动
|
|
|
|
|
|
if (contentHeight > containerHeight) {
|
|
|
|
|
|
const duplicatedHtml = warningItemsHtml + warningItemsHtml;
|
|
|
|
|
|
$warningList.html(duplicatedHtml);
|
|
|
|
|
|
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
const newContentHeight = $listElement.scrollHeight;
|
|
|
|
|
|
const singleListHeight = newContentHeight / 2;
|
|
|
|
|
|
|
|
|
|
|
|
$warningList.addClass('warning-list-scroll');
|
|
|
|
|
|
|
|
|
|
|
|
const animationDuration = Math.max(25, Math.ceil(singleListHeight / 25));
|
|
|
|
|
|
|
|
|
|
|
|
$warningList.css({
|
|
|
|
|
|
'animation': `scrollWarning ${animationDuration}s linear infinite`,
|
|
|
|
|
|
'animation-fill-mode': 'forwards'
|
|
|
|
|
|
});
|
|
|
|
|
|
}, 200);
|
|
|
|
|
|
} else {
|
|
|
|
|
|
$warningList.addClass('warning-list-scroll');
|
|
|
|
|
|
}
|
|
|
|
|
|
}, 500);
|
|
|
|
|
|
}
|
2026-01-24 18:55:45 +08:00
|
|
|
|
|
|
|
|
|
|
// 打开任务详情弹框
|
|
|
|
|
|
function openTaskDetailModal(taskStatus) {
|
|
|
|
|
|
const modal = $('#taskDetailModal');
|
|
|
|
|
|
modal.addClass('show');
|
|
|
|
|
|
|
|
|
|
|
|
// 保存当前选中的taskStatus
|
|
|
|
|
|
modalTaskStatus = taskStatus || '';
|
|
|
|
|
|
modalQueryParams.taskStatus = modalTaskStatus;
|
|
|
|
|
|
|
|
|
|
|
|
// 重置关键字输入框
|
|
|
|
|
|
modalKeyword = '';
|
|
|
|
|
|
$('#modalKeywordInput').val('');
|
|
|
|
|
|
|
|
|
|
|
|
// 同步弹框查询参数
|
|
|
|
|
|
modalQueryParams.startTestDay = queryParams.startTestDay;
|
|
|
|
|
|
modalQueryParams.endTestDay = queryParams.endTestDay;
|
|
|
|
|
|
|
|
|
|
|
|
// 延迟初始化表格,确保弹框完全显示后再渲染表格
|
|
|
|
|
|
setTimeout(function () {
|
|
|
|
|
|
initModalTaskDetailTable();
|
|
|
|
|
|
}, 100);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 关闭任务详情弹框
|
|
|
|
|
|
function closeTaskDetailModal() {
|
|
|
|
|
|
const modal = $('#taskDetailModal');
|
|
|
|
|
|
modal.removeClass('show');
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化弹框内任务详情表格
|
|
|
|
|
|
function initModalTaskDetailTable() {
|
|
|
|
|
|
table.render({
|
|
|
|
|
|
elem: '#modalTaskDetailTable',
|
|
|
|
|
|
id: 'modalTaskDetailTable',
|
|
|
|
|
|
url: commonUrl + 'screen/worker/analysis/detail',
|
|
|
|
|
|
headers: {
|
|
|
|
|
|
decrypt: 'decrypt',
|
|
|
|
|
|
Authorization: token
|
|
|
|
|
|
},
|
|
|
|
|
|
method: 'GET',
|
|
|
|
|
|
where: {
|
|
|
|
|
|
projectId: bidCode,
|
2026-01-27 18:06:23 +08:00
|
|
|
|
startTestDay: '',
|
|
|
|
|
|
endTestDay: '',
|
2026-01-24 18:55:45 +08:00
|
|
|
|
taskStatus: modalTaskStatus || '',
|
|
|
|
|
|
keyword: modalKeyword || ''
|
|
|
|
|
|
},
|
|
|
|
|
|
skin: 'line',
|
|
|
|
|
|
page: {
|
|
|
|
|
|
layout: ['prev', 'page', 'next', 'count', 'skip'],
|
|
|
|
|
|
groups: 5,
|
|
|
|
|
|
limit: 10,
|
|
|
|
|
|
limits: [10, 20, 30, 50]
|
|
|
|
|
|
},
|
|
|
|
|
|
height: 'full',
|
|
|
|
|
|
request: {
|
|
|
|
|
|
pageName: 'pageNum',
|
|
|
|
|
|
limitName: 'pageSize'
|
|
|
|
|
|
},
|
|
|
|
|
|
response: {
|
|
|
|
|
|
statusName: 'code',
|
|
|
|
|
|
statusCode: 200,
|
|
|
|
|
|
msgName: 'msg',
|
|
|
|
|
|
countName: 'total',
|
|
|
|
|
|
dataName: 'rows'
|
|
|
|
|
|
},
|
|
|
|
|
|
cols: [[
|
|
|
|
|
|
{ type: 'numbers', title: '序号', width: '8%', align: 'center' },
|
|
|
|
|
|
{ field: 'userName', title: '姓名', width: '10%', align: 'center' },
|
|
|
|
|
|
{ field: 'teamName', title: '所属班组', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'workContent', title: '工作内容', width: '18%', align: 'center' },
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'taskStatus', title: '任务状态', width: '10%', align: 'center', templet: function (d) {
|
|
|
|
|
|
// taskStatus: 1-已完成, 2-进行中, 3-未开始, 4-延期
|
|
|
|
|
|
const statusMap = {
|
|
|
|
|
|
'1': '<span style="color: #00FFB8;">已完成</span>',
|
|
|
|
|
|
'2': '<span style="color: #FFC857;">进行中</span>',
|
|
|
|
|
|
'3': '<span style="color: #6BB9F0;">未开始</span>',
|
|
|
|
|
|
'4': '<span style="color: #FF6B6B;">延期</span>'
|
|
|
|
|
|
};
|
|
|
|
|
|
return statusMap[d.taskStatus] || d.taskStatus;
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ field: 'planStartTime', title: '计划开始时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'planEndTime', title: '计划完成时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{ field: 'actualEndTime', title: '实际完成时间', width: '12%', align: 'center' },
|
|
|
|
|
|
{
|
|
|
|
|
|
field: 'isDelay', title: '是否延期', width: '8%', align: 'center', templet: function (d) {
|
|
|
|
|
|
return d.isDelay === '1' || d.isDelay === 1 || d.isDelay === '是' ?
|
|
|
|
|
|
'<span style="color: #FF6B6B;">是</span>' :
|
|
|
|
|
|
'<span style="color: #00FFB8;">否</span>';
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
{ field: 'delayDays', title: '延期天数', width: '8%', align: 'center' }
|
|
|
|
|
|
]]
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 弹框内查询记录
|
|
|
|
|
|
function queryModalRecords() {
|
|
|
|
|
|
modalKeyword = $('#modalKeywordInput').val() || '';
|
|
|
|
|
|
|
|
|
|
|
|
// 重新加载表格
|
|
|
|
|
|
table.reload('modalTaskDetailTable', {
|
|
|
|
|
|
where: {
|
|
|
|
|
|
projectId: bidCode,
|
|
|
|
|
|
startTestDay: modalQueryParams.startTestDay,
|
|
|
|
|
|
endTestDay: modalQueryParams.endTestDay,
|
|
|
|
|
|
taskStatus: modalTaskStatus || '',
|
|
|
|
|
|
keyword: modalKeyword
|
|
|
|
|
|
},
|
|
|
|
|
|
page: {
|
|
|
|
|
|
curr: 1
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
}
|