let table, layer, form, laydate; let teamQualityChart = null; let qualityRatioChart = null; let currentPage = 1; let pageSize = 10; 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 initPage() { initTeamQualityChart(); initQualityRatioChart(); initQualityRecordTable(); initWarningList(); // 初始化自适应处理 // initResizeHandler(); } // 防抖函数 function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // 初始化自适应处理 function initResizeHandler() { // 创建防抖的resize处理函数 const handleResize = debounce(function() { // 重新调整所有图表大小 if (teamQualityChart) { try { teamQualityChart.resize(); } catch(e) { console.error('调整柱状图大小失败:', e); } } if (qualityRatioChart) { try { qualityRatioChart.resize(); } catch(e) { console.error('调整环形图大小失败:', e); } } // 重新调整表格大小(如果需要) if (table) { try { table.resize('qualityRecordTable'); } catch(e) { // 表格resize可能不支持,忽略错误 } } }, 300); // 300ms防抖延迟 // 监听窗口resize事件 window.addEventListener('resize', handleResize); // 监听iframe的resize(如果页面在iframe中) if (window.parent !== window) { window.parent.addEventListener('resize', handleResize); } // 页面加载完成后也执行一次resize,确保初始状态正确 setTimeout(function() { handleResize(); }, 100); } // 初始化施工队伍质量合格率柱状图 function initTeamQualityChart() { const chartDom = document.getElementById('teamQualityChart'); if (!chartDom) return; if (teamQualityChart) { teamQualityChart.dispose(); } teamQualityChart = echarts.init(chartDom); // 模拟数据 - 后续替换为真实接口数据 const teams = ['班组一', '班组二', '班组三', '班组四', '班组五', '班组六', '班组七', '班组八']; const acceptedData = [450, 380, 520, 420, 480, 350, 510, 440]; // 已验收 const unacceptedData = [150, 120, 180, 160, 140, 221, 170, 160]; // 未验收 const option = { backgroundColor: 'transparent', tooltip: { trigger: 'axis', axisPointer: { type: 'shadow', shadowStyle: { color: 'rgba(6, 189, 221, 0.2)' } }, 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) { if (!params || params.length === 0) return ''; const dataIndex = params[0].dataIndex; const teamName = params[0].name; let unaccepted = 0; let accepted = 0; params.forEach(function(item) { if (item.seriesName === '未验收') { unaccepted = item.value; } else if (item.seriesName === '已验收') { accepted = item.value; } }); return `
子分部工程
未验收 ${unaccepted}
已验收 ${accepted}
`; } }, legend: { data: ['未验收', '已验收'], top: '-15%', right: '5%', itemGap: 15, textStyle: { color: '#FFFFFF', fontSize: 12 }, itemWidth: 12, itemHeight: 12, icon: 'circle' }, grid: { left: '2%', right: '2%', bottom: '3%', top: '10%', containLabel: true }, xAxis: { type: 'category', data: teams, axisLabel: { color: '#FFFFFF', fontSize: 12, margin: 10 }, axisLine: { show: true, lineStyle: { color: 'rgba(255, 255, 255, 0.3)', width: 1 } }, axisTick: { show: false } }, yAxis: { type: 'value', min: 0, max: 600, interval: 150, axisLabel: { color: '#FFFFFF', fontSize: 12, margin: 8 }, axisLine: { show: true, lineStyle: { color: 'rgba(255, 255, 255, 0.3)', width: 1 } }, splitLine: { show: true, lineStyle: { color: 'rgba(255, 255, 255, 0.15)', type: 'dashed', width: 1 } } }, series: [ { name: '未验收', type: 'bar', data: unacceptedData, stack: 'total', barWidth: '45%', itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(74, 144, 226, 0.9)' }, { offset: 1, color: 'rgba(74, 144, 226, 0.6)' }]), borderRadius: [2, 2, 0, 0], shadowColor: 'rgba(74, 144, 226, 0.5)', shadowBlur: 8, shadowOffsetY: 3 }, emphasis: { itemStyle: { shadowBlur: 15, shadowOffsetY: 5, shadowColor: 'rgba(74, 144, 226, 0.8)' } }, label: { show: false } }, { name: '已验收', type: 'bar', data: acceptedData, stack: 'total', barWidth: '45%', itemStyle: { 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], shadowColor: 'rgba(0, 255, 184, 0.6)', shadowBlur: 10, shadowOffsetY: 4, borderColor: 'rgba(0, 255, 184, 0.3)', borderWidth: 1 }, emphasis: { itemStyle: { shadowBlur: 18, shadowOffsetY: 6, shadowColor: 'rgba(0, 255, 184, 0.9)', borderColor: 'rgba(0, 255, 184, 0.6)', borderWidth: 2 } }, label: { show: true, position: 'top', color: '#FFFFFF', fontSize: 12, fontWeight: 'bold', formatter: function(params) { return params.value; }, textShadowColor: 'rgba(0, 0, 0, 0.5)', textShadowBlur: 3, textShadowOffsetX: 1, textShadowOffsetY: 1 } } ] }; teamQualityChart.setOption(option); } // 初始化质量检测合格占比环形图 function initQualityRatioChart() { const chartDom = document.getElementById('qualityRatioChart'); if (!chartDom) return; if (qualityRatioChart) { qualityRatioChart.dispose(); } qualityRatioChart = echarts.init(chartDom); // 模拟数据 - 后续替换为真实接口数据 const passRate = 65.00; const failRate = 35.00; 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], position: 'right', textStyle: { color: '#FFFFFF', fontSize: 12 }, extraCssText: 'z-index: 9999999999;', // 确保tooltip在最上层 formatter: function(params) { const name = params.name; const value = params.value; const color = params.color; return `
质量检测合格占比
${name} ${value.toFixed(2)}%
`; } }, series: [ // 外层圆环 - 2-4px宽度,白色/亮色,完整圆环 { name: '外层圆环', type: 'pie', radius: ['94%', '97%'], center: ['50%', '50%'], avoidLabelOverlap: false, silent: true, // 不响应鼠标事件 itemStyle: { color: function(params) { // 根据图片,外层圆环可能是白色或亮青色,带发光效果 return new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(255, 255, 255, 0.9)' }, { offset: 1, color: 'rgba(0, 255, 212, 0.8)' }]); }, borderRadius: 2, // 外层圆环圆角效果 borderColor: 'transparent', borderWidth: 0, shadowBlur: 8, shadowColor: 'rgba(0, 255, 212, 0.6)' }, label: { show: false }, labelLine: { show: false }, data: [{ value: 100, name: '' }] }, // 内层圆环 - 15-20px宽度,显示数据 { name: '质量检测合格占比', type: 'pie', radius: ['70%', '80%'], center: ['50%', '50%'], avoidLabelOverlap: false, // 添加分段之间的间隙 gap: 3, // 分段之间的间隙(像素),创建可见的深色间隙 itemStyle: { borderRadius: 5, // 添加圆角效果,使圆环更圆润 borderColor: 'transparent', borderWidth: 0 }, label: { show: true, position: 'center', formatter: function() { return '{a|100}{b|%}'; }, rich: { a: { fontSize: 32, fontWeight: 'bold', color: '#FFFFFF', lineHeight: 40 }, b: { fontSize: 20, fontWeight: 'bold', color: '#FFFFFF', lineHeight: 40 } } }, emphasis: { itemStyle: { borderRadius: 6, // 悬停时圆角更大 shadowBlur: 10, shadowOffsetX: 0, shadowColor: 'rgba(0, 0, 0, 0.5)' }, label: { rich: { a: { fontSize: 36, fontWeight: 'bold', color: '#FFFFFF' }, b: { fontSize: 22, fontWeight: 'bold', color: '#FFFFFF' } } } }, labelLine: { show: false }, data: [ { value: passRate, name: '合格', itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#00FFD4' }, { offset: 0.5, color: '#00D4FF' }, { offset: 1, color: '#00A8FF' }]) } }, { value: failRate, name: '不合格', itemStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: 'rgba(238, 248, 245, 1)' }, { offset: 1, color: 'rgba(238, 248, 245, 0.8)' }]) } } ] } ] }; qualityRatioChart.setOption(option); // 更新显示值 const passRatioEl = document.getElementById('passRatio'); const failRatioEl = document.getElementById('failRatio'); if (passRatioEl) { passRatioEl.textContent = passRate.toFixed(2) + '%'; } if (failRatioEl) { failRatioEl.textContent = failRate.toFixed(2) + '%'; } } // 生成模拟数据 function generateMockData() { const teams = ['班组一', '班组二', '班组三', '班组四', '班组五', '班组六', '班组七', '班组八']; const contents = [ '混凝土强度检测', '钢筋焊接质量检测', '模板安装质量检测', '钢筋绑扎质量检测', '混凝土浇筑质量检测', '模板拆除质量检测', '钢筋加工质量检测', '混凝土养护质量检测', '钢筋连接质量检测', '模板支撑质量检测', '混凝土配合比检测', '钢筋保护层检测', '模板平整度检测', '混凝土坍落度检测', '钢筋间距检测', '模板垂直度检测' ]; const results = ['合格', '不合格']; const mockData = []; const today = new Date(); for (let i = 0; i < 25; i++) { const date = new Date(today); date.setDate(date.getDate() - Math.floor(i / 3)); const dateStr = date.getFullYear() + '-' + String(date.getMonth() + 1).padStart(2, '0') + '-' + String(date.getDate()).padStart(2, '0'); mockData.push({ teamName: teams[Math.floor(Math.random() * teams.length)], inspectionContent: contents[Math.floor(Math.random() * contents.length)], inspectionDate: dateStr, inspectionResult: results[Math.random() > 0.3 ? 0 : 1] }); } return mockData; } // 初始化质量检测记录表格 function initQualityRecordTable() { const mockData = generateMockData(); table.render({ elem: '#qualityRecordTable', data: mockData, // 直接使用数据,不使用url skin: 'line', page: { layout: ['prev', 'page', 'next', 'count', 'skip'], groups: 5, limit: 10, limits: [10, 20, 30] }, height: 'full', cols: [[ {type: 'numbers', title: '序号', width: '15%', align: 'center'}, {field: 'teamName', title: '班组名称', width: '20%', align: 'center'}, {field: 'inspectionContent', title: '检测内容', width: '25%', align: 'center'}, {field: 'inspectionDate', title: '检测日期', width: '20%', align: 'center'}, {field: 'inspectionResult', title: '检测结果', width: '20%', align: 'center', templet: function(d) { return d.inspectionResult === '合格' ? '合格' : '不合格'; }} ]] }); } // 初始化日期范围选择器 function initDateRangePicker() { // 使用范围选择器,两个输入框都可以触发 // 先绑定开始日期 laydate.render({ elem: '#dateStart', type: 'date', range: ['#dateStart', '#dateEnd'], format: 'yyyy-MM-dd', theme: 'dark', max: 0, // 最大日期为今天 done: function(value, date, endDate) { if (value) { const dates = value.split(' - '); if (dates.length === 2) { $('#dateStart').val(dates[0]); $('#dateEnd').val(dates[1]); } } } }); // 为结束日期也绑定相同的配置,确保点击结束日期也能触发 $('#dateEnd').on('click', function() { // 点击结束日期时,触发开始日期的日期选择器 $('#dateStart').click(); }); } // 查询记录 function queryRecords() { const keyword = $('#keywordInput').val(); const startDate = $('#dateStart').val(); const endDate = $('#dateEnd').val(); table.reload('qualityRecordTable', { where: { keyword: keyword, startDate: startDate, endDate: endDate, bidCode: parent.parent.$('#bidPro').val() || '' }, page: { curr: 1 } }); } // 初始化警告列表 function initWarningList() { // 模拟数据 - 后续替换为真实接口数据 const warnings = [ {date: '2026-01-11', team: '班组一', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-11', team: '班组三', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-10', team: '班组五', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-10', team: '班组七', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-09', team: '班组二', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-09', team: '班组四', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-08', team: '班组六', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'}, {date: '2026-01-08', team: '班组八', message: '质量检测合格率低于80%,请持续关注该班组施工质量情况。'} ]; // 生成警告项HTML const warningItemsHtml = warnings.map(function(warning) { const fullText = `${warning.date} ${warning.team}${warning.message}`; return `
${fullText}
`; }).join(''); const $warningList = $('#warningList'); // 先渲染一次,检查是否需要滚动 $warningList.html(warningItemsHtml); // 等待DOM渲染后检查高度 setTimeout(function() { const $container = $warningList.parent(); const $listElement = $warningList[0]; if (!$listElement) return; const contentHeight = $listElement.scrollHeight; const containerHeight = $container.height(); // 如果内容高度超过容器高度,启用无缝滚动 if (contentHeight > containerHeight) { // 复制2份内容实现无缝循环:原始 + 复制1 const duplicatedHtml = warningItemsHtml + warningItemsHtml; $warningList.html(duplicatedHtml); // 等待DOM更新后重新计算高度和启动动画 setTimeout(function() { const newContentHeight = $listElement.scrollHeight; const singleListHeight = newContentHeight / 2; // 单份内容的高度 // 添加滚动类 $warningList.addClass('warning-list-scroll'); // 计算动画时长,根据内容高度动态调整 // 滚动距离是单份内容的高度(50%对应单份高度) // 每25px用1秒,确保滚动速度适中且流畅 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 getTeamQualityData() { const bidCode = parent.parent.$('#bidPro').val() || ''; const url = commonUrl + 'screen/largeScreen/dataAnalysis/getTeamQualityPassRate'; $.ajax({ url: url, type: 'GET', headers: { decrypt: 'decrypt', Authorization: token }, data: { bidCode: bidCode }, success: function(res) { if (res.code === 200 && res.data) { // 更新图表数据 updateTeamQualityChart(res.data); } }, error: function(err) { console.error('获取施工队伍质量合格率数据失败:', err); } }); } // 更新施工队伍质量合格率图表 function updateTeamQualityChart(data) { if (!teamQualityChart) return; const teams = data.map(item => item.teamName); const acceptedData = data.map(item => item.accepted || 0); const unacceptedData = data.map(item => item.unaccepted || 0); teamQualityChart.setOption({ xAxis: { data: teams }, series: [ { name: '未验收', data: unacceptedData }, { name: '已验收', data: acceptedData } ] }); } // 获取质量检测合格占比数据(接口调用) function getQualityRatioData() { const bidCode = parent.parent.$('#bidPro').val() || ''; const url = commonUrl + 'screen/largeScreen/dataAnalysis/getQualityRatio'; $.ajax({ url: url, type: 'GET', headers: { decrypt: 'decrypt', Authorization: token }, data: { bidCode: bidCode }, success: function(res) { if (res.code === 200 && res.data) { // 更新图表数据 updateQualityRatioChart(res.data); } }, error: function(err) { console.error('获取质量检测合格占比数据失败:', err); } }); } // 更新质量检测合格占比图表 function updateQualityRatioChart(data) { if (!qualityRatioChart) return; const passRate = data.passRate || 0; const failRate = data.failRate || 0; qualityRatioChart.setOption({ series: [{ data: [ {value: passRate, name: '合格'}, {value: failRate, name: '不合格'} ] }] }); // 更新显示值 document.getElementById('passRatio').textContent = passRate.toFixed(2) + '%'; document.getElementById('failRatio').textContent = failRate.toFixed(2) + '%'; } // 获取警告列表数据(接口调用) function getWarningListData() { const bidCode = parent.parent.$('#bidPro').val() || ''; const url = commonUrl + 'screen/largeScreen/dataAnalysis/getQualityWarnings'; $.ajax({ url: url, type: 'GET', headers: { decrypt: 'decrypt', Authorization: token }, data: { bidCode: bidCode }, success: function(res) { if (res.code === 200 && res.data) { // 更新警告列表 updateWarningList(res.data); } }, error: function(err) { console.error('获取警告列表数据失败:', err); } }); } // 更新警告列表 function updateWarningList(data) { const warningListHtml = data.map(function(warning) { return `
${warning.date} ${warning.message}
`; }).join(''); $('#warningList').html(warningListHtml); }