721 lines
24 KiB
Plaintext
721 lines
24 KiB
Plaintext
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="ManPowerStat.aspx.cs" Inherits="FineUIPro.Web.JDGL.SGManPower.ManPowerStat" %>
|
||
|
||
<!DOCTYPE html>
|
||
<html>
|
||
<head id="Head1" runat="server">
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
<title>人力统计</title>
|
||
<link href="../../res/index/css/reset.css" rel="stylesheet" />
|
||
<link href="../../res/index/css/home.css" rel="stylesheet" />
|
||
<link href="../../res/index/css/swiper-3.4.2.min.css" rel="stylesheet" />
|
||
<style type="text/css">
|
||
* {
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.flexV {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.wrap {
|
||
height: 100%;
|
||
padding: 15px;
|
||
background-color: #FFFFFF;
|
||
}
|
||
|
||
.iteml {
|
||
margin-left: 5px;
|
||
}
|
||
|
||
.itemb {
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.bottom-wrap {
|
||
padding: 0;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.bottom-wrap:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.bw-b-bottom {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
|
||
.bw-b-bottom-up {
|
||
border-radius: 0;
|
||
height: 100%;
|
||
margin: 0;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.bw-item-content {
|
||
padding: 5px;
|
||
}
|
||
|
||
.top {
|
||
width: 100%;
|
||
}
|
||
|
||
.bw-b {
|
||
width: 50%;
|
||
}
|
||
|
||
.tab-wrap {
|
||
left: auto;
|
||
right: 15px;
|
||
top: 5px;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.tab .t-item {
|
||
width: auto;
|
||
padding: 5px 10px;
|
||
color: #363636;
|
||
}
|
||
|
||
.tit-item {
|
||
padding: 0 10px;
|
||
justify-content: space-between;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.tab-wrap .tab .t-item {
|
||
color: #1C1C1C;
|
||
}
|
||
|
||
.tip-item {
|
||
margin-left: 10px;
|
||
align-items: center;
|
||
font-size: 10px;
|
||
}
|
||
|
||
.tip {
|
||
width: 25px;
|
||
height: 13px;
|
||
background-color: #258F76;
|
||
border-radius: 2px;
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.tip-next {
|
||
background-color: #4F4F4F;
|
||
}
|
||
|
||
.myTableClass {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: auto;
|
||
margin: 2px 1px;
|
||
border-collapse: collapse;
|
||
border: 1px solid #BEBEBE;
|
||
background: #ffffff;
|
||
color: #8B8989;
|
||
text-align: center;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.tab-title {
|
||
height: 48px;
|
||
color: #3CB371;
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
}
|
||
|
||
.tab-header {
|
||
height: 36px;
|
||
color: #1C86EE;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
}
|
||
|
||
td, th {
|
||
border: 1px solid #BEBEBE;
|
||
}
|
||
.container {
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100%;
|
||
}
|
||
|
||
.filter-options {
|
||
justify-content: flex-end;
|
||
padding: 10px;
|
||
background-color: #f8f8f8;
|
||
border-bottom: 1px solid #ddd;
|
||
}
|
||
|
||
.filter-options label {
|
||
margin-left: 10px;
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
|
||
.filter-options input[type="radio"] {
|
||
margin-right: 5px;
|
||
}
|
||
|
||
.loading-overlay {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
background: rgba(0, 0, 0, 0.5);
|
||
display: none;
|
||
justify-content: center;
|
||
align-items: center;
|
||
z-index: 9999;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 50px;
|
||
height: 50px;
|
||
border: 5px solid #f3f3f3;
|
||
border-top: 5px solid #3498db;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
.chart-container {
|
||
width: 100%;
|
||
height: 100%;
|
||
min-height: 300px;
|
||
}
|
||
|
||
.error-message {
|
||
color: red;
|
||
text-align: center;
|
||
padding: 20px;
|
||
display: none;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<div class="filter-options">
|
||
<label>
|
||
<input type="radio" name="data-filter" value="total" checked> 总数
|
||
</label>
|
||
<label>
|
||
<input type="radio" name="data-filter" value="annual"> 年度
|
||
</label>
|
||
<select id="year-select" style="display: none; margin-left: 10px; padding: 2px; font-size: 14px;">
|
||
<!-- 年份选项将通过JavaScript动态填充 -->
|
||
</select>
|
||
<label>
|
||
<input type="radio" name="data-filter" value="monthly"> 月度
|
||
</label>
|
||
<select id="month-select" style="display: none; margin-left: 10px; padding: 2px; font-size: 14px;">
|
||
<option value="1">1月</option>
|
||
<option value="2">2月</option>
|
||
<option value="3">3月</option>
|
||
<option value="4">4月</option>
|
||
<option value="5">5月</option>
|
||
<option value="6">6月</option>
|
||
<option value="7">7月</option>
|
||
<option value="8">8月</option>
|
||
<option value="9">9月</option>
|
||
<option value="10">10月</option>
|
||
<option value="11">11月</option>
|
||
<option value="12">12月</option>
|
||
</select>
|
||
</div>
|
||
<div class="wrap flex flexV">
|
||
<div class="bottom-wrap flex1">
|
||
<div class="top flex">
|
||
<div class="item flex2 iteml">
|
||
<div class="bw-b-bottom">
|
||
<div class="bw-b-bottom-up">
|
||
<div class="bw-item-content">
|
||
<div id='one' class="chart-container"></div>
|
||
<div id='one-error' class="error-message"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="item flex2 iteml">
|
||
<div class="bw-b-bottom">
|
||
<div class="bw-b-bottom-up">
|
||
<div class="bw-item-content">
|
||
<div id='two' class="chart-container"></div>
|
||
<div id='two-error' class="error-message"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="bottom-wrap flex1">
|
||
<div class="top flex">
|
||
<div class="item flex2 iteml">
|
||
<div class="bw-b-bottom">
|
||
<div class="bw-b-bottom-up">
|
||
<div class="bw-item-content">
|
||
<div id='three' class="chart-container"></div>
|
||
<div id='three-error' class="error-message"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item flex2 iteml">
|
||
<div class="bw-b-bottom">
|
||
<div class="bw-b-bottom-up">
|
||
<div class="bw-item-content">
|
||
<div id='four' class="chart-container"></div>
|
||
<div id='four-error' class="error-message"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 加载动画 -->
|
||
<div id="loadingOverlay" class="loading-overlay">
|
||
<div class="loading-spinner"></div>
|
||
</div>
|
||
</body>
|
||
<script type="text/javascript" src="../../res/index/js/jquery-3.4.1.min.js"></script>
|
||
<script type="text/javascript" src="../../res/index/js/swiper-3.4.2.jquery.min.js"></script>
|
||
<script type="text/javascript" src="../../res/index/js/echarts.min.js"></script>
|
||
|
||
<script type="text/javascript">
|
||
// 存储各图表的实例
|
||
var chartInstances = {};
|
||
|
||
// 页面加载完成后初始化图表
|
||
$(document).ready(function() {
|
||
// 填充年份下拉框
|
||
populateYearSelect();
|
||
|
||
// 获取当前URL中的type参数,如果没有则默认为total
|
||
var urlParams = new URLSearchParams(window.location.search);
|
||
var currentType = urlParams.get('type') || 'total';
|
||
|
||
// 设置对应的单选按钮为选中状态
|
||
$('input[name="data-filter"][value="' + currentType + '"]').prop('checked', true);
|
||
|
||
// 根据选中的类型显示/隐藏年份下拉框
|
||
toggleYearSelect(currentType);
|
||
|
||
// 初始化图表
|
||
loadAndRenderCharts(currentType);
|
||
|
||
// 监听单选按钮变化事件
|
||
$('input[name="data-filter"]').change(function() {
|
||
var dataType = $(this).val();
|
||
toggleYearSelect(dataType);
|
||
});
|
||
|
||
// 监听年份下拉框变化事件
|
||
$('#year-select').change(function() {
|
||
var dataType = $('input[name="data-filter"]:checked').val();
|
||
if (dataType === 'annual' || dataType === 'monthly') {
|
||
loadAndRenderCharts(dataType);
|
||
}
|
||
});
|
||
|
||
// 监听月份下拉框变化事件
|
||
$('#month-select').change(function() {
|
||
var dataType = $('input[name="data-filter"]:checked').val();
|
||
if (dataType === 'monthly') {
|
||
loadAndRenderCharts(dataType);
|
||
}
|
||
});
|
||
});
|
||
|
||
// 填充年份下拉框
|
||
function populateYearSelect() {
|
||
var currentYear = new Date().getFullYear();
|
||
var yearSelect = $('#year-select');
|
||
|
||
// 添加最近10年的选项
|
||
for (var i = currentYear; i >= currentYear - 10; i--) {
|
||
yearSelect.append($('<option></option>').attr('value', i).text(i));
|
||
}
|
||
|
||
// 默认选中当前年份
|
||
yearSelect.val(currentYear);
|
||
}
|
||
|
||
// 根据选中的数据类型显示/隐藏年份下拉框
|
||
function toggleYearSelect(dataType) {
|
||
if (dataType === 'annual') {
|
||
$('#year-select').show();
|
||
$('#month-select').hide();
|
||
// 不再立即触发数据查询,只显示年份选择框
|
||
} else if (dataType === 'monthly') {
|
||
$('#year-select').show();
|
||
$('#month-select').show();
|
||
// 不再立即触发数据查询,只显示年份和月份选择框
|
||
} else {
|
||
$('#year-select').hide();
|
||
$('#month-select').hide();
|
||
}
|
||
}
|
||
|
||
// 通过Ajax加载数据并渲染图表
|
||
function loadAndRenderCharts(type) {
|
||
// 显示加载状态
|
||
showLoading();
|
||
|
||
// 隐藏所有错误信息
|
||
$('.error-message').hide();
|
||
|
||
// 获取选中的年份或月份
|
||
var selectedYear = $('#year-select').val();
|
||
var selectedMonth = $('#month-select').val();
|
||
|
||
// 使用Ajax并行获取四个图表的数据
|
||
$.when(
|
||
$.ajax({
|
||
url: 'ManPowerStat.aspx/GetChartData',
|
||
type: 'POST',
|
||
data: JSON.stringify(createParams(type, 'One', selectedYear, selectedMonth)),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
timeout: 30000 // 30秒超时
|
||
}),
|
||
$.ajax({
|
||
url: 'ManPowerStat.aspx/GetChartData',
|
||
type: 'POST',
|
||
data: JSON.stringify(createParams(type, 'Two', selectedYear, selectedMonth)),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
timeout: 30000
|
||
}),
|
||
$.ajax({
|
||
url: 'ManPowerStat.aspx/GetChartData',
|
||
type: 'POST',
|
||
data: JSON.stringify(createParams(type, 'Three', selectedYear, selectedMonth)),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
timeout: 30000
|
||
}),
|
||
$.ajax({
|
||
url: 'ManPowerStat.aspx/GetChartData',
|
||
type: 'POST',
|
||
data: JSON.stringify(createParams(type, 'Four', selectedYear, selectedMonth)),
|
||
contentType: 'application/json; charset=utf-8',
|
||
dataType: 'json',
|
||
timeout: 30000
|
||
})
|
||
).done(function(oneResult, twoResult, threeResult, fourResult) {
|
||
try {
|
||
// 渲染四个图表
|
||
renderChart('one', oneResult[0].d, '五环管理人员统计分析');
|
||
renderChart('two', twoResult[0].d, '施工单位管理人员统计分析');
|
||
renderChart('three', threeResult[0].d, '作业人员统计分析');
|
||
renderChart('four', fourResult[0].d, '过程人力统计分析');
|
||
} catch (e) {
|
||
console.error('图表渲染错误:', e);
|
||
showError('图表渲染失败,请重试');
|
||
}
|
||
|
||
// 隐藏加载状态
|
||
hideLoading();
|
||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||
// 处理错误情况
|
||
console.error('Ajax请求失败:', textStatus, errorThrown);
|
||
console.error('响应内容:', jqXHR.responseText);
|
||
|
||
var errorMessage = '数据加载失败';
|
||
if (textStatus === 'timeout') {
|
||
errorMessage = '请求超时,请重试';
|
||
} else if (jqXHR.responseText) {
|
||
try {
|
||
var errorResponse = JSON.parse(jqXHR.responseText);
|
||
if (errorResponse.Message) {
|
||
errorMessage = errorResponse.Message;
|
||
}
|
||
} catch (e) {
|
||
errorMessage = jqXHR.responseText;
|
||
}
|
||
}
|
||
|
||
showError(errorMessage);
|
||
hideLoading();
|
||
});
|
||
}
|
||
|
||
// 创建传递给后端的参数对象
|
||
function createParams(type, chart, year, month) {
|
||
debugger
|
||
var params = {
|
||
type: type,
|
||
chart: chart ,
|
||
year:null,
|
||
month:null,
|
||
};
|
||
|
||
// 只有在需要时才添加year和month参数
|
||
if (type === 'annual' && year) {
|
||
params.year = year;
|
||
} else if (type === 'monthly' && year && month) {
|
||
params.year = year;
|
||
params.month = month;
|
||
}
|
||
|
||
// 确保参数对象中不包含值为undefined的属性
|
||
for (var key in params) {
|
||
if (params[key] === undefined) {
|
||
delete params[key];
|
||
}
|
||
}
|
||
|
||
return params;
|
||
}
|
||
|
||
// 渲染单个图表的通用方法
|
||
function renderChart(chartId, data, title) {
|
||
try {
|
||
// 隐藏错误信息
|
||
$('#' + chartId + '-error').hide();
|
||
|
||
// 解析数据
|
||
var chartData;
|
||
if (typeof data === 'string') {
|
||
chartData = JSON.parse(data);
|
||
} else {
|
||
chartData = data;
|
||
}
|
||
|
||
// 验证数据
|
||
if (!chartData || !chartData.categories || !chartData.series) {
|
||
throw new Error('数据格式不正确');
|
||
}
|
||
|
||
// 如果图表实例已存在,先销毁
|
||
if (chartInstances[chartId]) {
|
||
chartInstances[chartId].dispose();
|
||
}
|
||
|
||
var chartContainer = document.getElementById(chartId);
|
||
if (!chartContainer) {
|
||
throw new Error('找不到图表容器: ' + chartId);
|
||
}
|
||
|
||
var myChart = echarts.init(chartContainer);
|
||
var xArr = chartData.categories;
|
||
var num = chartData.xFontNum || 6;
|
||
|
||
// 确保series数据存在
|
||
var seriesData = [];
|
||
if (chartData.series && chartData.series.length >= 2) {
|
||
seriesData = [
|
||
{
|
||
name: '计划',
|
||
type: 'line',
|
||
data: chartData.series[1].data || [],
|
||
label: {
|
||
show: true,
|
||
position: 'top',
|
||
textStyle: {
|
||
fontSize: '12px',
|
||
color: '#363636'
|
||
},
|
||
formatter: function (params) {
|
||
return params.value === 0 ? '' : params.value;
|
||
},
|
||
},
|
||
itemStyle: { normal: { color: 'rgba(255,0,0, 0.5)' } },
|
||
smooth: true
|
||
},
|
||
{
|
||
name: '实际',
|
||
type: 'line',
|
||
data: chartData.series[0].data || [],
|
||
label: {
|
||
show: true,
|
||
position: 'top',
|
||
textStyle: {
|
||
fontSize: '12px',
|
||
color: '#363636'
|
||
},
|
||
formatter: function (params) {
|
||
return params.value === 0 ? '' : params.value;
|
||
},
|
||
},
|
||
itemStyle: { normal: { color: 'rgba(0,100,0,0.8)' } },
|
||
smooth: true
|
||
}
|
||
];
|
||
}
|
||
|
||
var option = {
|
||
title: {
|
||
text: title,
|
||
textStyle: {
|
||
color: '#1C1C1C',
|
||
fontSize: 16,
|
||
fontWeight: 700
|
||
},
|
||
show: true
|
||
},
|
||
tooltip: {},
|
||
legend: {
|
||
left: '80%',
|
||
show: true,
|
||
textStyle: {
|
||
color: '#363636',
|
||
fontSize: 12,
|
||
}
|
||
},
|
||
dataZoom: [
|
||
{
|
||
type: 'slider',
|
||
maxValueSpan: 6,
|
||
show: xArr && xArr.length > 6, // 只有数据超过6个才显示缩放
|
||
xAxisIndex: [0],
|
||
bottom: 0, height: 10,
|
||
backgroundColor: 'rgba(0,0,0,0)',
|
||
borderColor: 'none',
|
||
brushSelect: false,
|
||
textStyle: {
|
||
color: 'rgba(0,0,0,0)'
|
||
},
|
||
selectedDataBackground: {
|
||
areaStyle: {
|
||
color: 'red',
|
||
borderWidth: 0
|
||
}
|
||
},
|
||
handleStyle: {
|
||
color: "#0a1449"
|
||
},
|
||
moveHandleStyle: {
|
||
color: '#0a1449'
|
||
}
|
||
}
|
||
],
|
||
xAxis: {
|
||
axisTick: {
|
||
show: false
|
||
},
|
||
axisLine: {
|
||
lineStyle: {
|
||
color: 'rgba(0,0,0, 0.3)',
|
||
}
|
||
},
|
||
axisLabel: {
|
||
show: true,
|
||
textStyle: {
|
||
color: 'rgba(0,0,0, 0.8)'
|
||
},
|
||
interval: 0,
|
||
rotate: -15,
|
||
formatter: function (value) {
|
||
if (!value) return '';
|
||
var ret = "";
|
||
var maxLength = num;
|
||
var valLength = value.length;
|
||
var rowN = Math.ceil(valLength / maxLength);
|
||
if (rowN > 1) {
|
||
for (var i = 0; i < rowN; i++) {
|
||
var temp = "";
|
||
var start = i * maxLength;
|
||
var end = start + maxLength;
|
||
temp = value.substring(start, end) + (i == rowN - 1 ? "" : "\n");
|
||
ret += temp;
|
||
}
|
||
return ret;
|
||
} else {
|
||
return value;
|
||
}
|
||
}
|
||
},
|
||
type: 'category',
|
||
data: xArr || [],
|
||
boundaryGap: [0, 0.01],
|
||
},
|
||
yAxis: {
|
||
axisTick: {
|
||
show: false
|
||
},
|
||
axisLine: {
|
||
show: false,
|
||
lineStyle: {
|
||
color: 'rgba(0,0,0, 0.3)'
|
||
}
|
||
},
|
||
axisLabel: {
|
||
show: true,
|
||
textStyle: {
|
||
color: 'rgba(0,0,0, 0.8)'
|
||
}
|
||
},
|
||
},
|
||
series: seriesData,
|
||
grid: {
|
||
top: '20%',
|
||
left: '0%',
|
||
right: '0%',
|
||
bottom: 40,
|
||
containLabel: true,
|
||
backgroundColor: 'rgba(0,162,233, 0.01)',
|
||
},
|
||
backgroundColor: 'rgba(0,162,233, 0.01)',
|
||
textStyle: {
|
||
color: 'rgba(0,0,0, 0.3)'
|
||
}
|
||
};
|
||
|
||
myChart.setOption(option);
|
||
chartInstances[chartId] = myChart;
|
||
|
||
// 监听窗口大小变化,重新调整图表大小
|
||
var resizeHandler = function() {
|
||
if (chartInstances[chartId]) {
|
||
chartInstances[chartId].resize();
|
||
}
|
||
};
|
||
|
||
// 避免重复绑定事件
|
||
if (window.addEventListener) {
|
||
window.removeEventListener('resize', resizeHandler);
|
||
window.addEventListener('resize', resizeHandler);
|
||
}
|
||
} catch (e) {
|
||
console.error('渲染图表失败 [' + chartId + ']:', e);
|
||
showError('图表渲染失败: ' + e.message, chartId);
|
||
}
|
||
}
|
||
|
||
// 显示错误信息
|
||
function showError(message, chartId) {
|
||
if (chartId) {
|
||
$('#' + chartId + '-error').text(message).show();
|
||
} else {
|
||
// 全局错误显示
|
||
alert(message);
|
||
}
|
||
}
|
||
|
||
// 显示加载状态
|
||
function showLoading() {
|
||
document.getElementById('loadingOverlay').style.display = 'flex';
|
||
}
|
||
|
||
// 隐藏加载状态
|
||
function hideLoading() {
|
||
document.getElementById('loadingOverlay').style.display = 'none';
|
||
}
|
||
</script>
|
||
|
||
|
||
|
||
|
||
</html>
|