using BLL; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; namespace FineUIPro.Web.JDGL.SGManPower { public partial class ManPowerWorkGrid : PageBase { #region Page_Init // 注意:动态创建的代码需要放置于Page_Init(不是Page_Load),这样每次构造页面时都会执行 protected void Page_Init(object sender, EventArgs e) { InitGrid(); } public DataTable GridTable = new DataTable(); private void InitGrid() { FineUIPro.BoundField bf; FineUIPro.RenderField rf; FineUIPro.TextBox txTextBox; // 设置Grid的编辑属性 Grid1.AllowCellEditing = true; Grid1.ClicksToEdit = 1; Grid1.EnableAfterEditEvent = true; UnitId = Request.Params["UnitId"]; StartTime = Request.Params["StartTime"]; EndTime = Request.Params["EndTime"]; GridTable.Columns.Add("Id"); // 添加隐藏列来存储额外的ID信息 GridTable.Columns.Add("UnitId"); GridTable.Columns.Add("WorkPostId"); ListItem[] list = new ListItem[4]; list[0] = new ListItem("序号", "SerialNumber"); list[1] = new ListItem("单位", "UnitName"); list[2] = new ListItem("岗位", "WorkPostName"); list[3] = new ListItem("累计", "TotalCount"); foreach (var item in list) { bf = new FineUIPro.BoundField(); bf.ColumnID = item.Value; bf.DataField = item.Value; bf.HeaderText = item.Text; bf.HeaderTextAlign = TextAlign.Center; bf.TextAlign = TextAlign.Center; bf.Locked = true; Grid1.Columns.Add(bf); GridTable.Columns.Add(item.Value); } // 动态获取日期范围 DateTime startDate = Convert.ToDateTime(StartTime); DateTime endDate = Convert.ToDateTime(EndTime); var dateRange = Enumerable.Range(0, (endDate - startDate).Days + 1) .Select(i => startDate.AddDays(i)) .ToList(); // 按年分组日期 var groupedByYear = dateRange.GroupBy(d => d.Year) .OrderBy(g => g.Key) .ToList(); foreach (var yearGroup in groupedByYear) { GroupField yearGroupField = new GroupField(); yearGroupField.HeaderText = $"{yearGroup.Key}年"; yearGroupField.TextAlign = TextAlign.Center; // 按月分组 var groupedByMonth = yearGroup.GroupBy(d => d.Month) .OrderBy(g => g.Key) .ToList(); foreach (var monthGroup in groupedByMonth) { GroupField monthGroupField = new GroupField(); monthGroupField.HeaderText = $"{monthGroup.Key}月"; monthGroupField.TextAlign = TextAlign.Center; // 添加具体日期的列 foreach (var date in monthGroup.OrderBy(d => d)) { bf = new FineUIPro.BoundField(); bf.ColumnID = date.ToString("yyyy-MM-dd"); bf.DataField = date.ToString("yyyy-MM-dd"); bf.HeaderText = date.ToString("dd"); bf.HeaderTextAlign = TextAlign.Center; bf.TextAlign = TextAlign.Center; monthGroupField.Columns.Add(bf); GridTable.Columns.Add(date.ToString("yyyy-MM-dd")); } yearGroupField.Columns.Add(monthGroupField); } Grid1.Columns.Add(yearGroupField); } } #endregion public string UnitId { get => (string)ViewState["UnitId"]; set => ViewState["UnitId"] = value; } public string StartTime { get => (string)ViewState["StartTime"]; set => ViewState["StartTime"] = value; } public string EndTime { get => (string)ViewState["EndTime"]; set => ViewState["EndTime"] = value; } protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { Funs.DropDownPageSize(this.ddlPageSize); // 设置Grid的PageSize与下拉框默认值一致 Grid1.PageSize = Convert.ToInt32(ddlPageSize.SelectedValue); WorkPostService.InitWorkPostDropDownList(this.drpWorkPost, true); //岗位 // 绑定表格 this.BindGrid(); } } #region 绑定数据 /// /// 绑定数据 /// private void BindGrid() { // 清空现有数据 GridTable.Clear(); // 重新添加列定义(保持列结构) if (GridTable.Columns.Count == 0) { GridTable.Columns.Add("Id"); GridTable.Columns.Add("UnitId"); GridTable.Columns.Add("WorkPostId"); // 添加动态日期列(这部分已经在InitGrid中定义了) ListItem[] list = new ListItem[4]; list[0] = new ListItem("序号", "SerialNumber"); list[1] = new ListItem("单位", "UnitName"); list[2] = new ListItem("岗位", "WorkPostName"); list[3] = new ListItem("累计", "TotalCount"); foreach (var item in list) { GridTable.Columns.Add(item.Value); } // 日期列会在InitGrid中添加,这里不需要重复添加 } else { // 清空行数据但保持列结构 GridTable.Rows.Clear(); } // 使用原生SQL查询来提高性能,直接在数据库层面进行分组统计 string strSql = @" SELECT UnitId, PostId, RecordDate, COUNT(1) as RecordCount FROM T_d_EmployInOutRecord WHERE ProjectId = @ProjectId AND RecordDate >= @StartDate AND RecordDate <= @EndDate"; var parameters = new List { new System.Data.SqlClient.SqlParameter("@ProjectId", this.CurrUser.LoginProjectId), new System.Data.SqlClient.SqlParameter("@StartDate", Convert.ToDateTime(StartTime)), new System.Data.SqlClient.SqlParameter("@EndDate", Convert.ToDateTime(EndTime)) }; if (UnitId != Const._Null) { strSql += " AND UnitId = @UnitId"; parameters.Add(new System.Data.SqlClient.SqlParameter("@UnitId", UnitId)); } if (drpWorkPost.SelectedValue != Const._Null) { strSql += " AND PostId = @PostId"; parameters.Add(new System.Data.SqlClient.SqlParameter("@PostId", drpWorkPost.SelectedValue)); } strSql += " GROUP BY UnitId, PostId, RecordDate"; // 执行查询获取分组数据 var dt = SQLHelper.GetDataTableRunText(strSql, parameters.ToArray()); // 将数据转换为更易处理的格式 var groupedData = new List(); var groupedDict = new Dictionary(); foreach (System.Data.DataRow row in dt.Rows) { string key = $"{row["UnitId"]}_{row["PostId"]}"; DateTime recordDate = Convert.ToDateTime(row["RecordDate"]); int count = Convert.ToInt32(row["RecordCount"]); if (!groupedDict.ContainsKey(key)) { dynamic group = new System.Dynamic.ExpandoObject(); group.UnitId = row["UnitId"]; group.PostId = row["PostId"]; group.DailyCounts = new Dictionary(); group.TotalCount = 0; groupedDict[key] = group; groupedData.Add(group); } groupedDict[key].DailyCounts[recordDate] = count; groupedDict[key].TotalCount += count; } Grid1.RecordCount = groupedData.Count(); // 分页处理 var pagedData = groupedData.Skip(Grid1.PageSize * Grid1.PageIndex).Take(Grid1.PageSize).ToList(); // 只获取当前页需要的单位和岗位信息,避免加载全部数据 var unitIds = pagedData.Where(x => x.UnitId != null).Select(x => x.UnitId.ToString()).Distinct().ToList(); var postIds = pagedData.Where(x => x.PostId != null).Select(x => x.PostId.ToString()).Distinct().ToList(); var units = new Dictionary(); var workPosts = new Dictionary(); if (unitIds.Any()) { var unitQuery = from u in Funs.DB.Base_Unit where unitIds.Contains(u.UnitId) select new { u.UnitId, u.UnitName }; foreach (var u in unitQuery) { units[u.UnitId] = u.UnitName; } } if (postIds.Any()) { var postQuery = from p in Funs.DB.Base_WorkPost where postIds.Contains(p.WorkPostId) select new { p.WorkPostId, p.WorkPostName }; foreach (var p in postQuery) { workPosts[p.WorkPostId] = p.WorkPostName; } } foreach (var group in pagedData) { DataRow row = GridTable.NewRow(); // 基本信息 row["Id"] = Guid.NewGuid().ToString(); // 生成唯一ID用于行标识 row["SerialNumber"] = GridTable.Rows.Count + 1; // 序号 // 单位信息 string unitName = ""; if (group.UnitId != null && units.ContainsKey(group.UnitId.ToString())) { unitName = units[group.UnitId.ToString()]; } row["UnitName"] = unitName; row["UnitId"] = group.UnitId ?? (object)DBNull.Value; // 岗位信息 string workPostName = ""; if (group.PostId != null && workPosts.ContainsKey(group.PostId.ToString())) { workPostName = workPosts[group.PostId.ToString()]; } row["WorkPostName"] = workPostName; row["WorkPostId"] = group.PostId ?? (object)DBNull.Value; // 每日数量填充 foreach (var kvp in group.DailyCounts) { string dateColumnId = kvp.Key.ToString("yyyy-MM-dd"); // 确保列存在 if (GridTable.Columns.Contains(dateColumnId)) { row[dateColumnId] = kvp.Value; } } // 设置累计数量 row["TotalCount"] = group.TotalCount; GridTable.Rows.Add(row); } Grid1.DataSource = GridTable; Grid1.DataBind(); // 计算汇总数据 OutputSummaryData(); } #region 计算合计 /// /// 计算合计 /// private void OutputSummaryData() { // 创建用于存储合计值的对象 JObject summary = new JObject(); // 设置固定列的合计值 summary.Add("UnitName", "合计"); // 计算TotalCount列的合计值 int totalCountSum = 0; foreach (DataRow row in GridTable.Rows) { if (row["TotalCount"] != DBNull.Value && row["TotalCount"] != null) { int value; if (int.TryParse(row["TotalCount"].ToString(), out value)) { totalCountSum += value; } } } summary.Add("TotalCount", totalCountSum.ToString()); // 计算日期列的合计值 foreach (DataColumn column in GridTable.Columns) { // 检查是否为日期列(格式为 yyyy-MM-dd) DateTime date; if (DateTime.TryParseExact(column.ColumnName, "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out date)) { // 计算该列的合计值 int columnSum = 0; foreach (DataRow row in GridTable.Rows) { if (row[column.ColumnName] != DBNull.Value && row[column.ColumnName] != null) { int value; if (int.TryParse(row[column.ColumnName].ToString(), out value)) { columnSum += value; } } } summary.Add(column.ColumnName, columnSum.ToString()); } } // 设置汇总数据 Grid1.SummaryData = summary; } #endregion #endregion #region GV 数据操作 /// /// 分页 /// /// /// protected void Grid1_PageIndexChange(object sender, GridPageEventArgs e) { this.Grid1.PageIndex = e.NewPageIndex; this.BindGrid(); } /// /// 排序 /// /// /// protected void Grid1_Sort(object sender, GridSortEventArgs e) { this.Grid1.SortDirection = e.SortDirection; this.Grid1.SortField = e.SortField; this.BindGrid(); } /// /// 分页显示条数下拉框 /// /// /// protected void ddlPageSize_SelectedIndexChanged(object sender, EventArgs e) { Grid1.PageSize = Convert.ToInt32(ddlPageSize.SelectedValue); this.BindGrid(); } #endregion #region 数据查询 /// /// 查询 /// /// /// protected void btnQuery_OnClick(object sender, EventArgs e) { BindGrid(); } /// /// 统计图表 /// /// /// protected void btnGetChart_Click(object sender, EventArgs e) { if (!string.IsNullOrEmpty(UnitId) && !string.IsNullOrEmpty(StartTime) && !string.IsNullOrEmpty(EndTime)) { // 构建基础URL参数 string urlParams = string.Format("UnitId={0}&StartTime={1}&EndTime={2}", UnitId, StartTime, EndTime); // 添加岗位参数(如果已选择) if (drpWorkPost.SelectedValue != Const._Null && !string.IsNullOrEmpty(drpWorkPost.SelectedValue)) { urlParams += "&WorkPostId=" + drpWorkPost.SelectedValue; } PageContext.RegisterStartupScript( Window2.GetShowReference(string.Format("ManPowerWorkChart.aspx?{0}", urlParams), "人力计划图表")); } else { ShowNotify("请先选确保时间范围已设置", MessageBoxIcon.Warning); } } #endregion #region 关闭弹出窗 /// /// 关闭弹出窗 /// /// /// protected void Window1_Close(object sender, WindowCloseEventArgs e) { BindGrid(); } #endregion #region 导出按钮 /// 导出按钮 /// /// /// protected void btnOut_Click(object sender, EventArgs e) { Response.ClearContent(); string filename = Funs.GetNewFileName(); Response.AddHeader("content-disposition", "attachment; filename=" + System.Web.HttpUtility.UrlEncode("现场考勤人力表" + filename, System.Text.Encoding.UTF8) + ".xls"); Response.ContentType = "application/excel"; Response.ContentEncoding = System.Text.Encoding.UTF8; this.BindGrid(); // 生成并写入Excel表格 Response.Write(GetGridTableHtml(Grid1)); Response.End(); } /// /// 导出方法 - 支持多级表头 /// /// /// /// private string GetGridTableHtml(Grid grid) { StringBuilder sb = new StringBuilder(); MultiHeaderTable mht = new MultiHeaderTable(); mht.ResolveMultiHeaderTable(grid.Columns); sb.Append(""); sb.Append(""); // 生成多级表头 foreach (List rows in mht.MultiTable) { sb.Append(""); foreach (object[] cell in rows) { int rowspan = 1; int colspan = Convert.ToInt32(cell[1]); GridColumn column = cell[2] as GridColumn; // 对于锁定列(固定列),确保rowspan为3 if (column.Locked) { rowspan = 3; } sb.AppendFormat("{3}", " rowspan=\"" + rowspan + "\"", colspan != 1 ? " colspan=\"" + colspan + "\"" : "", colspan != 1 ? " style=\"text-align:center;\"" : "", column.HeaderText); } sb.Append(""); } // 生成数据行 foreach (GridRow row in grid.Rows) { sb.Append(""); foreach (GridColumn column in mht.Columns) { string html = row.Values[column.ColumnIndex].ToString(); // 特殊处理固定列 if (column.ColumnID == "UnitName") { html = row.Values[column.ColumnIndex].ToString(); } else if (column.ColumnID == "WorkPostName") { html = row.Values[column.ColumnIndex].ToString(); } else if (column.ColumnID == "TotalCount") { html = row.Values[column.ColumnIndex].ToString(); } // 处理日期列(格式为 yyyy-MM-dd) else if (DateTime.TryParseExact(column.ColumnID, "yyyy-MM-dd", null, System.Globalization.DateTimeStyles.None, out _)) { html = row.Values[column.ColumnIndex].ToString(); } sb.AppendFormat("", html); } sb.Append(""); } // 添加合计行 if (grid.SummaryData != null) { sb.Append(""); foreach (GridColumn column in mht.Columns) { string summaryValue = ""; // 检查SummaryData中是否有该列的合计值 if (grid.SummaryData.Properties().Any(p => p.Name == column.ColumnID)) { var property = grid.SummaryData.Properties().FirstOrDefault(p => p.Name == column.ColumnID); if (property != null) { summaryValue = property.Value.ToString(); } } else if (column.ColumnID == "UnitName") { summaryValue = "合计"; } sb.AppendFormat("", summaryValue); } sb.Append(""); } sb.Append("
{0}
{0}
"); return sb.ToString(); } #region 多表头处理 /// /// 处理多表头的类 /// public class MultiHeaderTable { // 包含 rowspan,colspan 的多表头,方便生成 HTML 的 table 标签 public List> MultiTable = new List>(); // 最终渲染的列数组 public List Columns = new List(); public void ResolveMultiHeaderTable(GridColumnCollection columns) { List row = new List(); foreach (GridColumn column in columns) { object[] cell = new object[4]; cell[0] = 1; // rowspan cell[1] = 1; // colspan cell[2] = column; cell[3] = null; row.Add(cell); } ResolveMultiTable(row, 0); ResolveColumns(row); } private void ResolveColumns(List row) { foreach (object[] cell in row) { GroupField groupField = cell[2] as GroupField; if (groupField != null && groupField.Columns.Count > 0) { List subrow = new List(); foreach (GridColumn column in groupField.Columns) { subrow.Add(new object[] { 1, 1, column, groupField }); } ResolveColumns(subrow); } else { Columns.Add(cell[2] as GridColumn); } } } private void ResolveMultiTable(List row, int level) { List nextrow = new List(); foreach (object[] cell in row) { GroupField groupField = cell[2] as GroupField; if (groupField != null && groupField.Columns.Count > 0) { // 如果当前列包含子列,则更改当前列的 colspan,以及增加父列(向上递归)的colspan cell[1] = Convert.ToInt32(groupField.Columns.Count); PlusColspan(level - 1, cell[3] as GridColumn, groupField.Columns.Count - 1); foreach (GridColumn column in groupField.Columns) { nextrow.Add(new object[] { 1, 1, column, groupField }); } } else { // 如果当前列不包含子列,但不是最末级列(不是叶子节点),则增加rowspan if (level > 0) { cell[0] = level + 1; } } } MultiTable.Add(row); if (nextrow.Count > 0) { ResolveMultiTable(nextrow, level + 1); } } private void PlusColspan(int level, GridColumn column, int colspan) { if (level < 0) { return; } foreach (List rows in MultiTable) { foreach (object[] cells in rows) { if (cells[2] == column) { cells[1] = Convert.ToInt32(cells[1]) + colspan; PlusColspan(level - 1, cells[3] as GridColumn, colspan); break; } } } } } #endregion #endregion } }