diff --git a/ExportFiles/退卡明细_20251228193529.xls b/ExportFiles/退卡明细_20251228193529.xls new file mode 100644 index 0000000..df7e27d --- /dev/null +++ b/ExportFiles/退卡明细_20251228193529.xls diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListOutput.cs new file mode 100644 index 0000000..8b6f121 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListOutput.cs @@ -0,0 +1,86 @@ +using System; + +namespace NCC.Extend.Entitys.Dto.LqHytkHytk +{ + /// + /// 退卡明细列表输出参数 + /// + public class RefundDetailListOutput + { + /// + /// 门店ID + /// + public string storeId { get; set; } + + /// + /// 门店名称 + /// + public string storeName { get; set; } + + /// + /// 会员ID + /// + public string memberId { get; set; } + + /// + /// 会员名称 + /// + public string memberName { get; set; } + + /// + /// 会员电话 + /// + public string memberPhone { get; set; } + + /// + /// 退卡时间 + /// + public DateTime? refundTime { get; set; } + + /// + /// 退卡品项ID + /// + public string itemId { get; set; } + + /// + /// 退卡品项名称 + /// + public string itemName { get; set; } + + /// + /// 退卡数量 + /// + public decimal refundQuantity { get; set; } + + /// + /// 单价 + /// + public decimal unitPrice { get; set; } + + /// + /// 总价 + /// + public decimal totalPrice { get; set; } + + /// + /// 业绩类型 + /// + public string performanceType { get; set; } + + /// + /// 科美类型 + /// + public string beautyType { get; set; } + + /// + /// 来源类型 + /// + public string sourceType { get; set; } + + /// + /// 品项分类 + /// + public string itemCategory { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListQueryInput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListQueryInput.cs new file mode 100644 index 0000000..fe0c7c5 --- /dev/null +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqHytkHytk/RefundDetailListQueryInput.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; + +namespace NCC.Extend.Entitys.Dto.LqHytkHytk +{ + /// + /// 退卡明细列表查询输入参数 + /// + public class RefundDetailListQueryInput + { + /// + /// 当前页码 + /// + public int currentPage { get; set; } = 1; + + /// + /// 每页数量 + /// + public int pageSize { get; set; } = 20; + + /// + /// 排序字段 + /// + public string sidx { get; set; } = "tksj"; + + /// + /// 排序方式(asc/desc) + /// + public string sort { get; set; } = "desc"; + + /// + /// 门店ID列表(多门店筛选) + /// + public List storeIds { get; set; } + + /// + /// 会员ID(会员筛选) + /// + public string memberId { get; set; } + + /// + /// 开始时间(时间范围筛选) + /// + public DateTime? startTime { get; set; } + + /// + /// 结束时间(时间范围筛选) + /// + public DateTime? endTime { get; set; } + + /// + /// 品项ID(品项筛选) + /// + public string itemId { get; set; } + + /// + /// 业绩类型(业绩类型筛选) + /// + public string performanceType { get; set; } + + /// + /// 科美类型(科美类型筛选) + /// + public string beautyType { get; set; } + + /// + /// 来源类型(来源类型筛选) + /// + public string sourceType { get; set; } + + /// + /// 品项分类(品项分类筛选) + /// + public string itemCategory { get; set; } + } +} + diff --git a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxListOutput.cs b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxListOutput.cs index 796345d..62ca416 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxListOutput.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend.Entitys/Dto/LqKhxx/LqKhxxListOutput.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using NCC.Code; using NCC.Extend.Entitys.Enum; @@ -253,6 +254,26 @@ namespace NCC.Extend.Entitys.Dto.LqKhxx public int consumeLevel { get; set; } /// + /// 消费等级名称 + /// + public string consumeLevelName + { + get + { + var levelMap = new Dictionary + { + { 0, "D" }, + { 1, "C" }, + { 2, "B" }, + { 3, "A" }, + { 4, "A+" }, + { 5, "A++" } + }; + return levelMap.ContainsKey(consumeLevel) ? levelMap[consumeLevel] : "D"; + } + } + + /// /// 消费等级更新时间 /// public DateTime? consumeLevelUpdateTime { get; set; } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs index 6ebe09a..6731e6a 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqHytkHytkService.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Mapster; using Microsoft.AspNetCore.Mvc; @@ -26,6 +28,8 @@ using NCC.Extend.Entitys.lq_hytk_kjbsyj; using NCC.Extend.Entitys.lq_hytk_mx; using NCC.Extend.Entitys.lq_kd_pxmx; using NCC.Extend.Entitys.lq_xmzl; +using NCC.Extend.Entitys.lq_khxx; +using NCC.Extend.Entitys.lq_mdxx; using NCC.Extend.Interfaces.LqHytkHytk; using NCC.FriendlyException; using NCC.JsonSerialization; @@ -810,5 +814,445 @@ namespace NCC.Extend.LqHytkHytk } } #endregion + + #region 退卡明细查询 + /// + /// 获取退卡明细列表 + /// + /// + /// 获取退卡明细列表,支持多门店、会员、时间范围、品项、业绩类型、科美类型、来源类型、品项分类等筛选 + /// + /// 示例请求: + /// ```json + /// GET /api/Extend/LqHytkHytk/refund-detail-list?storeIds=门店ID1,门店ID2&memberId=会员ID&startTime=2025-01-01&endTime=2025-12-31&currentPage=1&pageSize=20 + /// ``` + /// + /// 参数说明: + /// - storeIds: 门店ID列表(可选,多门店筛选) + /// - memberId: 会员ID(可选) + /// - startTime: 开始时间(可选,时间范围筛选) + /// - endTime: 结束时间(可选,时间范围筛选) + /// - itemId: 品项ID(可选) + /// - performanceType: 业绩类型(可选) + /// - beautyType: 科美类型(可选) + /// - sourceType: 来源类型(可选) + /// - itemCategory: 品项分类(可选) + /// - currentPage: 当前页码(必填) + /// - pageSize: 每页数量(必填) + /// + /// 查询参数 + /// 分页的退卡明细列表 + /// 成功返回退卡明细列表 + /// 参数错误 + /// 服务器内部错误 + [HttpPost("refund-detail-list")] + public async Task GetRefundDetailList([FromBody] RefundDetailListQueryInput input) + { + try + { + if (input == null) + { + throw NCCException.Oh("参数不能为空"); + } + + // 1. 先查询退卡明细表 + var mxQuery = _db.Queryable() + .Where(mx => mx.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(!string.IsNullOrEmpty(input.itemId), mx => mx.Px == input.itemId) + .WhereIF(!string.IsNullOrEmpty(input.performanceType), mx => mx.PerformanceType == input.performanceType) + .WhereIF(!string.IsNullOrEmpty(input.beautyType), mx => mx.BeautyType == input.beautyType) + .WhereIF(!string.IsNullOrEmpty(input.sourceType), mx => mx.SourceType == input.sourceType) + .WhereIF(!string.IsNullOrEmpty(input.itemCategory), mx => mx.ItemCategory == input.itemCategory) + .WhereIF(input.startTime.HasValue, mx => mx.Tksj.HasValue && mx.Tksj >= input.startTime.Value) + .WhereIF(input.endTime.HasValue, mx => mx.Tksj.HasValue && mx.Tksj <= input.endTime.Value); + + var mxList = await mxQuery.ToListAsync(); + + if (!mxList.Any()) + { + return PageResult.SqlSugarPageResult(new SqlSugarPagedList()); + } + + // 2. 批量查询退卡信息表 + var refundInfoIds = mxList.Select(x => x.RefundInfoId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var refundInfoList = new List(); + if (refundInfoIds.Any()) + { + refundInfoList = await _db.Queryable() + .Where(x => refundInfoIds.Contains(x.Id)) + .WhereIF(input.storeIds != null && input.storeIds.Any(), x => input.storeIds.Contains(x.Md)) + .WhereIF(!string.IsNullOrEmpty(input.memberId), x => x.Hy == input.memberId) + .WhereIF(input.startTime.HasValue && !mxList.Any(m => m.Tksj.HasValue), x => x.Tksj.HasValue && x.Tksj >= input.startTime.Value) + .WhereIF(input.endTime.HasValue && !mxList.Any(m => m.Tksj.HasValue), x => x.Tksj.HasValue && x.Tksj <= input.endTime.Value) + .ToListAsync(); + } + + var refundInfoDict = refundInfoList.ToDictionary(x => x.Id, x => x); + + // 3. 批量查询门店信息 + var storeIds = refundInfoList.Select(x => x.Md).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var storeDict = new Dictionary(); + if (storeIds.Any()) + { + var stores = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + storeDict = stores.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + + // 4. 批量查询会员信息 + var memberIds = mxList.Select(x => x.MemberId).Where(x => !string.IsNullOrEmpty(x)) + .Concat(refundInfoList.Select(x => x.Hy).Where(x => !string.IsNullOrEmpty(x))) + .Distinct().ToList(); + var memberDict = new Dictionary(); + if (memberIds.Any()) + { + var members = await _db.Queryable() + .Where(x => memberIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Sjh }) + .ToListAsync(); + memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); + } + + // 5. 组装数据 + var resultList = new List(); + foreach (var mx in mxList) + { + var refundInfo = refundInfoDict.ContainsKey(mx.RefundInfoId) ? refundInfoDict[mx.RefundInfoId] : null; + + // 应用筛选条件 + if (input.storeIds != null && input.storeIds.Any()) + { + if (refundInfo == null || !input.storeIds.Contains(refundInfo.Md)) + continue; + } + if (!string.IsNullOrEmpty(input.memberId)) + { + if (mx.MemberId != input.memberId && (refundInfo == null || refundInfo.Hy != input.memberId)) + continue; + } + + var memberId = mx.MemberId ?? (refundInfo?.Hy); + var refundTime = mx.Tksj ?? refundInfo?.Tksj; + + resultList.Add(new RefundDetailListOutput + { + storeId = refundInfo?.Md, + storeName = refundInfo != null && storeDict.ContainsKey(refundInfo.Md) ? storeDict[refundInfo.Md] : "", + memberId = memberId, + memberName = refundInfo?.Hymc, + memberPhone = !string.IsNullOrEmpty(memberId) && memberDict.ContainsKey(memberId) ? memberDict[memberId] : "", + refundTime = refundTime, + itemId = mx.Px, + itemName = mx.Pxmc, + refundQuantity = mx.ProjectNumber, + unitPrice = mx.Pxjg ?? 0, + totalPrice = mx.Tkje ?? mx.TotalPrice ?? 0, + performanceType = mx.PerformanceType, + beautyType = mx.BeautyType, + sourceType = mx.SourceType, + itemCategory = mx.ItemCategory + }); + } + + // 6. 排序 + var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; + + if (sort.ToLower() == "desc") + { + resultList = resultList.OrderByDescending(x => GetPropertyValue(x, sidx)).ToList(); + } + else + { + resultList = resultList.OrderBy(x => GetPropertyValue(x, sidx)).ToList(); + } + + // 7. 分页 + var total = resultList.Count; + var skip = (input.currentPage - 1) * input.pageSize; + var pagedList = resultList.Skip(skip).Take(input.pageSize).ToList(); + + var pageList = new SqlSugarPagedList + { + list = pagedList, + pagination = new PagedModel + { + PageIndex = input.currentPage, + PageSize = input.pageSize, + Total = total + } + }; + + return PageResult.SqlSugarPageResult(pageList); + } + catch (Exception ex) + { + throw NCCException.Oh($"获取退卡明细列表失败: {ex.Message}"); + } + } + + private object GetPropertyValue(RefundDetailListOutput obj, string propertyName) + { + var prop = typeof(RefundDetailListOutput).GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance); + return prop?.GetValue(obj) ?? ""; + } + + /// + /// 获取退卡明细列表(无分页,用于导出) + /// + /// 查询参数 + /// 退卡明细列表 + [NonAction] + public async Task> GetRefundDetailListNoPaging(RefundDetailListQueryInput input) + { + try + { + // 1. 先查询退卡明细表 + var mxQuery = _db.Queryable() + .Where(mx => mx.IsEffective == StatusEnum.有效.GetHashCode()) + .WhereIF(!string.IsNullOrEmpty(input.itemId), mx => mx.Px == input.itemId) + .WhereIF(!string.IsNullOrEmpty(input.performanceType), mx => mx.PerformanceType == input.performanceType) + .WhereIF(!string.IsNullOrEmpty(input.beautyType), mx => mx.BeautyType == input.beautyType) + .WhereIF(!string.IsNullOrEmpty(input.sourceType), mx => mx.SourceType == input.sourceType) + .WhereIF(!string.IsNullOrEmpty(input.itemCategory), mx => mx.ItemCategory == input.itemCategory) + .WhereIF(input.startTime.HasValue, mx => mx.Tksj.HasValue && mx.Tksj >= input.startTime.Value) + .WhereIF(input.endTime.HasValue, mx => mx.Tksj.HasValue && mx.Tksj <= input.endTime.Value); + + var mxList = await mxQuery.ToListAsync(); + + if (!mxList.Any()) + { + return new List(); + } + + // 2. 批量查询退卡信息表 + var refundInfoIds = mxList.Select(x => x.RefundInfoId).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var refundInfoList = new List(); + if (refundInfoIds.Any()) + { + refundInfoList = await _db.Queryable() + .Where(x => refundInfoIds.Contains(x.Id)) + .WhereIF(input.storeIds != null && input.storeIds.Any(), x => input.storeIds.Contains(x.Md)) + .WhereIF(!string.IsNullOrEmpty(input.memberId), x => x.Hy == input.memberId) + .WhereIF(input.startTime.HasValue && !mxList.Any(m => m.Tksj.HasValue), x => x.Tksj.HasValue && x.Tksj >= input.startTime.Value) + .WhereIF(input.endTime.HasValue && !mxList.Any(m => m.Tksj.HasValue), x => x.Tksj.HasValue && x.Tksj <= input.endTime.Value) + .ToListAsync(); + } + + var refundInfoDict = refundInfoList.ToDictionary(x => x.Id, x => x); + + // 3. 批量查询门店信息 + var storeIds = refundInfoList.Select(x => x.Md).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList(); + var storeDict = new Dictionary(); + if (storeIds.Any()) + { + var stores = await _db.Queryable() + .Where(x => storeIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Dm }) + .ToListAsync(); + storeDict = stores.ToDictionary(x => x.Id, x => x.Dm ?? ""); + } + + // 4. 批量查询会员信息 + var memberIds = mxList.Select(x => x.MemberId).Where(x => !string.IsNullOrEmpty(x)) + .Concat(refundInfoList.Select(x => x.Hy).Where(x => !string.IsNullOrEmpty(x))) + .Distinct().ToList(); + var memberDict = new Dictionary(); + if (memberIds.Any()) + { + var members = await _db.Queryable() + .Where(x => memberIds.Contains(x.Id)) + .Select(x => new { x.Id, x.Sjh }) + .ToListAsync(); + memberDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? ""); + } + + // 5. 组装数据 + var resultList = new List(); + foreach (var mx in mxList) + { + var refundInfo = refundInfoDict.ContainsKey(mx.RefundInfoId) ? refundInfoDict[mx.RefundInfoId] : null; + + // 应用筛选条件 + if (input.storeIds != null && input.storeIds.Any()) + { + if (refundInfo == null || !input.storeIds.Contains(refundInfo.Md)) + continue; + } + if (!string.IsNullOrEmpty(input.memberId)) + { + if (mx.MemberId != input.memberId && (refundInfo == null || refundInfo.Hy != input.memberId)) + continue; + } + + var memberId = mx.MemberId ?? (refundInfo?.Hy); + var refundTime = mx.Tksj ?? refundInfo?.Tksj; + + resultList.Add(new RefundDetailListOutput + { + storeId = refundInfo?.Md, + storeName = refundInfo != null && storeDict.ContainsKey(refundInfo.Md) ? storeDict[refundInfo.Md] : "", + memberId = memberId, + memberName = refundInfo?.Hymc, + memberPhone = !string.IsNullOrEmpty(memberId) && memberDict.ContainsKey(memberId) ? memberDict[memberId] : "", + refundTime = refundTime, + itemId = mx.Px, + itemName = mx.Pxmc, + refundQuantity = mx.ProjectNumber, + unitPrice = mx.Pxjg ?? 0, + totalPrice = mx.Tkje ?? mx.TotalPrice ?? 0, + performanceType = mx.PerformanceType, + beautyType = mx.BeautyType, + sourceType = mx.SourceType, + itemCategory = mx.ItemCategory + }); + } + + // 6. 排序 + var sidx = string.IsNullOrEmpty(input.sidx) ? "refundTime" : input.sidx; + var sort = string.IsNullOrEmpty(input.sort) ? "desc" : input.sort; + + if (sort.ToLower() == "desc") + { + resultList = resultList.OrderByDescending(x => GetPropertyValue(x, sidx)).ToList(); + } + else + { + resultList = resultList.OrderBy(x => GetPropertyValue(x, sidx)).ToList(); + } + + return resultList; + } + catch (Exception ex) + { + throw NCCException.Oh($"获取退卡明细列表失败: {ex.Message}"); + } + } + #endregion + + #region 退卡明细导出 + /// + /// 导出退卡明细 + /// + /// + /// 导出退卡明细到Excel,支持多门店、会员、时间范围、品项、业绩类型、科美类型、来源类型、品项分类等筛选 + /// + /// 示例请求: + /// ```json + /// POST /api/Extend/LqHytkHytk/refund-detail-export + /// { + /// "storeIds": ["门店ID1", "门店ID2"], + /// "memberId": "会员ID", + /// "startTime": "2025-01-01T00:00:00", + /// "endTime": "2025-12-31T23:59:59", + /// "itemId": "品项ID", + /// "performanceType": "业绩类型", + /// "beautyType": "科美类型", + /// "sourceType": "来源类型", + /// "itemCategory": "品项分类" + /// } + /// ``` + /// + /// 查询参数 + /// Excel文件下载信息 + /// 成功返回Excel文件下载链接 + /// 参数错误 + /// 服务器内部错误 + [HttpPost("refund-detail-export")] + public async Task ExportRefundDetail([FromBody] RefundDetailListQueryInput input) + { + try + { + var userInfo = await _userManager.GetUserInfo(); + var exportData = await GetRefundDetailListNoPaging(input); + + if (exportData == null || !exportData.Any()) + { + return new { name = "退卡明细.xls", url = "", message = "没有找到符合条件的数据" }; + } + + // 定义导出字段 + List paramList = + "[{\"value\":\"门店\",\"field\":\"storeName\"},{\"value\":\"会员ID\",\"field\":\"memberId\"},{\"value\":\"会员名称\",\"field\":\"memberName\"},{\"value\":\"会员电话\",\"field\":\"memberPhone\"},{\"value\":\"退卡时间\",\"field\":\"refundTime\"},{\"value\":\"退卡品项ID\",\"field\":\"itemId\"},{\"value\":\"退卡品项名称\",\"field\":\"itemName\"},{\"value\":\"退卡数量\",\"field\":\"refundQuantity\"},{\"value\":\"单价\",\"field\":\"unitPrice\"},{\"value\":\"总价\",\"field\":\"totalPrice\"},{\"value\":\"业绩类型\",\"field\":\"performanceType\"},{\"value\":\"科美类型\",\"field\":\"beautyType\"},{\"value\":\"来源类型\",\"field\":\"sourceType\"},{\"value\":\"品项分类\",\"field\":\"itemCategory\"},]".ToList(); + + ExcelConfig excelconfig = new ExcelConfig(); + excelconfig.FileName = "退卡明细_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".xls"; + excelconfig.HeadFont = "微软雅黑"; + excelconfig.HeadPoint = 10; + excelconfig.IsAllSizeColumn = true; + excelconfig.ColumnModel = new List(); + + // 添加所有字段到导出列 + foreach (var param in paramList) + { + excelconfig.ColumnModel.Add(new ExcelColumnModel() { Column = param.field, ExcelColumn = param.value }); + } + + // 查找项目根目录 + var baseDir = AppContext.BaseDirectory; + var projectRoot = baseDir; + var dir = new DirectoryInfo(baseDir); + + // 优先查找包含 .git 目录的目录(真正的项目根目录) + while (dir != null && dir.Parent != null) + { + try + { + if (dir.GetDirectories(".git").Any()) + { + projectRoot = dir.FullName; + break; + } + } + catch + { + // 忽略访问错误,继续向上查找 + } + dir = dir.Parent; + } + + // 如果没找到 .git 目录,再查找包含 .sln 文件的目录 + if (projectRoot == baseDir) + { + dir = new DirectoryInfo(baseDir); + while (dir != null && dir.Parent != null) + { + try + { + if (dir.GetFiles("*.sln").Any()) + { + projectRoot = dir.FullName; + break; + } + } + catch + { + // 忽略访问错误,继续向上查找 + } + dir = dir.Parent; + } + } + + // 在项目根目录下创建 ExportFiles 文件夹 + var exportFilesPath = Path.Combine(projectRoot, "ExportFiles"); + if (!Directory.Exists(exportFilesPath)) + { + Directory.CreateDirectory(exportFilesPath); + } + var addPath = Path.Combine(exportFilesPath, excelconfig.FileName); + + ExcelExportHelper.Export(exportData, excelconfig, addPath); + var fileName = _userManager.UserId + "|" + addPath + "|xls"; + var output = new { name = excelconfig.FileName, url = "/api/File/Download?encryption=" + DESCEncryption.Encrypt(fileName, "NCC") }; + return output; + } + catch (Exception ex) + { + throw NCCException.Oh($"导出退卡明细失败: {ex.Message}"); + } + } + #endregion } } diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs index 6fbeb1a..0feff54 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqKhxxService.cs @@ -562,7 +562,7 @@ namespace NCC.Extend.LqKhxx exportData = await this.GetNoPagingList(input); } List paramList = - "[{\"value\":\"客户编码\",\"field\":\"id\"},{\"value\":\"客户名称\",\"field\":\"khmc\"},{\"value\":\"手机号\",\"field\":\"sjh\"},{\"value\":\"档案号\",\"field\":\"dah\"},{\"value\":\"性别\",\"field\":\"xb\"},{\"value\":\"公众号状态\",\"field\":\"gzhzt\"},{\"value\":\"微信昵称\",\"field\":\"wxnc\"},{\"value\":\"小程序状态\",\"field\":\"wxxcxzt\"},{\"value\":\"最近登录时间\",\"field\":\"zjdlsj\"},{\"value\":\"客户目前归属\",\"field\":\"khmqgs\"},{\"value\":\"归属门店\",\"field\":\"gsmd\"},{\"value\":\"注册时间\",\"field\":\"zcsj\"},{\"value\":\"客户类型\",\"field\":\"khlx\"},{\"value\":\"客户阶段\",\"field\":\"khjd\"},{\"value\":\"客户消费\",\"field\":\"khxf\"},{\"value\":\"消费频次\",\"field\":\"xfpc\"},{\"value\":\"推荐人\",\"field\":\"tjr\"},{\"value\":\"负责顾问\",\"field\":\"fzgw\"},{\"value\":\"美容师\",\"field\":\"mrs\"},{\"value\":\"进店渠道\",\"field\":\"jdqd\"},{\"value\":\"联系地址\",\"field\":\"lxdz\"},{\"value\":\"备注\",\"field\":\"bz\"},{\"value\":\"阳历生日\",\"field\":\"yanglsr\"},{\"value\":\"阴历生日\",\"field\":\"yinlsr\"},{\"value\":\"年龄\",\"field\":\"ml\"},]".ToList(); + "[{\"value\":\"客户编码\",\"field\":\"id\"},{\"value\":\"客户名称\",\"field\":\"khmc\"},{\"value\":\"手机号\",\"field\":\"sjh\"},{\"value\":\"档案号\",\"field\":\"dah\"},{\"value\":\"性别\",\"field\":\"xb\"},{\"value\":\"公众号状态\",\"field\":\"gzhzt\"},{\"value\":\"微信昵称\",\"field\":\"wxnc\"},{\"value\":\"小程序状态\",\"field\":\"wxxcxzt\"},{\"value\":\"最近登录时间\",\"field\":\"zjdlsj\"},{\"value\":\"客户目前归属\",\"field\":\"khmqgs\"},{\"value\":\"归属门店\",\"field\":\"gsmd\"},{\"value\":\"注册时间\",\"field\":\"zcsj\"},{\"value\":\"客户类型\",\"field\":\"khlx\"},{\"value\":\"客户阶段\",\"field\":\"khjd\"},{\"value\":\"客户消费\",\"field\":\"khxf\"},{\"value\":\"消费频次\",\"field\":\"xfpc\"},{\"value\":\"推荐人\",\"field\":\"tjr\"},{\"value\":\"负责顾问\",\"field\":\"fzgw\"},{\"value\":\"美容师\",\"field\":\"mrs\"},{\"value\":\"进店渠道\",\"field\":\"jdqd\"},{\"value\":\"联系地址\",\"field\":\"lxdz\"},{\"value\":\"备注\",\"field\":\"bz\"},{\"value\":\"阳历生日\",\"field\":\"yanglsr\"},{\"value\":\"阴历生日\",\"field\":\"yinlsr\"},{\"value\":\"年龄\",\"field\":\"ml\"},{\"value\":\"消费等级\",\"field\":\"consumeLevelName\"},{\"value\":\"开单总金额\",\"field\":\"totalBillingAmount\"},{\"value\":\"剩余权益总金额\",\"field\":\"remainingRightsAmount\"},{\"value\":\"首次到店时间\",\"field\":\"firstVisitTime\"},{\"value\":\"最后到店时间\",\"field\":\"lastVisitTime\"},{\"value\":\"到店天数\",\"field\":\"visitDays\"},{\"value\":\"沉睡天数\",\"field\":\"sleepDays\"},]".ToList(); ExcelConfig excelconfig = new ExcelConfig(); excelconfig.FileName = "客户资料.xls"; excelconfig.HeadFont = "微软雅黑"; diff --git a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs index e5e9391..9dca7ff 100644 --- a/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs +++ b/netcore/src/Modularity/Extend/NCC.Extend/LqReportService.cs @@ -4351,11 +4351,11 @@ namespace NCC.Extend storeFilter = $" AND hytk.md IN ('{storeIdsStr}')"; } - // 1. 各门店退卡金额分布(不包含转卡)- 使用原生SQL确保正确 + // 1. 各门店退卡金额分布(不包含转卡)- 使用原生SQL确保正确,使用实退金额 var storeDistributionSql = $@" SELECT hytk.md as StoreId, - COALESCE(SUM(CAST(hytk.tkje AS DECIMAL(18,2))), 0) as RefundAmount, + COALESCE(SUM(CAST(COALESCE(hytk.F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as RefundAmount, COUNT(hytk.F_Id) as RefundCount FROM lq_hytk_hytk hytk WHERE hytk.F_IsEffective = 1 @@ -4390,10 +4390,10 @@ namespace NCC.Extend RefundCount = Convert.ToInt32(x.RefundCount ?? 0) }).OrderByDescending(x => x.RefundAmount).ToList(); - // 2. 总计数据 - 使用原生SQL确保正确(包含转卡,与驾驶舱保持一致) + // 2. 总计数据 - 使用原生SQL确保正确(包含转卡,与驾驶舱保持一致),使用实退金额 var totalStatsSql = $@" SELECT - COALESCE(SUM(CAST(tkje AS DECIMAL(18,2))), 0) as TotalRefundAmount, + COALESCE(SUM(CAST(COALESCE(F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as TotalRefundAmount, COALESCE(SUM(CAST(COALESCE(F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as TotalActualRefundAmount, COUNT(F_Id) as TotalRefundCount FROM lq_hytk_hytk @@ -4409,10 +4409,10 @@ namespace NCC.Extend var totalActualRefundAmount = totalStats != null ? Convert.ToDecimal(totalStats.TotalActualRefundAmount ?? 0) : 0m; var totalRefundCount = totalStats != null ? Convert.ToInt32(totalStats.TotalRefundCount ?? 0) : 0; - // 转卡总计(单独统计)- 使用原生SQL + // 转卡总计(单独统计)- 使用原生SQL,使用实退金额 var transferCardSql = $@" SELECT - COALESCE(SUM(CAST(tkje AS DECIMAL(18,2))), 0) as TotalTransferAmount, + COALESCE(SUM(CAST(COALESCE(F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as TotalTransferAmount, COUNT(F_Id) as TotalTransferCount FROM lq_hytk_hytk WHERE F_IsEffective = 1 @@ -4427,13 +4427,13 @@ namespace NCC.Extend var totalTransferAmount = transferCardStats != null ? Convert.ToDecimal(transferCardStats.TotalTransferAmount ?? 0) : 0m; var totalTransferCount = transferCardStats != null ? Convert.ToInt32(transferCardStats.TotalTransferCount ?? 0) : 0; - // 3. 退卡金额最大的人 - 使用原生SQL + // 3. 退卡金额最大的人 - 使用原生SQL,使用实退金额 // 注意:按 hymc(会员名称)分组,因为同一个会员可能有不同的 hy(会员ID) var maxAmountPersonSql = $@" SELECT MAX(hy) as MemberId, hymc as MemberName, - COALESCE(SUM(CAST(tkje AS DECIMAL(18,2))), 0) as TotalRefundAmount, + COALESCE(SUM(CAST(COALESCE(F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as TotalRefundAmount, COUNT(F_Id) as RefundCount FROM lq_hytk_hytk WHERE F_IsEffective = 1 @@ -4451,13 +4451,13 @@ namespace NCC.Extend var maxAmountPersonResult = await _db.Ado.SqlQueryAsync(maxAmountPersonSql); var maxAmountPerson = maxAmountPersonResult?.FirstOrDefault(); - // 4. 退卡次数最多的人 - 使用原生SQL(按退卡单数统计,一个退卡单算一次) + // 4. 退卡次数最多的人 - 使用原生SQL(按退卡单数统计,一个退卡单算一次),使用实退金额 // 注意:按 hymc(会员名称)分组,因为同一个会员可能有不同的 hy(会员ID) var maxCountPersonSql = $@" SELECT MAX(hy) as MemberId, hymc as MemberName, - COALESCE(SUM(CAST(tkje AS DECIMAL(18,2))), 0) as TotalRefundAmount, + COALESCE(SUM(CAST(COALESCE(F_ActualRefundAmount, 0) AS DECIMAL(18,2))), 0) as TotalRefundAmount, COUNT(F_Id) as RefundCount FROM lq_hytk_hytk WHERE F_IsEffective = 1