using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using NCC.Common.Core.Manager;
using NCC.Common.Filter;
using NCC.Dependency;
using NCC.DynamicApiController;
using NCC.Extend.Entitys.Dto.LqPackageInfo;
using NCC.Extend.Entitys.Dto.LqXmzl;
using NCC.Extend.Entitys.Enum;
using NCC.Extend.Entitys.lq_package_info;
using NCC.Extend.Entitys.lq_package_item_detail;
using NCC.Extend.Entitys.lq_xmzl;
using NCC.Extend.Interfaces.LqPackageInfo;
using NCC.FriendlyException;
using SqlSugar;
using Yitter.IdGenerator;
namespace NCC.Extend.LqPackageInfo
{
///
/// 营销活动服务
///
[ApiDescriptionSettings(Tag = "绿纤营销活动服务", Name = "LqPackageInfo", Order = 200)]
[Route("api/Extend/[controller]")]
public class LqPackageInfoService : ILqPackageInfoService, IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository _packageInfoRepository;
private readonly SqlSugarScope _db;
private readonly IUserManager _userManager;
///
/// 构造函数
///
/// 营销活动仓储
/// 用户管理器
public LqPackageInfoService(ISqlSugarRepository packageInfoRepository, IUserManager userManager)
{
_packageInfoRepository = packageInfoRepository;
_db = packageInfoRepository.Context;
_userManager = userManager;
}
#region 添加营销活动
///
/// 添加营销活动
///
/// 营销活动创建输入
/// 营销活动ID
///
/// 创建新的营销活动,包含活动基本信息和品项明细
///
/// 示例请求:
/// ```json
/// {
/// "activityName": "春季护肤优惠活动",
/// "activityDesc": "春季护肤特惠活动",
/// "startTime": "2025-03-01T00:00:00",
/// "endTime": "2025-03-31T23:59:59",
/// "minItemQuantity": 2,
/// "activityRules": "活动规则说明",
/// "activityImages": "[\"image1.jpg\"]",
/// "sortOrder": 1,
/// "activityItems": [
/// {
/// "itemId": "ITEM001",
/// "itemName": "面部清洁",
/// "itemCategory": "基础护理",
/// "itemRemark": "推荐品项"
/// }
/// ]
/// }
/// ```
///
/// 参数说明:
/// - activityName: 营销活动名称
/// - activityDesc: 营销活动描述
/// - startTime: 活动开始时间
/// - endTime: 活动结束时间
/// - minItemQuantity: 至少购买品项数量
/// - activityRules: 活动规则说明
/// - activityImages: 活动图片(JSON格式)
/// - sortOrder: 排序
/// - activityItems: 营销活动品项明细列表
///
/// 成功创建营销活动,返回营销活动ID
/// 请求参数错误
/// 服务器内部错误
[HttpPost("CreatePackageInfoAsync")]
public async Task CreatePackageInfoAsync(LqPackageInfoCrInput input)
{
try
{
// 验证活动时间
if (input.StartTime >= input.EndTime)
{
throw NCCException.Oh("活动开始时间必须小于结束时间");
}
// 验证品项明细
if (input.ActivityItems == null || !input.ActivityItems.Any())
{
throw NCCException.Oh("营销活动必须包含至少一个品项");
}
// 验证至少购买品项数量
if (input.ActivityItems.Count < input.MinItemQuantity)
{
throw NCCException.Oh($"品项数量不能少于至少购买品项数量({input.MinItemQuantity})");
}
// 开始事务
_db.BeginTran();
try
{
// 创建营销活动实体
var packageInfo = input.Adapt();
packageInfo.Id = YitIdHelper.NextId().ToString();
packageInfo.CreateTime = DateTime.Now;
packageInfo.UpdateTime = DateTime.Now;
packageInfo.CreateUser = _userManager.UserId;
packageInfo.UpdateUser = _userManager.UserId;
packageInfo.IsEffective = StatusEnum.有效.GetHashCode();
// 保存营销活动
await _db.Insertable(packageInfo).ExecuteCommandAsync();
// 创建营销活动品项明细
var packageItemDetails = input.ActivityItems.Select(item =>
{
var packageItemDetail = item.Adapt();
packageItemDetail.Id = YitIdHelper.NextId().ToString();
packageItemDetail.ActivityId = packageInfo.Id;
packageItemDetail.CreateTime = DateTime.Now;
packageItemDetail.UpdateTime = DateTime.Now;
packageItemDetail.IsEffective = StatusEnum.有效.GetHashCode();
return packageItemDetail;
}).ToList();
// 批量保存营销活动品项明细
if (packageItemDetails.Any())
{
await _db.Insertable(packageItemDetails).ExecuteCommandAsync();
}
// 提交事务
_db.CommitTran();
return packageInfo.Id;
}
catch
{
// 回滚事务
_db.RollbackTran();
throw;
}
}
catch (Exception ex)
{
throw NCCException.Oh($"添加营销活动失败: {ex.Message}");
}
}
#endregion
#region 获取营销活动列表
///
/// 获取营销活动列表
///
/// 营销活动列表查询输入
/// 营销活动列表
///
/// 获取营销活动列表,支持按活动名称、时间范围等条件筛选
///
/// 查询参数说明:
/// - activityName: 活动名称(模糊查询)
/// - activityDesc: 活动描述(模糊查询)
/// - startTimeStart: 活动开始时间范围开始
/// - startTimeEnd: 活动开始时间范围结束
/// - endTimeStart: 活动结束时间范围开始
/// - endTimeEnd: 活动结束时间范围结束
/// - minItemQuantity: 至少购买品项数量
/// - createTimeStart: 创建时间范围开始
/// - createTimeEnd: 创建时间范围结束
///
/// 成功获取营销活动列表
/// 请求参数错误
/// 服务器内部错误
[HttpGet("GetPackageInfoListAsync")]
public async Task GetPackageInfoListAsync([FromQuery] LqPackageInfoListQueryInput input)
{
var sidx = input.sidx == null ? "CreateTime" : input.sidx;
var data = await _db.Queryable()
.WhereIF(!string.IsNullOrEmpty(input.ActivityName), w => w.ActivityName.Contains(input.ActivityName))
.WhereIF(!string.IsNullOrEmpty(input.ActivityDesc), w => w.ActivityDesc.Contains(input.ActivityDesc))
.WhereIF(input.StartTimeStart.HasValue, w => w.StartTime >= input.StartTimeStart.Value)
.WhereIF(input.StartTimeEnd.HasValue, w => w.StartTime <= input.StartTimeEnd.Value)
.WhereIF(input.EndTimeStart.HasValue, w => w.EndTime >= input.EndTimeStart.Value)
.WhereIF(input.EndTimeEnd.HasValue, w => w.EndTime <= input.EndTimeEnd.Value)
.WhereIF(input.MinItemQuantity.HasValue, w => w.MinItemQuantity == input.MinItemQuantity.Value)
.WhereIF(input.CreateTimeStart.HasValue, w => w.CreateTime >= input.CreateTimeStart.Value)
.WhereIF(input.CreateTimeEnd.HasValue, w => w.CreateTime <= input.CreateTimeEnd.Value)
.WhereIF(input.IsEffective.HasValue, w => w.IsEffective == input.IsEffective.Value)
.Select(it => new LqPackageInfoListOutput
{
id = it.Id,
activityName = it.ActivityName,
activityDesc = it.ActivityDesc,
startTime = it.StartTime,
endTime = it.EndTime,
minItemQuantity = it.MinItemQuantity,
activityRules = it.ActivityRules,
sortOrder = it.SortOrder,
createTime = it.CreateTime,
isEffective = it.IsEffective,
createUser = it.CreateUser,
updateUser = it.UpdateUser,
updateTime = it.UpdateTime,
activityImages = it.ActivityImages,
}).MergeTable().OrderBy(sidx + " " + input.sort).ToPagedListAsync(input.currentPage, input.pageSize);
return PageResult.SqlSugarPageResult(data);
}
#endregion
#region 获取营销活动详情
///
/// 获取营销活动详情
///
/// 营销活动ID
/// 营销活动详情(包含品项信息)
///
/// 获取营销活动详情,包括活动基本信息和对应的品项明细列表
///
/// 返回数据说明:
/// - 活动基本信息:活动名称、描述、时间、规则等
/// - 品项明细列表:该活动包含的所有品项信息
///
/// 成功获取营销活动详情
/// 营销活动不存在
/// 服务器内部错误
[HttpGet("GetPackageInfoDetailAsync")]
public async Task GetPackageInfoDetailAsync(string id)
{
try
{
// 获取营销活动基本信息
var packageInfo = await _db.Queryable().Where(w => w.Id == id).FirstAsync();
if (packageInfo == null)
{
throw NCCException.Oh("营销活动不存在");
}
// 获取品项明细信息
var activityItems = await _db.Queryable()
.Where(w => w.ActivityId == id && w.IsEffective == StatusEnum.有效.GetHashCode())
.OrderBy(w => w.CreateTime)
.Select(it => new
{
id = it.Id,
activityId = it.ActivityId,
itemId = it.ItemId,
itemName = it.ItemName,
itemCategory = it.ItemCategory,
itemRemark = it.ItemRemark,
createTime = it.CreateTime
})
.ToListAsync();
// 构建返回结果
var result = new
{
// 活动基本信息
id = packageInfo.Id,
activityName = packageInfo.ActivityName,
activityDesc = packageInfo.ActivityDesc,
startTime = packageInfo.StartTime,
endTime = packageInfo.EndTime,
minItemQuantity = packageInfo.MinItemQuantity,
activityRules = packageInfo.ActivityRules,
activityImages = packageInfo.ActivityImages,
sortOrder = packageInfo.SortOrder,
createTime = packageInfo.CreateTime,
updateTime = packageInfo.UpdateTime,
createUser = packageInfo.CreateUser,
updateUser = packageInfo.UpdateUser,
isEffective = packageInfo.IsEffective,
// 品项明细列表
activityItems = activityItems
};
return result;
}
catch (Exception ex)
{
throw NCCException.Oh($"获取营销活动详情失败:{ex.Message}");
}
}
#endregion
#region 更新营销活动
///
/// 更新营销活动
///
/// 营销活动更新输入
/// 营销活动ID
///
/// 更新营销活动信息,包括活动基本信息和品项明细
///
/// 示例请求:
/// ```json
/// {
/// "id": "123456789",
/// "activityName": "春季护肤优惠活动",
/// "activityDesc": "春季护肤特惠活动",
/// "startTime": "2025-03-01T00:00:00",
/// "endTime": "2025-03-31T23:59:59",
/// "minItemQuantity": 2,
/// "activityRules": "活动规则说明",
/// "activityImages": "[\"image1.jpg\"]",
/// "sortOrder": 1,
/// "activityItems": [
/// {
/// "itemId": "ITEM001",
/// "itemName": "面部清洁",
/// "itemCategory": "基础护理",
/// "itemRemark": "推荐品项"
/// }
/// ]
/// }
/// ```
///
/// 参数说明:
/// - id: 营销活动ID(必填)
/// - activityName: 营销活动名称
/// - activityDesc: 营销活动描述
/// - startTime: 活动开始时间
/// - endTime: 活动结束时间
/// - minItemQuantity: 至少购买品项数量
/// - activityRules: 活动规则说明
/// - activityImages: 活动图片(JSON格式)
/// - sortOrder: 排序
/// - activityItems: 营销活动品项明细列表
///
/// 成功更新营销活动,返回营销活动ID
/// 请求参数错误
/// 营销活动不存在
/// 服务器内部错误
[HttpPut("UpdatePackageInfoAsync")]
public async Task UpdatePackageInfoAsync(LqPackageInfoUpInput input)
{
try
{
// 验证活动时间
if (input.StartTime >= input.EndTime)
{
throw NCCException.Oh("活动开始时间必须小于结束时间");
}
// 验证品项明细
if (input.ActivityItems == null || !input.ActivityItems.Any())
{
throw NCCException.Oh("营销活动必须包含至少一个品项");
}
// 验证至少购买品项数量
if (input.ActivityItems.Count < input.MinItemQuantity)
{
throw NCCException.Oh($"品项数量不能少于至少购买品项数量({input.MinItemQuantity})");
}
// 检查营销活动是否存在
var existingActivity = await _db.Queryable()
.Where(w => w.Id == input.Id)
.FirstAsync();
if (existingActivity == null)
{
throw NCCException.Oh("营销活动不存在");
}
// 开始事务
_db.BeginTran();
try
{
// 更新营销活动基本信息
var updateResult = await _db.Updateable()
.SetColumns(it => new LqPackageInfoEntity
{
ActivityName = input.ActivityName,
ActivityDesc = input.ActivityDesc,
StartTime = input.StartTime,
EndTime = input.EndTime,
MinItemQuantity = input.MinItemQuantity,
ActivityRules = input.ActivityRules,
ActivityImages = input.ActivityImages,
SortOrder = input.SortOrder,
UpdateTime = DateTime.Now,
UpdateUser = _userManager.UserId
})
.Where(w => w.Id == input.Id)
.ExecuteCommandAsync();
if (updateResult <= 0)
{
throw NCCException.Oh("更新营销活动失败");
}
// 删除原有的品项明细
await _db.Deleteable()
.Where(w => w.ActivityId == input.Id)
.ExecuteCommandAsync();
// 创建新的品项明细
var packageItemDetails = input.ActivityItems.Select(item =>
{
var packageItemDetail = item.Adapt();
packageItemDetail.Id = YitIdHelper.NextId().ToString();
packageItemDetail.ActivityId = input.Id;
packageItemDetail.CreateTime = DateTime.Now;
packageItemDetail.UpdateTime = DateTime.Now;
packageItemDetail.IsEffective = 1;
return packageItemDetail;
}).ToList();
// 批量保存新的品项明细
if (packageItemDetails.Any())
{
await _db.Insertable(packageItemDetails).ExecuteCommandAsync();
}
// 提交事务
_db.CommitTran();
return input.Id;
}
catch
{
// 回滚事务
_db.RollbackTran();
throw;
}
}
catch (Exception ex)
{
throw NCCException.Oh($"更新营销活动失败: {ex.Message}");
}
}
#endregion
#region 标记删除营销活动
///
/// 标记删除营销活动
///
/// 营销活动ID
/// 营销活动ID
[HttpDelete("MarkDeletePackageInfoAsync")]
public async Task MarkDeletePackageInfoAsync(string id)
{
var entity = await _db.Queryable().Where(w => w.Id == id).FirstAsync();
if (entity == null)
{
throw NCCException.Oh("营销活动不存在");
}
entity.IsEffective = StatusEnum.无效.GetHashCode();
await _db.Updateable(entity).ExecuteCommandAsync();
await _db.Updateable().SetColumns(it => new LqPackageItemDetailEntity { IsEffective = StatusEnum.无效.GetHashCode() }).Where(w => w.ActivityId == id).ExecuteCommandAsync();
return id;
}
#endregion
#region 根据营销活动ID获取品项详情
///
/// 根据营销活动ID获取品项详情
///
/// 营销活动ID
/// 品项详情列表
///
/// 通过营销活动ID获取对应的品项ID,然后查询品项表获取完整的品项信息
///
/// 查询流程:
/// 1. 根据营销活动ID查询营销活动品项明细表,获取品项ID列表
/// 2. 根据品项ID列表查询项目资料表,获取完整的品项信息
/// 3. 返回品项详情列表
///
/// 成功获取品项详情
/// 营销活动不存在或没有品项
/// 服务器内部错误
[HttpGet("GetPackageItemDetailByActivityIdAsync/{activityId}")]
public async Task GetPackageItemDetailByActivityIdAsync(string activityId)
{
try
{
// 验证参数
if (string.IsNullOrEmpty(activityId))
{
throw NCCException.Oh("营销活动ID不能为空");
}
// 检查营销活动是否存在
var activityExists = await _db.Queryable().Where(w => w.Id == activityId && w.IsEffective == StatusEnum.有效.GetHashCode()).AnyAsync();
if (!activityExists)
{
throw NCCException.Oh("营销活动不存在或已失效");
}
// 获取营销活动下的品项ID列表
var itemIds = await _db.Queryable().Where(w => w.ActivityId == activityId && w.IsEffective == StatusEnum.有效.GetHashCode()).Select(w => w.ItemId).ToListAsync();
if (!itemIds.Any())
{
throw NCCException.Oh("该营销活动暂无品项");
}
// 根据品项ID查询项目资料表
var itemDetails = await _db.Queryable()
.Where(w => itemIds.Contains(w.Id) && w.IsEffective == StatusEnum.有效.GetHashCode())
.Select(it => new LqXmzlListOutput
{
id = it.Id,
xmbh = it.Xmbh,
xmmc = it.Xmmc,
bzjg = it.Bzjg,
xmsc = it.Xmsc,
jcfwtc = it.Jcfwtc,
fl1 = it.Fl1,
fl2 = it.Fl2,
fl3 = it.Fl3,
fl4 = it.Fl4,
fl = it.Fl,
qt1 = it.Qt1,
qt2 = it.Qt2,
sgf = it.Sgf,
beautyType = it.BeautyType,
isEffective = it.IsEffective,
sourceType = it.SourceType
}).MergeTable().ToPagedListAsync(1, 50);
return PageResult.SqlSugarPageResult(itemDetails);
}
catch (Exception ex)
{
throw NCCException.Oh($"获取品项详情失败: {ex.Message}");
}
}
#endregion
#region 获取当前时间有效的活动
///
/// 获取当前时间有效的活动
///
/// 当前时间有效的活动
[HttpGet("GetCurrentTimeEffectiveActivityAsync")]
public async Task GetCurrentTimeEffectiveActivityAsync()
{
var data = await _db.Queryable().Where(w => w.StartTime <= DateTime.Now && w.EndTime >= DateTime.Now && w.IsEffective == StatusEnum.有效.GetHashCode()).ToListAsync();
var output = data.Adapt>();
return output;
}
#endregion
#region 营销活动统计
///
/// 获取营销活动统计数据
///
///
/// 统计指定营销活动的开单、退卡相关数据
/// 包括:开单数量、开单金额、退卡数量、退卡金额、净开单数量、净开单金额、退卡率
///
/// 示例请求:
/// ```json
/// {
/// "activityId": "营销活动ID",
/// "startTime": "2025-10-01",
/// "endTime": "2025-10-31",
/// "storeIds": ["门店ID1", "门店ID2"]
/// }
/// ```
///
/// 参数说明:
/// - activityId: 营销活动ID(必填)
/// - startTime: 开始时间(可选,默认为活动开始时间)
/// - endTime: 结束时间(可选,默认为活动结束时间)
/// - storeIds: 门店ID列表(可选)
///
/// 返回字段说明:
/// - ActivityId: 营销活动ID
/// - ActivityName: 营销活动名称
/// - BillingCount: 开单数量
/// - BillingAmount: 开单金额
/// - RefundCount: 退卡数量
/// - RefundAmount: 退卡金额
/// - NetBillingCount: 净开单数量(开单数量 - 退卡数量)
/// - NetBillingAmount: 净开单金额(开单金额 - 退卡金额)
/// - RefundRate: 退卡率(退卡数量 / 开单数量)
/// - DebtAmount: 欠款金额(所有开单的欠款总和)
///
/// 查询参数
/// 营销活动统计数据
/// 成功返回统计数据
/// 参数错误
/// 服务器错误
[HttpPost("get-activity-statistics")]
public async Task