using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Threading.Tasks; using Mapster; using Microsoft.AspNetCore.Mvc; using NCC.Common.Core.Manager; using NCC.Common.Enum; using NCC.Common.Filter; using NCC.Dependency; using NCC.DynamicApiController; using NCC.Extend.Entitys.Dto.LqMdTarget; using NCC.Extend.Entitys.Enum; using NCC.Extend.Entitys.lq_md_target; using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Interfaces.LqMdTarget; using NCC.FriendlyException; using SqlSugar; using Yitter.IdGenerator; namespace NCC.Extend.LqMdTarget { /// /// 门店目标服务 /// [ApiDescriptionSettings(Tag = "绿纤门店目标服务", Name = "LqMdTarget", Order = 200)] [Route("api/Extend/[controller]")] public class LqMdTargetService : ILqMdTargetService, IDynamicApiController, ITransient { private readonly ISqlSugarRepository _lqMdTargetRepository; private readonly SqlSugarScope _db; private readonly IUserManager _userManager; /// /// 初始化一个类型的新实例 /// public LqMdTargetService(ISqlSugarRepository lqMdTargetRepository, IUserManager userManager) { _lqMdTargetRepository = lqMdTargetRepository; _db = _lqMdTargetRepository.Context; _userManager = userManager; } #region 获取门店目标信息 /// /// 获取门店目标信息 /// /// 主键ID /// [HttpGet("{id}")] public async Task GetInfo(string id) { var entity = await _db.Queryable().FirstAsync(p => p.Id == id); _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); var output = entity.Adapt(); return output; } #endregion #region 获取门店目标列表 /// /// 获取门店目标列表 /// /// 请求参数 /// [HttpGet("")] public async Task GetList([FromQuery] LqMdTargetListQueryInput input) { var sidx = input.sidx == null ? "id" : input.sidx; var sort = string.IsNullOrEmpty(input.sort) ? "DESC" : input.sort; var data = await _db.Queryable() .WhereIF(!string.IsNullOrEmpty(input.storeId), p => p.StoreId.Contains(input.storeId)) .WhereIF(!string.IsNullOrEmpty(input.month), p => p.Month == input.month) .WhereIF(!string.IsNullOrEmpty(input.businessUnit), p => p.BusinessUnit.Contains(input.businessUnit)) .WhereIF(!string.IsNullOrEmpty(input.techDepartment), p => p.TechDepartment.Contains(input.techDepartment)) .WhereIF(!string.IsNullOrEmpty(input.educationDepartment), p => p.EducationDepartment.Contains(input.educationDepartment)) .WhereIF(!string.IsNullOrEmpty(input.majorProjectDepartment), p => p.MajorProjectDepartment.Contains(input.majorProjectDepartment)) .Select(it => new LqMdTargetListOutput { id = it.Id, storeId = it.StoreId, month = it.Month, businessUnit = it.BusinessUnit, techDepartment = it.TechDepartment, educationDepartment = it.EducationDepartment, majorProjectDepartment = it.MajorProjectDepartment, businessUnitTarget = it.BusinessUnitTarget, techDepartmentTarget = it.TechDepartmentTarget, educationDepartmentTarget = it.EducationDepartmentTarget, majorProjectDepartmentTarget = it.MajorProjectDepartmentTarget, businessUnitGeneralManager = it.BusinessUnitGeneralManager, businessUnitManager = it.BusinessUnitManager, storeTarget = it.StoreTarget, storeLifeline = it.StoreLifeline, storeConsumeTarget = it.StoreConsumeTarget, storeProjectTarget = it.StoreProjectTarget, storeHeadcountTarget = it.StoreHeadcountTarget, assistantHeadcountTargetStage1 = it.AssistantHeadcountTargetStage1, assistantHeadcountTargetStage2 = it.AssistantHeadcountTargetStage2, createTime = it.CreateTime, createUser = it.CreateUser, updateTime = it.UpdateTime, updateUser = it.UpdateUser, }) .MergeTable() .OrderBy($"{sidx} {sort}") .ToPagedListAsync(input.currentPage, input.pageSize); return PageResult.SqlSugarPageResult(data); } #endregion #region 新建门店目标 /// /// 新建门店目标 /// /// 参数 /// [HttpPost("")] public async Task Create([FromBody] LqMdTargetCrInput input) { var userInfo = await _userManager.GetUserInfo(); // 验证门店ID和月份的唯一性 var exists = await _db.Queryable().Where(p => p.StoreId == input.storeId && p.Month == input.month).AnyAsync(); if (exists) { throw NCCException.Oh(ErrorCode.COM1000, "该门店在该月份已存在目标记录"); } // 验证月份格式 if (input.month.Length != 6 || !Regex.IsMatch(input.month, @"^\d{6}$")) { throw NCCException.Oh(ErrorCode.COM1000, "月份格式必须为YYYYMM(如:202501)"); } var entity = input.Adapt(); entity.Id = YitIdHelper.NextId().ToString(); entity.CreateTime = DateTime.Now; entity.CreateUser = userInfo.userId; var isOk = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000); } #endregion #region 根据门店批量创建数据 /// /// 根据门店批量创建数据 /// 会删除设置月份的所有门店数据(谨用!!!) /// /// 月份(YYYYMM格式) /// [HttpPost("BatchCreateByStores")] public async Task BatchCreateByStores([FromQuery] string month) { var userInfo = await _userManager.GetUserInfo(); if (userInfo == null || string.IsNullOrEmpty(userInfo.userId)) { throw NCCException.Oh("用户信息获取失败,请重新登录"); } // 验证月份格式 if (string.IsNullOrEmpty(month) || month.Length != 6 || !Regex.IsMatch(month, @"^\d{6}$")) { throw NCCException.Oh("月份格式必须为YYYYMM(如:202501)"); } //查询门店列表 var storeList = await _db.Queryable().Select(p => p.Id).ToListAsync(); if (storeList == null || storeList.Count == 0) { return new { success = true, message = "没有有效的门店数据", createdCount = 0 }; } // 删除设置月份的所有门店数据 await _db.Deleteable().Where(p => p.Month == month).ExecuteCommandAsync(); // 批量创建 var entities = new List(); foreach (var storeId in storeList) { if (string.IsNullOrEmpty(storeId)) continue; entities.Add(new LqMdTargetEntity { Id = YitIdHelper.NextId().ToString(), StoreId = storeId, Month = month, BusinessUnit = "", TechDepartment = "", EducationDepartment = "", MajorProjectDepartment = "", BusinessUnitTarget = 0, TechDepartmentTarget = 0, EducationDepartmentTarget = 0, BusinessUnitGeneralManager = "", BusinessUnitManager = "", StoreTarget = 0, StoreLifeline = 0, StoreConsumeTarget = 0, StoreProjectTarget = 0, StoreHeadcountTarget = 0, AssistantHeadcountTargetStage1 = 0, AssistantHeadcountTargetStage2 = 0, CreateTime = DateTime.Now, CreateUser = userInfo.userId, }); } if (entities.Count == 0) { return new { success = true, message = "没有有效的门店数据可创建", createdCount = 0 }; } var isOk = await _db.Insertable(entities).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1000, "批量创建失败"); return new { success = true, message = $"成功创建{isOk}条记录", createdCount = isOk }; } #endregion #region 更新门店目标 /// /// 更新门店目标 /// /// 主键ID /// 参数 /// [HttpPut("{id}")] public async Task Update(string id, [FromBody] LqMdTargetUpInput input) { var userInfo = await _userManager.GetUserInfo(); // 验证记录是否存在 var entity = await _db.Queryable().FirstAsync(p => p.Id == id); _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); // 验证月份格式 if (input.month.Length != 6 || !Regex.IsMatch(input.month, @"^\d{6}$")) { throw NCCException.Oh("月份格式必须为YYYYMM(如:202501)"); } // 如果门店ID或月份发生变化,需要验证唯一性 if (entity.StoreId != input.storeId || entity.Month != input.month) { var exists = await _db.Queryable().Where(p => p.StoreId == input.storeId && p.Month == input.month && p.Id != id).AnyAsync(); if (exists) { throw NCCException.Oh("该门店在该月份已存在目标记录"); } } var updateEntity = input.Adapt(); updateEntity.Id = id; updateEntity.UpdateTime = DateTime.Now; updateEntity.UpdateUser = userInfo.userId; var isOk = await _db.Updateable(updateEntity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1001); } #endregion #region 删除门店目标 /// /// 删除门店目标 /// /// 主键ID /// [HttpDelete("{id}")] public async Task Delete(string id) { var entity = await _db.Queryable().FirstAsync(p => p.Id == id); _ = entity ?? throw NCCException.Oh(ErrorCode.COM1005); var isOk = await _db.Deleteable().Where(d => d.Id == id).ExecuteCommandAsync(); if (!(isOk > 0)) throw NCCException.Oh(ErrorCode.COM1002); } #endregion #region 同步上月数据 /// /// 同步上月数据 /// /// 目标月份(YYYYMM格式),如果为空则同步到当前月份 /// [HttpPost("SyncLastMonthData")] public async Task SyncLastMonthData([FromQuery] string targetMonth = null) { var userInfo = await _userManager.GetUserInfo(); // 确定目标月份 string targetMonthStr; if (string.IsNullOrEmpty(targetMonth)) { // 如果未指定,使用当前月份 var now = DateTime.Now; targetMonthStr = now.ToString("yyyyMM"); } else { // 验证月份格式 if (targetMonth.Length != 6 || !Regex.IsMatch(targetMonth, @"^\d{6}$")) { throw NCCException.Oh(ErrorCode.COM1000, "月份格式必须为YYYYMM(如:202501)"); } targetMonthStr = targetMonth; } // 计算上个月份 var targetDate = DateTime.ParseExact(targetMonthStr, "yyyyMM", null); var lastMonthDate = targetDate.AddMonths(-1); var lastMonthStr = lastMonthDate.ToString("yyyyMM"); // 查询上个月的所有门店目标数据 var lastMonthData = await _db.Queryable() .Where(p => p.Month == lastMonthStr) .ToListAsync(); if (lastMonthData == null || lastMonthData.Count == 0) { return new { success = true, message = $"上个月({lastMonthStr})没有数据可同步", syncedCount = 0, skippedCount = 0 }; } // 查询目标月份已存在的记录 var existingStoreIds = await _db.Queryable() .Where(p => p.Month == targetMonthStr) .Select(p => p.StoreId) .ToListAsync(); // 过滤掉已存在的门店,只同步新门店 var newEntities = lastMonthData .Where(p => !existingStoreIds.Contains(p.StoreId)) .Select(p => new LqMdTargetEntity { Id = YitIdHelper.NextId().ToString(), StoreId = p.StoreId, Month = targetMonthStr, BusinessUnit = p.BusinessUnit, TechDepartment = p.TechDepartment, EducationDepartment = p.EducationDepartment, MajorProjectDepartment = p.MajorProjectDepartment, BusinessUnitTarget = p.BusinessUnitTarget, TechDepartmentTarget = p.TechDepartmentTarget, EducationDepartmentTarget = p.EducationDepartmentTarget, BusinessUnitGeneralManager = p.BusinessUnitGeneralManager, BusinessUnitManager = p.BusinessUnitManager, StoreTarget = p.StoreTarget, StoreLifeline = p.StoreLifeline, StoreConsumeTarget = p.StoreConsumeTarget, StoreProjectTarget = p.StoreProjectTarget, StoreHeadcountTarget = p.StoreHeadcountTarget, AssistantHeadcountTargetStage1 = p.AssistantHeadcountTargetStage1, AssistantHeadcountTargetStage2 = p.AssistantHeadcountTargetStage2, CreateTime = DateTime.Now, CreateUser = userInfo.userId, }) .ToList(); int syncedCount = 0; int skippedCount = lastMonthData.Count - newEntities.Count; if (newEntities.Count > 0) { syncedCount = await _db.Insertable(newEntities).ExecuteCommandAsync(); } return new { success = true, message = $"同步完成:成功同步{syncedCount}条记录,跳过{skippedCount}条已存在的记录", syncedCount = syncedCount, skippedCount = skippedCount, lastMonth = lastMonthStr, targetMonth = targetMonthStr }; } #endregion #region 获取部门管理的门店列表 /// /// 获取部门管理的门店列表 /// /// /// 根据年月、组织类型、部门ID查询该部门在该月份管理的门店列表 /// /// 示例请求: /// ```json /// { /// "month": "202511", /// "organizationType": "事业部", /// "departmentId": "部门ID" /// } /// ``` /// /// 参数说明: /// - month: 年月,格式为YYYYMM(如:202511表示2025年11月) /// - organizationType: 组织类型,可选值:事业部、科技部、教育部、大项目部 /// - departmentId: 部门ID /// /// 查询参数 /// 门店列表(包含门店ID和门店名称) /// 成功返回门店列表 /// 参数错误 [HttpPost("GetManagedStores")] public async Task GetManagedStores([FromBody] GetManagedStoresInput input) { try { // 验证参数 if (input == null) { throw NCCException.Oh("参数不能为空"); } if (string.IsNullOrEmpty(input.Month)) { throw NCCException.Oh("年月不能为空"); } if (input.Month.Length != 6 || !Regex.IsMatch(input.Month, @"^\d{6}$")) { throw NCCException.Oh("年月格式必须为YYYYMM(如:202511)"); } if (string.IsNullOrEmpty(input.OrganizationType)) { throw NCCException.Oh("组织类型不能为空"); } if (string.IsNullOrEmpty(input.DepartmentId)) { throw NCCException.Oh("部门ID不能为空"); } // 构建查询条件(使用多表关联方式) var query = _db.Queryable( (t, s) => t.StoreId == s.Id) .Where((t, s) => t.Month == input.Month); // 根据组织类型添加部门过滤条件 switch (input.OrganizationType) { case "事业部": query = query.Where((t, s) => t.BusinessUnit == input.DepartmentId); break; case "科技部": query = query.Where((t, s) => t.TechDepartment == input.DepartmentId); break; case "教育部": query = query.Where((t, s) => t.EducationDepartment == input.DepartmentId); break; case "大项目部": query = query.Where((t, s) => t.MajorProjectDepartment == input.DepartmentId); break; default: throw NCCException.Oh($"不支持的组织类型:{input.OrganizationType},支持的类型:事业部、科技部、教育部、大项目部"); } // 关联门店表获取门店名称 var result = await query .Select((t, s) => new ManagedStoreOutput { StoreId = t.StoreId, StoreName = s.Dm ?? "未知门店" }) .ToListAsync(); return result; } catch (Exception ex) { throw NCCException.Oh($"查询失败:{ex.Message}"); } } #endregion } }