From 2030a58d60aca87a461237747e803e9bf328ddb5 Mon Sep 17 00:00:00 2001 From: “wangming” <“wangming@antissoft.com”> Date: Wed, 10 Dec 2025 18:37:28 +0800 Subject: [PATCH] 优化考勤数据导入接口:支持按列名匹配、多种年份月份格式解析 --- netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 167 insertions(+), 12 deletions(-) diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs index b17c064..b34cd28 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqAttendanceSummaryService.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using Mapster; using Microsoft.AspNetCore.Http; @@ -110,20 +111,87 @@ namespace NCC.Extend throw NCCException.Oh("Excel文件中没有数据行"); } + // 根据列名查找列索引(支持多种可能的列名) + int GetColumnIndex(string[] possibleNames) + { + foreach (var name in possibleNames) + { + for (int col = 0; col < dataTable.Columns.Count; col++) + { + var columnName = dataTable.Columns[col].ColumnName?.Trim(); + if (columnName == name || columnName?.Contains(name) == true) + { + return col; + } + } + } + return -1; + } + + var nameColIndex = GetColumnIndex(new[] { "员工姓名", "姓名", "员工", "姓名" }); + var phoneColIndex = GetColumnIndex(new[] { "员工电话", "电话", "手机", "手机号", "联系电话" }); + var yearColIndex = GetColumnIndex(new[] { "年份", "年" }); + var monthColIndex = GetColumnIndex(new[] { "月份", "月" }); + var workDaysColIndex = GetColumnIndex(new[] { "出勤天数", "出勤", "工作天数", "上班天数" }); + var leaveDaysColIndex = GetColumnIndex(new[] { "请假天数", "请假", "事假天数" }); + var restDaysColIndex = GetColumnIndex(new[] { "休息天数", "休息", "休假天数" }); + var remarkColIndex = GetColumnIndex(new[] { "备注", "说明", "备注信息" }); + + // 验证必需的列是否存在 + if (nameColIndex == -1) throw NCCException.Oh("Excel文件中未找到'员工姓名'列"); + if (phoneColIndex == -1) throw NCCException.Oh("Excel文件中未找到'员工电话'列"); + if (yearColIndex == -1) throw NCCException.Oh("Excel文件中未找到'年份'列"); + if (monthColIndex == -1) throw NCCException.Oh("Excel文件中未找到'月份'列"); + // 从第1行开始读取数据(跳过标题行) for (int i = 1; i < dataTable.Rows.Count; i++) { try { var row = dataTable.Rows[i]; - var employeeName = row[0]?.ToString()?.Trim(); - var employeePhone = row[1]?.ToString()?.Trim(); - var yearText = row[2]?.ToString()?.Trim(); - var monthText = row[3]?.ToString()?.Trim(); - var workDaysText = row[4]?.ToString()?.Trim(); - var leaveDaysText = row[5]?.ToString()?.Trim(); - var restDaysText = row[6]?.ToString()?.Trim(); - var remark = row[7]?.ToString()?.Trim(); + var employeeName = row[nameColIndex]?.ToString()?.Trim(); + var employeePhone = row[phoneColIndex]?.ToString()?.Trim(); + + // 处理年份:可能是数字、日期或字符串 + string yearText = null; + if (yearColIndex >= 0 && row[yearColIndex] != null && row[yearColIndex] != DBNull.Value) + { + if (row[yearColIndex] is DateTime dt) + { + yearText = dt.Year.ToString(); + } + else if (row[yearColIndex] is double d) + { + yearText = ((int)d).ToString(); + } + else + { + yearText = row[yearColIndex].ToString()?.Trim(); + } + } + + // 处理月份:可能是数字、日期或字符串 + string monthText = null; + if (monthColIndex >= 0 && row[monthColIndex] != null && row[monthColIndex] != DBNull.Value) + { + if (row[monthColIndex] is DateTime dt) + { + monthText = dt.Month.ToString(); + } + else if (row[monthColIndex] is double d) + { + monthText = ((int)d).ToString(); + } + else + { + monthText = row[monthColIndex].ToString()?.Trim(); + } + } + + var workDaysText = workDaysColIndex >= 0 ? row[workDaysColIndex]?.ToString()?.Trim() : null; + var leaveDaysText = leaveDaysColIndex >= 0 ? row[leaveDaysColIndex]?.ToString()?.Trim() : null; + var restDaysText = restDaysColIndex >= 0 ? row[restDaysColIndex]?.ToString()?.Trim() : null; + var remark = remarkColIndex >= 0 ? row[remarkColIndex]?.ToString()?.Trim() : null; // 跳过空行 if (string.IsNullOrEmpty(employeeName) && string.IsNullOrEmpty(employeePhone)) @@ -142,13 +210,100 @@ namespace NCC.Extend } // 解析数值字段 - if (!int.TryParse(yearText, out int year)) + int year = 0; + int month = 0; + + // 解析年份:支持纯数字、日期格式、中文格式 + if (string.IsNullOrEmpty(yearText)) + { + throw new Exception($"第{i + 1}行:年份不能为空"); + } + + // 尝试直接解析为整数 + if (int.TryParse(yearText, out year)) + { + // 成功解析 + } + // 尝试解析日期格式(如:2025-11-01 或 2025/11/01) + else if (DateTime.TryParse(yearText, out DateTime yearDate)) + { + year = yearDate.Year; + } + // 尝试解析中文格式(如:2025年) + else if (yearText.Contains("年")) + { + var yearMatch = Regex.Match(yearText, @"(\d{4})年"); + if (yearMatch.Success && int.TryParse(yearMatch.Groups[1].Value, out year)) + { + // 成功解析 + } + else + { + throw new Exception($"第{i + 1}行:年份格式错误,无法解析:{yearText}"); + } + } + else + { + throw new Exception($"第{i + 1}行:年份格式错误,无法解析。实际值:\"{yearText}\"(类型:{yearText?.GetType().Name})"); + } + + // 验证年份范围 + if (year < 2020 || year > 2030) + { + throw new Exception($"第{i + 1}行:年份必须在2020-2030之间"); + } + + // 解析月份:支持纯数字、日期格式、中文格式 + if (string.IsNullOrEmpty(monthText)) + { + throw new Exception($"第{i + 1}行:月份不能为空"); + } + + // 尝试直接解析为整数 + if (int.TryParse(monthText, out month)) + { + // 成功解析 + } + // 尝试解析日期格式(如:2025-11-01 或 2025/11/01) + else if (DateTime.TryParse(monthText, out DateTime monthDate)) + { + month = monthDate.Month; + } + // 尝试解析中文格式(如:11月) + else if (monthText.Contains("月")) + { + var monthMatch = Regex.Match(monthText, @"(\d{1,2})月"); + if (monthMatch.Success && int.TryParse(monthMatch.Groups[1].Value, out month)) + { + // 成功解析 + } + else + { + throw new Exception($"第{i + 1}行:月份格式错误,无法解析:{monthText}"); + } + } + // 尝试解析"年-月"格式(如:2025-11) + else if (monthText.Contains("-") || monthText.Contains("/")) + { + var parts = monthText.Split(new[] { "-", "/" }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length >= 2 && int.TryParse(parts[1], out month)) + { + // 成功解析 + } + else + { + throw new Exception($"第{i + 1}行:月份格式错误,无法解析:{monthText}"); + } + } + else { - throw new Exception($"第{i + 1}行:年份格式错误"); + throw new Exception($"第{i + 1}行:月份格式错误,无法解析。实际值:\"{monthText}\"(类型:{monthText?.GetType().Name})"); } - if (!int.TryParse(monthText, out int month)) + + // 验证月份范围 + if (month < 1 || month > 12) { - throw new Exception($"第{i + 1}行:月份格式错误"); + throw new Exception($"第{i + 1}行:月份必须在1-12之间"); } decimal.TryParse(workDaysText, out decimal workDays); -- libgit2 0.21.4