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;
using NCC.ClayObject;
using NCC.Common.Configuration;
using NCC.Common.Core.Manager;
using NCC.Common.Enum;
using NCC.Common.Extension;
using NCC.Common.Filter;
using NCC.Common.Helper;
using NCC.Common.Model.NPOI;
using NCC.DataEncryption;
using NCC.Dependency;
using NCC.DynamicApiController;
using NCC.Extend.Entitys.Dto.LqHytkHytk;
using NCC.Extend.Entitys.Dto.LqHytkJksyj;
using NCC.Extend.Entitys.Dto.LqHytkKjbsyj;
using NCC.Extend.Entitys.Dto.LqHytkMx;
using NCC.Extend.Entitys.Enum;
using NCC.Extend.Entitys.lq_hytk_hytk;
using NCC.Extend.Entitys.lq_hytk_jksyj;
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_kd_jksyj;
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;
using SqlSugar;
using Yitter.IdGenerator;
namespace NCC.Extend.LqHytkHytk
{
///
/// 退卡_信息表服务
///
[ApiDescriptionSettings(Tag = "绿纤退卡信息表服务", Name = "LqHytkHytk", Order = 200)]
[Route("api/Extend/[controller]")]
public class LqHytkHytkService : ILqHytkHytkService, IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository _lqHytkHytkRepository;
private readonly ISqlSugarRepository _lqHytkMxRepository;
private readonly ISqlSugarRepository _lqHytkJksyjRepository;
private readonly ISqlSugarRepository _lqHytkKjbsyjRepository;
private readonly SqlSugarScope _db;
private readonly IUserManager _userManager;
///
/// 初始化一个类型的新实例
///
public LqHytkHytkService(
ISqlSugarRepository lqHytkHytkRepository,
ISqlSugarRepository lqHytkMxRepository,
ISqlSugarRepository lqHytkJksyjRepository,
ISqlSugarRepository lqHytkKjbsyjRepository,
IUserManager userManager
)
{
_lqHytkHytkRepository = lqHytkHytkRepository;
_lqHytkMxRepository = lqHytkMxRepository;
_lqHytkJksyjRepository = lqHytkJksyjRepository;
_lqHytkKjbsyjRepository = lqHytkKjbsyjRepository;
_db = _lqHytkHytkRepository.Context;
_userManager = userManager;
}
#region 获取退卡信息列表
///
/// 获取退卡信息列表
///
///
/// 获取退卡记录列表,支持根据健康师ID或科技部老师ID筛选,返回品项明细、健康师业绩和科技部老师业绩
///
/// 示例请求:
/// ```json
/// GET /api/Extend/LqHytkHytk?jksId=健康师ID&kjblsId=科技部老师ID¤tPage=1&pageSize=10
/// ```
///
/// 参数说明:
/// - jksId: 健康师ID(可选,传入后只返回该健康师参与的退卡记录)
/// - kjblsId: 科技部老师ID(可选,传入后只返回该老师参与的退卡记录)
/// - id: 退卡编号(可选)
/// - md: 门店ID(可选)
/// - hy: 会员ID(可选)
/// - tksj: 退卡时间(可选,格式:yyyy-MM-dd,yyyy-MM-dd)
/// - currentPage: 当前页码(必填)
/// - pageSize: 每页数量(必填)
///
/// 返回数据说明:
/// - 退卡基本信息:id、门店信息、会员信息、退卡金额、退卡时间等
/// - lqHytkMxList: 退卡品项明细列表,每个明细包含品项信息、退款金额、项目次数等
/// - lqHytkJksyjList: 健康师业绩列表,每个业绩包含健康师信息、业绩金额、手工费、退卡品项次数等
/// - lqHytkKjbsyjList: 科技部老师业绩列表,每个业绩包含科技部老师信息、业绩金额、手工费、退卡品项次数等
///
/// 查询参数
/// 分页的退卡记录列表,包含退卡基本信息、品项明细、健康师业绩、科技部老师业绩
/// 成功返回退卡列表
/// 参数错误
/// 服务器内部错误
[HttpGet("")]
public async Task GetList([FromQuery] LqHytkHytkListQueryInput input)
{
var sidx = input.sidx == null ? "id" : input.sidx;
List queryTksj = input.tksj != null ? input.tksj.Split(',').ToObeject>() : null;
DateTime? startTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.First()) : null;
DateTime? endTksj = queryTksj != null ? Ext.GetDateTime(queryTksj.Last()) : null;
// 根据是否传入健康师ID或科技部老师ID,动态构建查询
ISugarQueryable baseQuery = null;
if (!string.IsNullOrEmpty(input.jksId) && !string.IsNullOrEmpty(input.kjblsId))
{
// 同时传入健康师ID和科技部老师ID,需要同时关联两个业绩表(不过滤有效性)
baseQuery = _db.Queryable(
(jksyj, kjbsyj, hytk) => jksyj.Gltkbh == hytk.Id && kjbsyj.Gltkbh == hytk.Id)
.Where((jksyj, kjbsyj, hytk) => jksyj.Jkszh == input.jksId)
.Where((jksyj, kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId)
.Select((jksyj, kjbsyj, hytk) => hytk)
.Distinct()
.MergeTable();
}
else if (!string.IsNullOrEmpty(input.jksId))
{
// 只传入健康师ID,关联健康师业绩表(不过滤有效性)
baseQuery = _db.Queryable(
(jksyj, hytk) => jksyj.Gltkbh == hytk.Id)
.Where((jksyj, hytk) => jksyj.Jkszh == input.jksId)
.Select((jksyj, hytk) => hytk)
.Distinct()
.MergeTable();
}
else if (!string.IsNullOrEmpty(input.kjblsId))
{
// 只传入科技部老师ID,关联科技部老师业绩表(不过滤有效性)
baseQuery = _db.Queryable(
(kjbsyj, hytk) => kjbsyj.Gltkbh == hytk.Id)
.Where((kjbsyj, hytk) => kjbsyj.Kjblszh == input.kjblsId)
.Select((kjbsyj, hytk) => hytk)
.Distinct()
.MergeTable();
}
else
{
// 没有传入健康师ID或科技部老师ID,使用原来的查询逻辑
baseQuery = _db.Queryable();
}
var data = await baseQuery
.WhereIF(!string.IsNullOrEmpty(input.id), p => p.Id.Contains(input.id))
.WhereIF(!string.IsNullOrEmpty(input.md), p => p.Md.Equals(input.md))
.WhereIF(!string.IsNullOrEmpty(input.mdbh), p => p.Mdbh.Contains(input.mdbh))
.WhereIF(!string.IsNullOrEmpty(input.mdmc), p => p.Mdmc.Contains(input.mdmc))
.WhereIF(!string.IsNullOrEmpty(input.hy), p => p.Hy.Equals(input.hy))
.WhereIF(!string.IsNullOrEmpty(input.hymc), p => p.Hymc.Contains(input.hymc))
.WhereIF(!string.IsNullOrEmpty(input.hyzh), p => p.Hyzh.Contains(input.hyzh))
.WhereIF(!string.IsNullOrEmpty(input.gklx), p => p.Gklx.Contains(input.gklx))
.WhereIF(input.tkje.HasValue, p => p.Tkje == input.tkje)
.WhereIF(input.sgfy.HasValue, p => p.Sgfy == input.sgfy)
.WhereIF(!string.IsNullOrEmpty(input.bz), p => p.Bz.Contains(input.bz))
.WhereIF(!string.IsNullOrEmpty(input.tkzt), p => p.Tkzt.Contains(input.tkzt))
.WhereIF(!string.IsNullOrEmpty(input.tkyy), p => p.Tkyy.Contains(input.tkyy))
.WhereIF(!string.IsNullOrEmpty(input.fileUrl), p => p.FileUrl.Contains(input.fileUrl))
.WhereIF(startTksj.HasValue, p => p.Tksj >= new DateTime(startTksj.Value.Year, startTksj.Value.Month, startTksj.Value.Day, 0, 0, 0))
.WhereIF(endTksj.HasValue, p => p.Tksj <= new DateTime(endTksj.Value.Year, endTksj.Value.Month, endTksj.Value.Day, 23, 59, 59))
.WhereIF(!string.IsNullOrEmpty(input.czry), p => p.Czry.Equals(input.czry))
.WhereIF(input.isEffective != 0, p => p.IsEffective == input.isEffective)
.WhereIF(input.isEffective == 0, p => p.IsEffective == StatusEnum.有效.GetHashCode()) // 如果未指定,默认只返回有效的
.Select(it => new LqHytkHytkListOutput
{
id = it.Id,
md = it.Md,
mdbh = it.Mdbh,
mdmc = it.Mdmc,
hy = it.Hy,
hymc = it.Hymc,
hyzh = it.Hyzh,
gklx = it.Gklx,
tkje = it.Tkje,
sgfy = it.Sgfy,
bz = it.Bz,
tkzt = it.Tkzt,
tkyy = it.Tkyy,
tksj = it.Tksj,
czry = it.Czry,
fileUrl = it.FileUrl,
isEffective = it.IsEffective,
cancelRemark = it.CancelRemark,
actualRefundAmount = it.ActualRefundAmount
})
.MergeTable()
.OrderBy(sidx + " " + input.sort)
.ToPagedListAsync(input.currentPage, input.pageSize);
// 获取当前页的退卡记录ID列表
var refundIds = data.list.Select(x => x.id).ToList();
// 批量查询会员电话(性能优化:一次性查询所有会员的手机号)
var memberPhoneDict = new Dictionary();
var memberIds = data.list.Where(x => !string.IsNullOrEmpty(x.hy)).Select(x => x.hy).Distinct().ToList();
if (memberIds.Any())
{
var members = await _db.Queryable()
.Where(x => memberIds.Contains(x.Id))
.Select(x => new { x.Id, x.Sjh })
.ToListAsync();
memberPhoneDict = members.ToDictionary(x => x.Id, x => x.Sjh ?? string.Empty);
}
// 填充会员电话
foreach (var item in data.list)
{
if (!string.IsNullOrEmpty(item.hy) && memberPhoneDict.ContainsKey(item.hy))
{
item.hyPhone = memberPhoneDict[item.hy];
}
}
// 批量查询品项明细(不过滤有效性,返回所有记录)
var itemDetails = new List();
if (refundIds.Any())
{
itemDetails = await _db.Queryable()
.Where(x => refundIds.Contains(x.RefundInfoId))
.Select(x => new LqHytkMxInfoOutput
{
id = x.Id,
refundInfoId = x.RefundInfoId,
billingItemId = x.BillingItemId,
px = x.Px,
pxmc = x.Pxmc,
pxjg = x.Pxjg,
tkje = x.Tkje,
projectNumber = x.ProjectNumber,
isEffective = x.IsEffective,
sourceType = x.SourceType,
totalPrice = x.TotalPrice
})
.ToListAsync();
}
// 批量查询健康师业绩(性能优化:一次性查询所有退卡的健康师业绩,不过滤有效性)
var jksyjList = new List();
if (refundIds.Any())
{
jksyjList = await _db.Queryable()
.Where(x => refundIds.Contains(x.Gltkbh))
.Select(x => new LqHytkJksyjInfoOutput
{
id = x.Id,
gltkbh = x.Gltkbh,
jks = x.Jks,
jksxm = x.Jksxm,
jkszh = x.Jkszh,
jksyj = x.Jksyj,
tksj = x.Tksj,
F_jsjid = x.F_jsjid,
F_tkpxid = x.F_tkpxid,
F_LaborCost = x.F_LaborCost,
F_tkpxNumber = x.F_tkpxNumber
})
.ToListAsync();
}
// 批量查询科技部老师业绩(性能优化:一次性查询所有退卡的科技部老师业绩,不过滤有效性)
var kjbsyjList = new List();
if (refundIds.Any())
{
kjbsyjList = await _db.Queryable()
.Where(x => refundIds.Contains(x.Gltkbh))
.Select(x => new LqHytkKjbsyjInfoOutput
{
id = x.Id,
gltkbh = x.Gltkbh,
kjbls = x.Kjbls,
kjblsxm = x.Kjblsxm,
kjblszh = x.Kjblszh,
kjblsyj = x.Kjblsyj,
tksj = x.Tksj,
F_tkpxid = x.F_tkpxid,
F_LaborCost = x.F_LaborCost,
F_tkpxNumber = x.F_tkpxNumber
})
.ToListAsync();
}
// 按退卡ID分组品项明细
var itemDetailsGrouped = itemDetails.GroupBy(x => x.refundInfoId)
.ToDictionary(g => g.Key, g => g.ToList());
// 按退卡ID分组健康师业绩
var jksyjGrouped = jksyjList.GroupBy(x => x.gltkbh)
.ToDictionary(g => g.Key, g => g.ToList());
// 按退卡ID分组科技部老师业绩
var kjbsyjGrouped = kjbsyjList.GroupBy(x => x.gltkbh)
.ToDictionary(g => g.Key, g => g.ToList());
// 为每个退卡记录分配品项明细、健康师业绩和科技部老师业绩
foreach (var item in data.list)
{
item.lqHytkMxList = itemDetailsGrouped.ContainsKey(item.id)
? itemDetailsGrouped[item.id]
: new List();
item.lqHytkJksyjList = jksyjGrouped.ContainsKey(item.id)
? jksyjGrouped[item.id]
: new List();
item.lqHytkKjbsyjList = kjbsyjGrouped.ContainsKey(item.id)
? kjbsyjGrouped[item.id]
: new List();
}
return PageResult.SqlSugarPageResult(data);
}
#endregion
#region 创建退卡信息及其关联的品项明细、健康师业绩、科技部老师业绩信息
///
/// 创建退卡信息及其关联的品项明细、健康师业绩、科技部老师业绩信息
///
///
/// 参数说明:
/// - md: 门店ID
/// - hy: 会员ID
/// - lqHytkMxList: 退卡品项明细列表
///
/// 退卡创建参数
/// 无返回值
/// 创建成功
/// 参数错误或数据验证失败
/// 服务器内部错误
[HttpPost("")]
public async Task Create([FromBody] LqHytkHytkCrInput input)
{
var userInfo = await _userManager.GetUserInfo();
var entity = input.Adapt();
entity.Id = YitIdHelper.NextId().ToString();
entity.F_CreateTime = DateTime.Now;
entity.F_CreateUser = userInfo.userId;
entity.IsEffective = StatusEnum.有效.GetHashCode();
entity.Czry = userInfo.userId;
try
{
// 开启事务
_db.BeginTran();
// 新增退卡主表记录
var newEntity = await _db.Insertable(entity).IgnoreColumns(ignoreNullColumn: true).ExecuteReturnEntityAsync();
// 收集所有需要插入的实体,然后批量插入
var allMxEntities = new List();
var allJksyjEntities = new List();
var allKjbsyjEntities = new List();
// 处理品项明细列表
if (input.lqHytkMxList != null && input.lqHytkMxList.Any())
{
foreach (var item in input.lqHytkMxList)
{
// 创建品项明细实体
var lqHytkMxEntity = new LqHytkMxEntity
{
Id = YitIdHelper.NextId().ToString(),
RefundInfoId = newEntity.Id,
BillingItemId = item.billingItemId,
MemberId = newEntity.Hy,
CreateTime = DateTime.Now,
CreateUser = userInfo.userId,
Px = item.px,
Pxmc = item.pxmc,
Pxjg = item.pxjg,
Tkje = item.tkje,
Tksj = input.tksj,
ProjectNumber = item.F_ProjectNumber ?? 1,
SourceType = item.F_SourceType,
TotalPrice = item.F_TotalPrice ?? (item.pxjg * (item.F_ProjectNumber ?? 1)),
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allMxEntities.Add(lqHytkMxEntity);
// 收集该品项关联的健康师业绩
if (item.lqHytkJksyjList != null && item.lqHytkJksyjList.Any())
{
foreach (var ijks_tem in item.lqHytkJksyjList)
{
allJksyjEntities.Add(new LqHytkJksyjEntity
{
Id = YitIdHelper.NextId().ToString(),
Gltkbh = newEntity.Id,
Jks = ijks_tem.jks,
Jksxm = ijks_tem.jksxm,
Jkszh = ijks_tem.jkszh,
Jksyj = ijks_tem.jksyj,
Tksj = input.tksj,
F_jsjid = ijks_tem.F_jsjid,
F_tkpxid = ijks_tem.F_tkpxid,
F_LaborCost = ijks_tem.F_LaborCost,
F_tkpxNumber = ijks_tem.F_tkpxNumber,
F_CreateTime = DateTime.Now,
F_CreateUser = userInfo.userId,
CardReturn = lqHytkMxEntity.Id,
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = lqHytkMxEntity.ItemCategory,
ItemId = lqHytkMxEntity.Px,
StoreId = newEntity.Md,
ItemName = lqHytkMxEntity.Pxmc,
PerformanceType = lqHytkMxEntity.PerformanceType,
BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
}
// 收集该品项关联的科技部老师业绩
if (item.lqHytkKjbsyjList != null && item.lqHytkKjbsyjList.Any())
{
foreach (var ikjbs_tem in item.lqHytkKjbsyjList)
{
allKjbsyjEntities.Add(
new LqHytkKjbsyjEntity
{
Id = YitIdHelper.NextId().ToString(),
Gltkbh = newEntity.Id,
Kjbls = ikjbs_tem.kjbls,
Kjblsxm = ikjbs_tem.kjblsxm,
Kjblszh = ikjbs_tem.kjblszh,
Kjblsyj = ikjbs_tem.kjblsyj,
Tksj = input.tksj,
F_tkpxid = ikjbs_tem.F_tkpxid,
F_LaborCost = ikjbs_tem.F_LaborCost,
F_tkpxNumber = ikjbs_tem.F_tkpxNumber,
F_CreateTime = DateTime.Now,
F_CreateUser = userInfo.userId,
CardReturn = lqHytkMxEntity.Id,
IsEffective = StatusEnum.有效.GetHashCode(),
ItemCategory = lqHytkMxEntity.ItemCategory,
ItemId = lqHytkMxEntity.Px,
StoreId = newEntity.Md,
ItemName = lqHytkMxEntity.Pxmc,
PerformanceType = lqHytkMxEntity.PerformanceType,
BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
}
}
}
// 批量插入品项明细
if (allMxEntities.Any())
{
await _db.Insertable(allMxEntities).ExecuteCommandAsync();
}
// 批量插入健康师业绩
if (allJksyjEntities.Any())
{
await _db.Insertable(allJksyjEntities).ExecuteCommandAsync();
}
// 批量插入科技部老师业绩
if (allKjbsyjEntities.Any())
{
await _db.Insertable(allKjbsyjEntities).ExecuteCommandAsync();
}
// 关闭事务
_db.CommitTran();
}
catch (Exception ex)
{
_db.RollbackTran();
throw NCCException.Oh(ErrorCode.COM1005, ex.Message);
}
}
#endregion
#region 更新退卡信息及其关联的品项明细、健康师业绩、科技部老师业绩信息
///
/// 更新退卡信息及其关联的品项明细、健康师业绩、科技部老师业绩信息
///
///
/// 更新退卡记录及其关联的品项明细、健康师业绩、科技部老师业绩信息
/// 先删除原有的关联数据,再插入新的数据
///
/// 退卡ID
/// 退卡更新参数
/// 无返回值
/// 更新成功
/// 参数错误或数据验证失败
/// 服务器内部错误
[HttpPut("{id}")]
public async Task Update(string id, [FromBody] LqHytkHytkUpInput input)
{
var userInfo = await _userManager.GetUserInfo();
var entity = input.Adapt();
entity.Id = id;
entity.F_ModifyTime = DateTime.Now;
entity.F_ModifyUser = userInfo.userId;
try
{
// 开启事务
_db.BeginTran();
// 更新退卡主表记录
await _db.Updateable(entity).IgnoreColumns(true).ExecuteCommandAsync();
// 删除原有的关联数据
await _db.Deleteable().Where(x => x.RefundInfoId == id).ExecuteCommandAsync();
await _db.Deleteable().Where(x => x.Gltkbh == id).ExecuteCommandAsync();
await _db.Deleteable().Where(x => x.Gltkbh == id).ExecuteCommandAsync();
// 收集所有需要插入的实体,然后批量插入
var allMxEntities = new List();
var allJksyjEntities = new List();
var allKjbsyjEntities = new List();
// 处理品项明细列表
if (input.lqHytkMxList != null && input.lqHytkMxList.Any())
{
foreach (var item in input.lqHytkMxList)
{
// 创建品项明细实体
var lqHytkMxEntity = new LqHytkMxEntity
{
Id = YitIdHelper.NextId().ToString(),
RefundInfoId = id,
BillingItemId = item.billingItemId,
MemberId = entity.Hy,
CreateTime = DateTime.Now,
CreateUser = userInfo.userId,
Tksj = input.tksj,
Px = item.px,
Pxmc = item.pxmc,
Pxjg = item.pxjg,
Tkje = item.tkje,
ProjectNumber = item.F_ProjectNumber ?? 1,
SourceType = item.F_SourceType,
TotalPrice = item.F_TotalPrice ?? (item.pxjg * (item.F_ProjectNumber ?? 1)),
ItemCategory = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Qt2).FirstAsync(),
PerformanceType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.Fl3).FirstAsync() ?? "",
BeautyType = await _db.Queryable().Where(x => x.Id == item.px).Select(x => x.BeautyType).FirstAsync(),
};
allMxEntities.Add(lqHytkMxEntity);
// 收集该品项关联的健康师业绩
if (item.lqHytkJksyjList != null && item.lqHytkJksyjList.Any())
{
foreach (var ijks_tem in item.lqHytkJksyjList)
{
allJksyjEntities.Add(
new LqHytkJksyjEntity
{
Id = YitIdHelper.NextId().ToString(),
Gltkbh = id,
Jks = ijks_tem.jks,
Jksxm = ijks_tem.jksxm,
Jkszh = ijks_tem.jkszh,
Jksyj = ijks_tem.jksyj,
Tksj = input.tksj,
F_jsjid = ijks_tem.F_jsjid,
F_tkpxid = ijks_tem.F_tkpxid,
F_LaborCost = ijks_tem.F_LaborCost,
F_tkpxNumber = ijks_tem.F_tkpxNumber,
F_CreateTime = DateTime.Now,
F_CreateUser = userInfo.userId,
ItemCategory = lqHytkMxEntity.ItemCategory,
ItemId = lqHytkMxEntity.Px,
StoreId = entity.Md,
ItemName = lqHytkMxEntity.Pxmc,
PerformanceType = lqHytkMxEntity.PerformanceType,
BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
}
// 收集该品项关联的科技部老师业绩
if (item.lqHytkKjbsyjList != null && item.lqHytkKjbsyjList.Any())
{
foreach (var ikjbs_tem in item.lqHytkKjbsyjList)
{
allKjbsyjEntities.Add(
new LqHytkKjbsyjEntity
{
Id = YitIdHelper.NextId().ToString(),
Gltkbh = id,
Kjbls = ikjbs_tem.kjbls,
Kjblsxm = ikjbs_tem.kjblsxm,
Kjblszh = ikjbs_tem.kjblszh,
Kjblsyj = ikjbs_tem.kjblsyj,
Tksj = input.tksj,
F_tkpxid = ikjbs_tem.F_tkpxid,
F_LaborCost = ikjbs_tem.F_LaborCost,
F_tkpxNumber = ikjbs_tem.F_tkpxNumber,
F_CreateTime = DateTime.Now,
F_CreateUser = userInfo.userId,
ItemCategory = lqHytkMxEntity.ItemCategory,
ItemId = lqHytkMxEntity.Px,
StoreId = entity.Md,
ItemName = lqHytkMxEntity.Pxmc,
PerformanceType = lqHytkMxEntity.PerformanceType,
BeautyType = lqHytkMxEntity.BeautyType,
}
);
}
}
}
}
// 批量插入品项明细
if (allMxEntities.Any())
{
await _db.Insertable(allMxEntities).ExecuteCommandAsync();
}
// 批量插入健康师业绩
if (allJksyjEntities.Any())
{
await _db.Insertable(allJksyjEntities).ExecuteCommandAsync();
}
// 批量插入科技部老师业绩
if (allKjbsyjEntities.Any())
{
await _db.Insertable(allKjbsyjEntities).ExecuteCommandAsync();
}
// 关闭事务
_db.CommitTran();
}
catch (Exception ex)
{
_db.RollbackTran();
throw NCCException.Oh(ErrorCode.COM1005, ex.Message);
}
}
#endregion
#region 作废退卡信息
///
/// 作废退卡信息
///
/// 主键
///
[HttpPut("VoidRefundCardInfo/{id}")]
public async Task VoidRefundCardInfo(string id, [FromQuery] string remarks = null)
{
try
{
var entity = await _db.Queryable().FirstAsync(p => p.Id == id && p.IsEffective == StatusEnum.有效.GetHashCode());
if (entity == null)
{
throw NCCException.Oh("退卡信息不存在或已被作废");
}
// 开启事务
_db.BeginTran();
// 更新主表
entity.IsEffective = StatusEnum.无效.GetHashCode();
entity.F_ModifyTime = DateTime.Now;
entity.CancelRemark = remarks;
await _db.Updateable(entity).ExecuteCommandAsync();
// 更新明细表
await _db.Updateable().SetColumns(it => new LqHytkMxEntity { IsEffective = StatusEnum.无效.GetHashCode() }).Where(w => w.RefundInfoId == id).ExecuteCommandAsync();
// 更新健康师业绩表
await _db.Updateable().SetColumns(it => new LqHytkJksyjEntity { IsEffective = StatusEnum.无效.GetHashCode() }).Where(w => w.Gltkbh == id).ExecuteCommandAsync();
// 更新科技部业绩表
await _db.Updateable().SetColumns(it => new LqHytkKjbsyjEntity { IsEffective = StatusEnum.无效.GetHashCode() }).Where(w => w.Gltkbh == id).ExecuteCommandAsync();
// 提交事务
_db.CommitTran();
return entity;
}
catch (Exception ex)
{
_db.RollbackTran();
throw NCCException.Oh($"删除退卡信息失败: {ex.Message}");
}
}
#endregion
#region 物理删除退卡信息
///
/// 物理删除退卡信息
///
///
/// 彻底删除退卡记录及其所有关联数据,包括:
/// - 退卡主表记录
/// - 退卡品项明细记录
/// - 退卡健康师业绩记录
/// - 退卡科技部老师业绩记录
///
/// 注意:此操作不可逆,请谨慎使用
///
/// 退卡记录主键ID
/// 删除结果
/// 删除成功
/// 退卡记录不存在
/// 服务器内部错误
[HttpDelete("physical/{id}")]
public async Task PhysicalDelete(string id)
{
try
{
// 检查退卡记录是否存在
var entity = await _db.Queryable().FirstAsync(p => p.Id == id);
if (entity == null)
{
throw NCCException.Oh("退卡记录不存在");
}
// 开启事务
_db.BeginTran();
// 1. 删除退卡品项明细记录
await _db.Deleteable().Where(x => x.RefundInfoId == id).ExecuteCommandAsync();
// 2. 删除退卡健康师业绩记录
await _db.Deleteable().Where(x => x.Gltkbh == id).ExecuteCommandAsync();
// 3. 删除退卡科技部老师业绩记录
await _db.Deleteable().Where(x => x.Gltkbh == id).ExecuteCommandAsync();
// 4. 删除退卡主表记录
await _db.Deleteable().Where(x => x.Id == id).ExecuteCommandAsync();
// 提交事务
_db.CommitTran();
return new
{
success = true,
message = "退卡记录已彻底删除",
deletedId = id,
deletedTime = DateTime.Now
};
}
catch (Exception ex)
{
// 回滚事务
_db.RollbackTran();
throw NCCException.Oh($"物理删除退卡记录失败: {ex.Message}");
}
}
#endregion
#region 获取退卡信息详情
///
/// 获取退卡信息详情
///
///
/// 获取退卡记录及其关联的品项明细、健康师业绩、科技部老师业绩信息
/// 按照退卡的完整格式返回数据,不包含汇总信息
///
/// 返回数据结构:
/// - 主表信息:退卡基础信息、门店信息、会员信息、退卡金额等
/// - 品项明细列表:每个品项包含完整的项目信息(项目次数、是否有效、来源类型等)
/// - 健康师业绩列表:按品项关联的健康师业绩信息
/// - 科技部老师业绩列表:按品项关联的科技部老师业绩信息
///
/// 退卡记录主键ID
/// 退卡记录完整信息
/// 查询成功
/// 退卡记录不存在
/// 服务器内部错误
[HttpGet("{id}")]
public async Task GetInfo(string id)
{
try
{
// 1. 查询主表信息
var entity = await _db.Queryable().Where(p => p.Id == id).FirstAsync();
if (entity == null)
{
throw NCCException.Oh("退卡记录不存在");
}
var output = entity.Adapt();
// 2. 查询品项明细列表
var lqHytkMxList = await _db.Queryable().Where(w => w.RefundInfoId == entity.Id).ToListAsync();
// 3. 查询健康师业绩列表
var lqHytkJksyjList = await _db.Queryable().Where(w => w.Gltkbh == entity.Id).ToListAsync();
// 4. 查询科技部老师业绩列表
var lqHytkKjbsyjList = await _db.Queryable().Where(w => w.Gltkbh == entity.Id).ToListAsync();
// 5. 构建品项明细输出,每个品项关联对应的业绩信息
var mxOutputList = new List();
foreach (var mx in lqHytkMxList)
{
var mxOutput = new LqHytkMxInfoOutput
{
id = mx.Id,
refundInfoId = mx.RefundInfoId,
billingItemId = mx.BillingItemId,
px = mx.Px,
pxmc = mx.Pxmc,
pxjg = mx.Pxjg,
tkje = mx.Tkje,
projectNumber = mx.ProjectNumber,
sourceType = mx.SourceType,
totalPrice = mx.TotalPrice,
isEffective = mx.IsEffective,
};
// 关联该品项的健康师业绩
var jksyjForMx = lqHytkJksyjList.Where(j => j.CardReturn == mx.Id).ToList();
mxOutput.lqHytkJksyjList = jksyjForMx.Adapt>();
// 关联该品项的科技部老师业绩
var kjbsyjForMx = lqHytkKjbsyjList.Where(k => k.CardReturn == mx.Id).ToList();
mxOutput.lqHytkKjbsyjList = kjbsyjForMx.Adapt>();
mxOutputList.Add(mxOutput);
}
// 6. 设置输出结果
output.lqHytkMxList = mxOutputList;
// 7. 设置全局业绩列表(用于兼容性,但主要使用品项关联的业绩)
output.lqHytkJksyjList = lqHytkJksyjList.Adapt>();
output.lqHytkKjbsyjList = lqHytkKjbsyjList.Adapt>();
return output;
}
catch (Exception ex)
{
throw NCCException.Oh($"获取退卡记录详情失败: {ex.Message}");
}
}
#endregion
#region 退卡明细查询
///
/// 获取退卡明细列表
///
///
/// 获取退卡明细列表,支持多门店、会员、时间范围、品项、业绩类型、科美类型、来源类型、品项分类等筛选
///
/// 示例请求:
/// ```json
/// GET /api/Extend/LqHytkHytk/refund-detail-list?storeIds=门店ID1,门店ID2&memberId=会员ID&startTime=2025-01-01&endTime=2025-12-31¤tPage=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. 先查询退卡明细表(不使用时间筛选,因为明细表的tksj可能为null,时间筛选在退卡信息表进行)
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);
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, x => x.Tksj.HasValue && x.Tksj >= input.startTime.Value)
.WhereIF(input.endTime.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 mxIds = mxList.Select(x => x.Id).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
// 使用字典存储每个退款明细对应的多个健康师信息
var healthCoachDict = new Dictionary>();
var actualRefundAmountDict = new Dictionary();
if (mxIds.Any())
{
// 通过退卡品相表ID(F_CardReturn)查询退款健康师业绩
var jksyjList = await _db.Queryable()
.Where(x => mxIds.Contains(x.CardReturn) && x.IsEffective == StatusEnum.有效.GetHashCode())
.Select(x => new { x.CardReturn, x.Jkszh, x.Jksxm, x.Jksyj })
.ToListAsync();
// 按退款明细ID分组,建立映射
foreach (var jksyj in jksyjList)
{
if (string.IsNullOrEmpty(jksyj.CardReturn))
continue;
var jksyjValue = jksyj.Jksyj ?? 0m;
if (!healthCoachDict.ContainsKey(jksyj.CardReturn))
{
healthCoachDict[jksyj.CardReturn] = new List<(string Id, string Name, decimal Performance)>();
actualRefundAmountDict[jksyj.CardReturn] = 0m;
}
healthCoachDict[jksyj.CardReturn].Add((jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue));
actualRefundAmountDict[jksyj.CardReturn] += jksyjValue;
}
}
// 6. 组装数据
var resultList = new List();
foreach (var mx in mxList)
{
var refundInfo = refundInfoDict.ContainsKey(mx.RefundInfoId) ? refundInfoDict[mx.RefundInfoId] : null;
// 如果退卡信息不在筛选范围内(时间、门店、会员等),跳过这条明细
if (refundInfo == null)
{
continue;
}
// 应用筛选条件
if (input.storeIds != null && input.storeIds.Any())
{
if (!input.storeIds.Contains(refundInfo.Md))
continue;
}
if (!string.IsNullOrEmpty(input.memberId))
{
if (mx.MemberId != input.memberId && refundInfo.Hy != input.memberId)
continue;
}
var memberId = mx.MemberId ?? (refundInfo?.Hy);
var refundTime = mx.Tksj ?? refundInfo?.Tksj;
// 获取健康师信息(支持多个健康师)
var healthCoachList = healthCoachDict.ContainsKey(mx.Id)
? healthCoachDict[mx.Id]
: new List<(string Id, string Name, decimal Performance)>();
// 合并多个健康师姓名和业绩(格式:姓名(业绩),用顿号分隔)
var healthCoachNames = "";
if (healthCoachList.Any())
{
var healthCoachItems = healthCoachList
.Where(h => !string.IsNullOrEmpty(h.Name))
.Select(h => $"{h.Name}({h.Performance:F2})")
.ToList();
healthCoachNames = string.Join("、", healthCoachItems);
}
// 获取第一个健康师信息(兼容旧版本)
var firstHealthCoach = healthCoachList.FirstOrDefault();
// 获取实际退款金额(所有健康师业绩之和)
var actualRefundAmount = actualRefundAmountDict.ContainsKey(mx.Id)
? actualRefundAmountDict[mx.Id]
: 0m;
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,
healthCoachId = firstHealthCoach.Id,
healthCoachName = healthCoachNames,
healthCoachPerformance = firstHealthCoach.Performance,
actualRefundAmount = actualRefundAmount
});
}
// 7. 排序
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();
}
// 8. 分页
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. 先查询退卡明细表(不使用时间筛选,因为明细表的tksj可能为null,时间筛选在退卡信息表进行)
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);
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, x => x.Tksj.HasValue && x.Tksj >= input.startTime.Value)
.WhereIF(input.endTime.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 mxIds = mxList.Select(x => x.Id).Where(x => !string.IsNullOrEmpty(x)).Distinct().ToList();
// 使用字典存储每个退款明细对应的多个健康师信息
var healthCoachDict = new Dictionary>();
var actualRefundAmountDict = new Dictionary();
if (mxIds.Any())
{
// 通过退卡品相表ID(F_CardReturn)查询退款健康师业绩
var jksyjList = await _db.Queryable()
.Where(x => mxIds.Contains(x.CardReturn) && x.IsEffective == StatusEnum.有效.GetHashCode())
.Select(x => new { x.CardReturn, x.Jkszh, x.Jksxm, x.Jksyj })
.ToListAsync();
// 按退款明细ID分组,建立映射
foreach (var jksyj in jksyjList)
{
if (string.IsNullOrEmpty(jksyj.CardReturn))
continue;
var jksyjValue = jksyj.Jksyj ?? 0m;
if (!healthCoachDict.ContainsKey(jksyj.CardReturn))
{
healthCoachDict[jksyj.CardReturn] = new List<(string Id, string Name, decimal Performance)>();
actualRefundAmountDict[jksyj.CardReturn] = 0m;
}
healthCoachDict[jksyj.CardReturn].Add((jksyj.Jkszh ?? "", jksyj.Jksxm ?? "", jksyjValue));
actualRefundAmountDict[jksyj.CardReturn] += jksyjValue;
}
}
// 6. 组装数据
var resultList = new List();
foreach (var mx in mxList)
{
var refundInfo = refundInfoDict.ContainsKey(mx.RefundInfoId) ? refundInfoDict[mx.RefundInfoId] : null;
// 如果退卡信息不在筛选范围内(时间、门店、会员等),跳过这条明细
if (refundInfo == null)
{
continue;
}
// 应用筛选条件
if (input.storeIds != null && input.storeIds.Any())
{
if (!input.storeIds.Contains(refundInfo.Md))
continue;
}
if (!string.IsNullOrEmpty(input.memberId))
{
if (mx.MemberId != input.memberId && refundInfo.Hy != input.memberId)
continue;
}
var memberId = mx.MemberId ?? (refundInfo?.Hy);
var refundTime = mx.Tksj ?? refundInfo?.Tksj;
// 获取健康师信息(支持多个健康师)
var healthCoachList = healthCoachDict.ContainsKey(mx.Id)
? healthCoachDict[mx.Id]
: new List<(string Id, string Name, decimal Performance)>();
// 合并多个健康师姓名和业绩(格式:姓名(业绩),用顿号分隔)
var healthCoachNames = "";
if (healthCoachList.Any())
{
var healthCoachItems = healthCoachList
.Where(h => !string.IsNullOrEmpty(h.Name))
.Select(h => $"{h.Name}({h.Performance:F2})")
.ToList();
healthCoachNames = string.Join("、", healthCoachItems);
}
// 获取第一个健康师信息(兼容旧版本)
var firstHealthCoach = healthCoachList.FirstOrDefault();
// 获取实际退款金额(所有健康师业绩之和)
var actualRefundAmount = actualRefundAmountDict.ContainsKey(mx.Id)
? actualRefundAmountDict[mx.Id]
: 0m;
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,
healthCoachId = firstHealthCoach.Id,
healthCoachName = healthCoachNames,
healthCoachPerformance = firstHealthCoach.Performance,
actualRefundAmount = actualRefundAmount
});
}
// 7. 排序
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\"},{\"value\":\"健康师\",\"field\":\"healthCoachName\"},{\"value\":\"健康师业绩\",\"field\":\"healthCoachPerformance\"},]".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
}
}