using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; using Mapster; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using NCC.Common.Core.Manager; using NCC.Common.Extension; using NCC.Common.Filter; using NCC.Common.Helper; using NCC.Dependency; using NCC.DynamicApiController; using NCC.Extend.Entitys.Dto.Common; using NCC.Extend.Entitys.Dto.LqEvent; using NCC.Extend.Entitys.Dto.LqEventUser; using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_event; using NCC.Extend.Entitys.lq_eventuser; using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Entitys.lq_tkjlb; using NCC.Extend.Interfaces.LqEvent; using NCC.FriendlyException; using NCC.System.Entitys.Permission; using SqlSugar; using Yitter.IdGenerator; namespace NCC.Extend.LqEvent { /// /// 拓客活动服务 /// [ApiDescriptionSettings(Tag = "绿纤拓客活动服务", Name = "LqEvent", Order = 200)] [Route("api/Extend/[controller]")] [ApiController] public class LqEventService : ILqEventService, IDynamicApiController, ITransient { private readonly ISqlSugarClient _db; private readonly IUserManager _userManager; /// /// 初始化一个类型的新实例 /// /// 数据库 /// 用户管理 public LqEventService(ISqlSugarClient db, IUserManager userManager) { _db = db; _userManager = userManager; } #region 获取拓客活动列表 /// /// 获取拓客活动列表 /// /// /// 分页查询拓客活动列表,支持多条件筛选和排序。 /// 返回结果包含每个活动的成员数量统计。 /// /// 示例请求: /// GET /api/Extend/LqEvent?page=1&rows=10&sidx=Id&sord=desc&eventName=春节拓客活动 /// /// 支持的条件筛选: /// - 活动名称模糊查询 /// - 活动编号模糊查询 /// - 活动负责人模糊查询 /// - 开始时间范围查询 /// - 结束时间范围查询 /// /// 支持的排序字段: /// - Id: 活动ID /// - EventName: 活动名称 /// - EventNumber: 活动编号 /// - EventCoordinator: 活动负责人 /// - StartTime: 开始时间 /// - EndTime: 结束时间 /// /// 查询参数 /// 分页的拓客活动列表,包含成员数量统计 [HttpGet("")] public async Task GetList([FromQuery] LqEventListQueryInput input) { var sidx = input.sidx == null ? "id" : input.sidx; var sord = input.sord == null ? "desc" : input.sord; // 先查询活动列表 var Data = await _db.Queryable() .WhereIF(!string.IsNullOrEmpty(input.EventName), e => e.EventName.Contains(input.EventName)) .WhereIF(!string.IsNullOrEmpty(input.EventNumber), e => e.EventNumber.Contains(input.EventNumber)) .Select(e => new LqEventListOutput { id = e.Id, eventName = e.EventName, startTime = e.StartTime, endTime = e.EndTime, eventCoordinator = e.EventCoordinator, eventNumber = e.EventNumber, memberCount = SqlFunc.Subqueryable().Where(u => u.EventId == e.Id).Count(), eventType = e.EventType, }) .MergeTable() .OrderBy(sidx + " " + sord) .ToPagedListAsync(input.page, input.rows); return PageResult.SqlSugarPageResult(Data); } #endregion #region 获取拓客活动详情 /// /// 获取拓客活动详情 /// /// /// 根据活动ID获取拓客活动的详细信息,包括基础信息和所有参与成员列表。 /// /// 示例请求: /// GET /api/Extend/LqEvent/1234567890123456789 /// /// 返回数据包含: /// - 活动基础信息(ID、名称、编号、负责人、开始时间、结束时间) /// - 成员列表(用户ID、部门ID、战队名称、创建时间、创建用户) /// /// 如果活动不存在,将返回404错误。 /// /// 拓客活动ID /// 拓客活动详情,包含成员信息 /// 成功返回拓客活动详情 /// 拓客活动不存在 /// 服务器内部错误 [HttpGet("{id}")] public async Task GetInfo(string id) { // 1. 获取拓客活动基本信息 var entity = await _db.Queryable().FirstAsync(p => p.Id == id); if (entity == null) { throw NCCException.Oh("拓客活动不存在"); } // 2. 手动映射到输出格式 var output = new LqEventInfoOutput { id = entity.Id, eventName = entity.EventName, startTime = entity.StartTime, endTime = entity.EndTime, eventCoordinator = entity.EventCoordinator, eventNumber = entity.EventNumber, eventType = entity.EventType, }; // 3. 获取拓客活动成员信息 var members = await _db.Queryable().Where(u => u.EventId == id).ToListAsync(); // 4. 手动映射成员信息 output.Members = members .Select(m => new LqEventUserInfoOutput { id = m.Id, eventId = m.EventId, userId = m.UserId, depId = m.DepId, teamName = m.TeamName, creationTime = m.CreationTime, creationUser = m.CreationUser, targetCount = m.EventTarget, storeId = m.StoreId, }) .ToList(); return output; } #endregion #region 创建拓客活动 /// /// 创建拓客活动 /// /// /// 创建新的拓客活动,可以同时添加参与成员。 /// 系统会自动生成活动ID,并记录创建用户信息。 /// /// 示例请求: /// POST /api/Extend/LqEvent /// Content-Type: application/json /// /// ```json /// { /// "eventName": "春节拓客活动", /// "eventNumber": "TK2024001", /// "eventCoordinator": "张三", /// "startTime": "2024-01-15T09:00:00", /// "endTime": "2024-01-20T18:00:00", /// "members": [ /// { /// "userId": "user001", /// "depId": "dept001", /// "teamName": "第一战队" /// }, /// { /// "userId": "user002", /// "depId": "dept001", /// "teamName": "第二战队" /// } /// ] /// } /// ``` /// /// 参数验证: /// - eventName: 必填,最大长度255字符 /// - eventNumber: 可选,最大长度255字符 /// - eventCoordinator: 可选,最大长度255字符 /// - members: 可选,成员列表 /// - userId: 必填 /// - depId: 可选 /// - teamName: 可选 /// /// 创建流程: /// 1. 生成新的活动ID /// 2. 插入拓客活动记录 /// 3. 插入成员记录(如果有) /// /// 创建参数 /// 无返回值 [HttpPost("")] public async Task Create([FromBody] LqEventCrInput input) { var userInfo = await _userManager.GetUserInfo(); var entity = input.Adapt(); // 生成新的ID entity.Id = YitIdHelper.NextId().ToString(); // 手动设置时间字段,确保时分秒不丢失 entity.StartTime = input.StartTime; entity.EndTime = input.EndTime; // 插入拓客活动 var isOk = await _db.Insertable(entity).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh("创建拓客活动失败"); // 插入拓客活动成员 if (input.Members != null && input.Members.Count > 0) { var memberEntities = new List(); foreach (var member in input.Members) { memberEntities.Add( new LqEventUserEntity { Id = YitIdHelper.NextId().ToString(), EventId = entity.Id.ToString(), UserId = member.UserId, DepId = member.DepId, TeamName = member.TeamName, CreationTime = DateTime.Now, CreationUser = userInfo?.userName, StoreId = member.StoreId, EventTarget = member.TargetCount, } ); } await _db.Insertable(memberEntities).ExecuteCommandAsync(); } } #endregion #region 更新拓客活动 /// /// 更新拓客活动 /// /// /// 更新拓客活动信息,包括基础信息和成员列表。 /// 更新时会先删除原有成员,再添加新成员。 /// /// 示例请求: /// PUT /api/Extend/LqEvent /// Content-Type: application/json /// /// ```json /// { /// "id": "1234567890123456789", /// "eventName": "春节拓客活动(更新)", /// "eventNumber": "TK2024001", /// "eventCoordinator": "李四", /// "startTime": "2024-01-15T09:00:00", /// "endTime": "2024-01-25T18:00:00", /// "members": [ /// { /// "userId": "user003", /// "depId": "dept002", /// "teamName": "精英战队" /// } /// ] /// } /// ``` /// /// 参数验证: /// - id: 必填,拓客活动ID /// - eventName: 必填,最大长度255字符 /// - eventNumber: 可选,最大长度255字符 /// - eventCoordinator: 可选,最大长度255字符 /// - members: 可选,成员列表(为空则清空所有成员) /// /// 更新流程: /// 1. 更新拓客活动记录 /// 2. 删除原有成员记录 /// 3. 插入新成员记录(如果有) /// /// 更新参数 /// 无返回值 /// 拓客活动更新成功 /// 请求参数错误或验证失败 /// 拓客活动不存在 /// 服务器内部错误 [HttpPut("")] public async Task Update([FromBody] LqEventUpInput input) { var userInfo = await _userManager.GetUserInfo(); var entity = input.Adapt(); // 手动设置时间字段,确保时分秒不丢失 entity.StartTime = input.StartTime; entity.EndTime = input.EndTime; // 更新拓客活动 var isOk = await _db.Updateable(entity).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh("更新拓客活动失败"); // 删除原有成员 await _db.Deleteable().Where(u => u.EventId == entity.Id.ToString()).ExecuteCommandAsync(); // 插入新成员 if (input.Members != null && input.Members.Count > 0) { var memberEntities = new List(); foreach (var member in input.Members) { memberEntities.Add( new LqEventUserEntity { Id = YitIdHelper.NextId().ToString(), EventId = entity.Id.ToString(), UserId = member.UserId, DepId = member.DepId, TeamName = member.TeamName, CreationTime = DateTime.Now, CreationUser = userInfo?.userName, StoreId = member.StoreId, EventTarget = member.TargetCount, } ); } await _db.Insertable(memberEntities).ExecuteCommandAsync(); } } #endregion #region 删除拓客活动 /// /// 删除拓客活动 /// /// /// 删除指定的拓客活动,会同时删除该活动的所有成员记录。 /// 删除操作不可恢复,请谨慎使用。 /// /// 示例请求: /// DELETE /api/Extend/LqEvent/1234567890123456789 /// /// 删除顺序: /// 1. 先删除所有相关成员记录 /// 2. 再删除拓客活动记录 /// /// 注意事项: /// - 删除操作不可恢复 /// - 会级联删除所有相关成员记录 /// - 如果活动不存在,将返回404错误 /// - 建议在删除前先查询确认活动信息 /// /// 拓客活动ID /// 无返回值 /// 拓客活动删除成功 /// 拓客活动不存在 /// 服务器内部错误 [HttpDelete("{id}")] public async Task Delete(string id) { // 删除拓客活动成员 await _db.Deleteable().Where(u => u.EventId == id).ExecuteCommandAsync(); // 删除拓客活动 var isOk = await _db.Deleteable().Where(p => p.Id == id).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh("删除拓客活动失败"); } #endregion #region 更新拓客目标数量 /// /// 更新拓客目标数量 /// /// 拓客活动ID /// 拓客目标数量 /// [HttpPut("{id}/target")] public async Task UpdateTarget(string id, int target) { var isOk = await _db.Updateable().SetColumns(it => new LqEventUserEntity { EventTarget = target }).Where(x => x.EventId == id).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh("更新拓客目标数量失败"); } #endregion #region 获取拓客目标数量 /// /// 获取拓客目标数量 /// /// 拓客活动ID /// [HttpGet("{id}/target")] public async Task GetTarget(string id) { return await _db.Queryable().Where(x => x.EventId == id).Select(x => x.EventTarget).FirstAsync(); } #endregion #region 根据用户ID获取参与的拓客活动 /// /// 根据用户ID获取参与的拓客活动 /// /// /// 根据用户ID查询该用户参与的所有拓客活动,支持时间范围筛选。 /// 返回结果包含活动基础信息和用户在该活动中的详细信息。 /// /// 示例请求: /// GET /api/Extend/LqEvent/user/user001?startTime=2024-01-01&endTime=2024-12-31 /// /// 参数说明: /// - userId: 用户ID(必填) /// - startTime: 开始时间(可选),查询在此时间之后开始的活动 /// - endTime: 结束时间(可选),查询在此时间之前结束的活动 /// /// 返回数据包含: /// - 活动基础信息(ID、名称、编号、负责人、开始时间、结束时间) /// - 用户参与信息(部门ID、战队名称、目标数量等) /// /// 用户ID /// 开始时间(可选) /// 结束时间(可选) /// 用户参与的拓客活动列表 /// 成功返回用户参与的拓客活动列表 /// 请求参数错误 /// 服务器内部错误 [HttpGet("user/{userId}")] [ProducesResponseType(typeof(List), 200)] [ProducesResponseType(400)] [ProducesResponseType(500)] public async Task> GetUserEvents(string userId, [FromQuery] DateTime? startTime = null, [FromQuery] DateTime? endTime = null) { try { // 先测试简单的查询 var eventUsers = await _db.Queryable().Where(u => u.UserId == userId).ToListAsync(); if (!eventUsers.Any()) { return new List(); } var eventIds = eventUsers.Select(u => u.EventId).ToList(); // 查询活动信息 var events = await _db.Queryable().Where(e => eventIds.Contains(e.Id)).ToListAsync(); // 时间范围筛选 if (startTime.HasValue) { events = events.Where(e => e.StartTime >= startTime.Value).ToList(); } if (endTime.HasValue) { events = events.Where(e => e.EndTime <= endTime.Value).ToList(); } // 构建结果 var result = new List(); foreach (var eventUser in eventUsers) { var eventInfo = events.FirstOrDefault(e => e.Id == eventUser.EventId); if (eventInfo != null) { result.Add( new LqEventUserEventOutput { // 活动基础信息 EventId = eventInfo.Id, EventName = eventInfo.EventName, EventNumber = eventInfo.EventNumber, EventCoordinator = eventInfo.EventCoordinator, StartTime = eventInfo.StartTime, EndTime = eventInfo.EndTime, // 用户参与信息 UserId = eventUser.UserId, DepId = eventUser.DepId, TeamName = eventUser.TeamName, EventTarget = eventUser.EventTarget, CreationTime = eventUser.CreationTime, CreationUser = eventUser.CreationUser, StoreId = eventUser.StoreId, } ); } } // 按开始时间降序排列 return result.OrderByDescending(x => x.StartTime).ToList(); } catch (Exception ex) { throw NCCException.Oh("获取用户参与的拓客活动失败", ex); } } #endregion #region 根据用户ID获取当前参与的拓客活动 /// /// 根据用户ID获取当前参与的拓客活动列表 /// /// /// 根据用户ID查询当前正在进行的拓客活动信息 /// 返回用户参与的所有活动详情,包括活动基本信息、用户目标、门店信息等 /// 如果没有当前活动,返回空列表 /// /// 示例请求: /// ```json /// GET /api/Extend/LqEvent/user/{userId}/current /// ``` /// /// 参数说明: /// - userId: 用户ID,必填参数 /// /// 返回信息包括: /// - 活动基本信息(ID、名称、编号、负责人、时间) /// - 用户参与信息(用户ID、部门ID、战队名称、目标数量) /// - 门店信息(门店ID、门店名称) /// - 创建信息(创建时间、创建用户) /// /// 用户ID /// 用户当前参与的拓客活动列表,无活动时返回空列表 /// 成功返回活动列表(可能为空) /// 参数错误,用户ID不能为空 [HttpGet("user/{userId}/current")] public async Task GetCurrentEvent(string userId) { if (string.IsNullOrEmpty(userId)) { throw NCCException.Oh("用户ID不能为空"); } try { var currentTime = DateTime.Now; // 先检查用户是否有活动记录 var userEventCount = await _db.Queryable().Where(eu => eu.UserId == userId).CountAsync(); if (userEventCount == 0) { return null; } // 使用多表查询方式,一次性获取所有数据 var eventUsers = await _db.Queryable((eventUser, eventInfo) => eventUser.EventId == eventInfo.Id) .Where((eventUser, eventInfo) => eventUser.UserId == userId && eventInfo.StartTime <= currentTime && eventInfo.EndTime >= currentTime) .Select( (eventUser, eventInfo) => new LqEventUserEventOutput { EventId = eventUser.EventId, EventName = eventInfo.EventName, EventNumber = eventInfo.EventNumber, EventCoordinator = eventInfo.EventCoordinator, StartTime = eventInfo.StartTime, EndTime = eventInfo.EndTime, UserId = eventUser.UserId, DepId = eventUser.DepId, TeamName = eventUser.TeamName, EventTarget = eventUser.EventTarget, CreationTime = eventUser.CreationTime, CreationUser = eventUser.CreationUser, StoreId = eventUser.StoreId, StoreName = null, // 不需要门店信息 } ) .ToListAsync(); // 如果没有查询到当前活动,返回空列表 return eventUsers ?? new List(); } catch (Exception ex) { throw NCCException.Oh($"查询用户 {userId} 当前活动失败: {ex.Message}", ex); } } #endregion #region 根据活动ID获取战队统计数据 /// /// 根据活动ID获取战队统计数据 /// /// /// 根据活动ID查询该活动下所有门店和战队的统计数据 /// 返回按门店和战队分组的拓客数据 /// /// 示例请求: /// ```json /// GET /api/Extend/LqEvent/team-data/{eventId} /// ``` /// /// 参数说明: /// - eventId: 活动ID,必填参数 /// /// 返回信息包括: /// - 门店信息(门店ID、门店名称) /// - 战队信息(战队名称) /// - 用户信息(用户ID、用户姓名、拓客数量、活动目标) /// /// 活动ID /// 按门店和战队分组的统计数据 /// 成功返回统计数据 /// 参数错误,活动ID不能为空 [HttpGet("team-data/{eventId}")] public async Task GetTeamDataByEventId(string eventId) { if (string.IsNullOrEmpty(eventId)) { throw NCCException.Oh("活动ID不能为空"); } try { // 使用SqlFunc子查询,一次性获取所有需要的数据,避免多次查询和内存合并 var teamData = await _db.Queryable() .Where(eventUser => eventUser.EventId == eventId) .Select(eventUser => new { StoreId = eventUser.StoreId, StoreName = SqlFunc.Subqueryable().Where(md => md.Id == eventUser.StoreId).Select(md => md.Dm), TeamName = eventUser.TeamName, ExpansionUserId = eventUser.UserId, ExpansionUserName = SqlFunc.Subqueryable().Where(u => u.Id == eventUser.UserId).Select(u => u.RealName), EventTarget = eventUser.EventTarget, ExpansionCount = SqlFunc.Subqueryable().Where(tkjlb => tkjlb.EventId == eventId && tkjlb.ExpansionUserId == eventUser.UserId).Count(), }) .ToListAsync(); // 按门店和战队分组数据 var result = teamData .GroupBy(x => new { x.StoreId, x.StoreName }) .Select(storeGroup => new StoreTeamDataOutput { StoreId = storeGroup.Key.StoreId, StoreName = storeGroup.Key.StoreName, TeamList = storeGroup .GroupBy(x => x.TeamName) .Select(teamGroup => new TeamInfoOutput { TeamName = teamGroup.Key, TeamUserInfo = teamGroup .Select(user => new TeamUserInfoOutput { ExpansionUserId = user.ExpansionUserId, ExpansionUserName = user.ExpansionUserName, ExpansionCount = user.ExpansionCount, EventTarget = user.EventTarget, }) .ToList(), }) .ToList(), }) .ToList(); return result; } catch (Exception ex) { throw NCCException.Oh($"查询活动 {eventId} 战队统计数据失败: {ex.Message}", ex); } } #endregion #region Excel导入拓客活动用户 /// /// Excel导入拓客活动用户 /// /// /// 通过Excel文件导入拓客活动用户数据,支持批量导入。 /// Excel列名:员工手机号、姓名、战队、门店、目标张数 /// /// 导入流程: /// 1. 通过员工手机号查找用户信息,获取用户ID和组织ID /// 2. 通过门店中文名称查找门店信息,获取门店ID /// 3. 验证数据完整性 /// 4. 返回成功和失败的数据列表 /// /// 示例请求: /// POST /api/Extend/LqEvent/import-users /// Content-Type: multipart/form-data /// /// 参数: /// - file: Excel文件 /// /// 返回数据: /// - SuccessCount: 成功数量 /// - FailCount: 失败数量 /// - SuccessData: 成功的数据列表 /// - FailData: 失败的数据列表(包含错误信息) /// /// Excel文件 /// 导入结果 /// 导入完成,返回成功和失败的数据统计 /// 请求参数错误或文件格式不正确 /// 服务器内部错误 [HttpPost("import-users")] public async Task ImportUsers(IFormFile file) { try { if (file == null || file.Length == 0) { throw NCCException.Oh("请选择要导入的Excel文件"); } var result = new LqEventImportResult(); // 读取Excel文件 var excelData = await ReadExcelFile(file); result.TotalCount = excelData.Count; foreach (var row in excelData) { try { var importError = new LqEventImportError { RowNumber = row.RowNumber, MobilePhone = row.MobilePhone, Name = row.Name, TeamName = row.TeamName, StoreName = row.StoreName, TargetCount = row.TargetCount, }; // 验证必填字段 if (string.IsNullOrEmpty(row.MobilePhone)) { importError.ErrorMessage = "员工手机号不能为空"; result.FailData.Add(importError); result.FailCount++; continue; } // 通过手机号查找用户 var user = await _db.Queryable().Where(u => u.MobilePhone == row.MobilePhone).FirstAsync(); if (user == null) { importError.ErrorMessage = $"未找到手机号为 {row.MobilePhone} 的用户"; result.FailData.Add(importError); result.FailCount++; continue; } // 获取用户组织ID(部门ID) if (string.IsNullOrEmpty(user.OrganizeId)) { importError.ErrorMessage = $"用户 {user.RealName} 没有关联的组织信息"; result.FailData.Add(importError); result.FailCount++; continue; } // 查找门店信息 string storeId = null; if (!string.IsNullOrEmpty(row.StoreName)) { var store = await _db.Queryable().Where(s => s.Dm == row.StoreName).FirstAsync(); if (store == null) { importError.ErrorMessage = $"未找到名称为 {row.StoreName} 的门店"; result.FailData.Add(importError); result.FailCount++; continue; } storeId = store.Id; } // 创建成功的数据 var successData = new NCC.Extend.Entitys.Dto.LqEventUser.LqEventUserCrInput { Id = YitIdHelper.NextId().ToString(), UserId = user.Id, DepId = user.OrganizeId, TeamName = row.TeamName, StoreId = storeId, TargetCount = row.TargetCount, }; result.SuccessData.Add(successData); result.SuccessCount++; } catch (Exception ex) { var importError = new LqEventImportError { RowNumber = row.RowNumber, MobilePhone = row.MobilePhone, Name = row.Name, TeamName = row.TeamName, StoreName = row.StoreName, TargetCount = row.TargetCount, ErrorMessage = $"处理数据时发生错误: {ex.Message}", }; result.FailData.Add(importError); result.FailCount++; } } return result; } catch (Exception ex) { throw NCCException.Oh($"导入拓客活动用户失败: {ex.Message}", ex); } } /// /// 读取Excel文件数据 /// /// Excel文件 /// Excel数据列表 [NonAction] private async Task> ReadExcelFile(IFormFile file) { var result = new List(); // 保存临时文件 var tempFilePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString() + Path.GetExtension(file.FileName)); try { using (var stream = new FileStream(tempFilePath, FileMode.Create)) { await file.CopyToAsync(stream); } // 使用ExcelImportHelper读取Excel文件 var dataTable = ExcelImportHelper.ToDataTable(tempFilePath, 0, 0); // 调试信息:输出总行数和列数 Console.WriteLine($"Excel总行数: {dataTable.Rows.Count}, 总列数: {dataTable.Columns.Count}"); // 调试信息:输出所有行的数据 for (int debugRow = 0; debugRow < dataTable.Rows.Count; debugRow++) { var debugRowData = dataTable.Rows[debugRow]; var debugValues = new List(); for (int debugCol = 0; debugCol < debugRowData.ItemArray.Length; debugCol++) { debugValues.Add(debugRowData[debugCol]?.ToString() ?? "null"); } Console.WriteLine($"调试第{debugRow + 1}行: {string.Join(", ", debugValues)}"); } // 从第1行开始读取数据(没有标题行) for (int i = 0; i < dataTable.Rows.Count; i++) { var row = dataTable.Rows[i]; var mobilePhone = row[0]?.ToString()?.Trim(); var name = row[1]?.ToString()?.Trim(); var teamName = row[2]?.ToString()?.Trim(); var storeName = row[3]?.ToString()?.Trim(); var targetCountStr = row[4]?.ToString()?.Trim(); // 调试信息:输出每一行读取的数据 Console.WriteLine($"第{i + 1}行数据: 手机号={mobilePhone}, 姓名={name}, 战队={teamName}, 门店={storeName}, 目标={targetCountStr}"); int targetCount = 0; if (!string.IsNullOrEmpty(targetCountStr) && int.TryParse(targetCountStr, out int target)) { targetCount = target; } // 跳过空行 if (string.IsNullOrEmpty(mobilePhone) && string.IsNullOrEmpty(name)) { Console.WriteLine($"第{i + 1}行被跳过:空行"); continue; } result.Add( new ExcelImportRow { RowNumber = i + 1, // Excel行号从1开始 MobilePhone = mobilePhone, Name = name, TeamName = teamName, StoreName = storeName, TargetCount = targetCount, } ); } } finally { // 清理临时文件 if (File.Exists(tempFilePath)) { File.Delete(tempFilePath); } } return result; } /// /// Excel导入行数据 /// private class ExcelImportRow { public int RowNumber { get; set; } public string MobilePhone { get; set; } public string Name { get; set; } public string TeamName { get; set; } public string StoreName { get; set; } public int TargetCount { get; set; } = 0; } #endregion #region 获取拓客类型枚举内容 /// /// 获取拓客类型枚举内容 /// /// 拓客类型枚举列表 [HttpGet("event-types")] public List GetEventTypes() { return Enum.GetValues() .Select(e => new EnumOutput { Value = (int)e, Name = e.ToString(), Description = e.GetDescription(), }) .ToList(); } #endregion } }