598 lines
18 KiB
C#
598 lines
18 KiB
C#
using MiAssessment.Admin.Business.Data;
|
||
using MiAssessment.Admin.Business.Entities;
|
||
using MiAssessment.Admin.Business.Models;
|
||
using MiAssessment.Admin.Business.Models.Common;
|
||
using MiAssessment.Admin.Business.Models.Planner;
|
||
using MiAssessment.Admin.Business.Services.Interfaces;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using Microsoft.Extensions.Logging;
|
||
|
||
namespace MiAssessment.Admin.Business.Services;
|
||
|
||
/// <summary>
|
||
/// 规划师服务实现
|
||
/// </summary>
|
||
public class PlannerService : IPlannerService
|
||
{
|
||
private readonly AdminBusinessDbContext _dbContext;
|
||
private readonly ILogger<PlannerService> _logger;
|
||
|
||
/// <summary>
|
||
/// 规划师状态名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> PlannerStatusNames = new()
|
||
{
|
||
{ 0, "禁用" },
|
||
{ 1, "启用" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 预约状态名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> BookingStatusNames = new()
|
||
{
|
||
{ 1, "待联系" },
|
||
{ 2, "已联系" },
|
||
{ 3, "已完成" },
|
||
{ 4, "已取消" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 性别名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> GenderNames = new()
|
||
{
|
||
{ 1, "男" },
|
||
{ 2, "女" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 年级名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> GradeNames = new()
|
||
{
|
||
{ 1, "一年级" },
|
||
{ 2, "二年级" },
|
||
{ 3, "三年级" },
|
||
{ 4, "四年级" },
|
||
{ 5, "五年级" },
|
||
{ 6, "六年级" },
|
||
{ 7, "初一" },
|
||
{ 8, "初二" },
|
||
{ 9, "初三" },
|
||
{ 10, "高一" },
|
||
{ 11, "高二" },
|
||
{ 12, "高三" }
|
||
};
|
||
|
||
|
||
/// <summary>
|
||
/// 订单状态名称映射
|
||
/// </summary>
|
||
private static readonly Dictionary<int, string> OrderStatusNames = new()
|
||
{
|
||
{ 1, "待支付" },
|
||
{ 2, "已支付" },
|
||
{ 3, "已完成" },
|
||
{ 4, "退款中" },
|
||
{ 5, "已退款" },
|
||
{ 6, "已取消" }
|
||
};
|
||
|
||
/// <summary>
|
||
/// 构造函数
|
||
/// </summary>
|
||
/// <param name="dbContext">数据库上下文</param>
|
||
/// <param name="logger">日志记录器</param>
|
||
public PlannerService(
|
||
AdminBusinessDbContext dbContext,
|
||
ILogger<PlannerService> logger)
|
||
{
|
||
_dbContext = dbContext;
|
||
_logger = logger;
|
||
}
|
||
|
||
#region 规划师管理
|
||
|
||
/// <inheritdoc />
|
||
public async Task<PagedResult<PlannerDto>> GetPlannerListAsync(PlannerQueryRequest request)
|
||
{
|
||
// 构建查询,过滤软删除记录
|
||
var query = _dbContext.Planners
|
||
.AsNoTracking()
|
||
.Where(p => !p.IsDeleted);
|
||
|
||
// 应用过滤条件
|
||
if (!string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
query = query.Where(p => p.Name.Contains(request.Name));
|
||
}
|
||
|
||
if (request.Status.HasValue)
|
||
{
|
||
query = query.Where(p => p.Status == request.Status.Value);
|
||
}
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页查询,按排序字段降序排列
|
||
var plannerIds = await query
|
||
.OrderByDescending(p => p.Sort)
|
||
.ThenByDescending(p => p.CreateTime)
|
||
.Skip(request.Skip)
|
||
.Take(request.PageSize)
|
||
.Select(p => p.Id)
|
||
.ToListAsync();
|
||
|
||
// 获取预约数量
|
||
var bookingCounts = await _dbContext.PlannerBookings
|
||
.AsNoTracking()
|
||
.Where(b => plannerIds.Contains(b.PlannerId) && !b.IsDeleted)
|
||
.GroupBy(b => b.PlannerId)
|
||
.Select(g => new { PlannerId = g.Key, Count = g.Count() })
|
||
.ToDictionaryAsync(x => x.PlannerId, x => x.Count);
|
||
|
||
// 获取规划师详情
|
||
var items = await query
|
||
.OrderByDescending(p => p.Sort)
|
||
.ThenByDescending(p => p.CreateTime)
|
||
.Skip(request.Skip)
|
||
.Take(request.PageSize)
|
||
.Select(p => new PlannerDto
|
||
{
|
||
Id = p.Id,
|
||
Name = p.Name,
|
||
Avatar = p.Avatar,
|
||
Title = p.Title,
|
||
Introduction = p.Introduction,
|
||
Tags = p.Tags,
|
||
Price = p.Price,
|
||
Sort = p.Sort,
|
||
Status = p.Status,
|
||
StatusName = GetPlannerStatusName(p.Status),
|
||
BookingCount = 0, // 稍后填充
|
||
CreateTime = p.CreateTime,
|
||
UpdateTime = p.UpdateTime
|
||
})
|
||
.ToListAsync();
|
||
|
||
// 填充预约数量
|
||
foreach (var item in items)
|
||
{
|
||
item.BookingCount = bookingCounts.TryGetValue(item.Id, out var count) ? count : 0;
|
||
}
|
||
|
||
return PagedResult<PlannerDto>.Create(items, total, request.Page, request.PageSize);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<long> CreatePlannerAsync(CreatePlannerRequest request)
|
||
{
|
||
var planner = new Planner
|
||
{
|
||
Name = request.Name,
|
||
Avatar = request.Avatar,
|
||
Title = request.Title,
|
||
Introduction = request.Introduction,
|
||
Tags = request.Tags,
|
||
Price = request.Price,
|
||
Sort = request.Sort,
|
||
Status = request.Status,
|
||
CreateTime = DateTime.Now,
|
||
UpdateTime = DateTime.Now,
|
||
IsDeleted = false
|
||
};
|
||
|
||
_dbContext.Planners.Add(planner);
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("创建规划师成功,ID: {PlannerId}, 姓名: {Name}", planner.Id, planner.Name);
|
||
|
||
return planner.Id;
|
||
}
|
||
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdatePlannerAsync(UpdatePlannerRequest request)
|
||
{
|
||
var planner = await _dbContext.Planners
|
||
.Where(p => p.Id == request.Id && !p.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (planner == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.PlannerNotFound, "规划师不存在");
|
||
}
|
||
|
||
// 验证价格
|
||
if (request.Price <= 0)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "价格必须大于0");
|
||
}
|
||
|
||
planner.Name = request.Name;
|
||
planner.Avatar = request.Avatar;
|
||
planner.Title = request.Title;
|
||
planner.Introduction = request.Introduction;
|
||
planner.Tags = request.Tags;
|
||
planner.Price = request.Price;
|
||
planner.Sort = request.Sort;
|
||
planner.Status = request.Status;
|
||
planner.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新规划师成功,ID: {PlannerId}", request.Id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> DeletePlannerAsync(long id)
|
||
{
|
||
var planner = await _dbContext.Planners
|
||
.Where(p => p.Id == id && !p.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (planner == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.PlannerNotFound, "规划师不存在");
|
||
}
|
||
|
||
// 软删除
|
||
planner.IsDeleted = true;
|
||
planner.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("删除规划师成功,ID: {PlannerId}", id);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdatePlannerStatusAsync(long id, int status)
|
||
{
|
||
var planner = await _dbContext.Planners
|
||
.Where(p => p.Id == id && !p.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (planner == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.PlannerNotFound, "规划师不存在");
|
||
}
|
||
|
||
planner.Status = status;
|
||
planner.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新规划师状态成功,ID: {PlannerId}, 状态: {Status}", id, status);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdatePlannerSortAsync(List<SortItem> items)
|
||
{
|
||
if (items == null || items.Count == 0)
|
||
{
|
||
return true;
|
||
}
|
||
|
||
var ids = items.Select(i => i.Id).ToList();
|
||
var planners = await _dbContext.Planners
|
||
.Where(p => ids.Contains(p.Id) && !p.IsDeleted)
|
||
.ToListAsync();
|
||
|
||
foreach (var planner in planners)
|
||
{
|
||
var sortItem = items.FirstOrDefault(i => i.Id == planner.Id);
|
||
if (sortItem != null)
|
||
{
|
||
planner.Sort = sortItem.Sort;
|
||
planner.UpdateTime = DateTime.Now;
|
||
}
|
||
}
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新规划师排序成功,数量: {Count}", items.Count);
|
||
|
||
return true;
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
#region 预约记录管理
|
||
|
||
/// <inheritdoc />
|
||
public async Task<PagedResult<BookingDto>> GetBookingListAsync(BookingQueryRequest request)
|
||
{
|
||
// 构建查询,过滤软删除记录
|
||
var query = _dbContext.PlannerBookings
|
||
.AsNoTracking()
|
||
.Include(b => b.User)
|
||
.Include(b => b.Planner)
|
||
.Include(b => b.Order)
|
||
.Where(b => !b.IsDeleted);
|
||
|
||
// 应用过滤条件
|
||
query = ApplyBookingQueryFilters(query, request);
|
||
|
||
// 获取总数
|
||
var total = await query.CountAsync();
|
||
|
||
// 分页查询,按创建时间降序排列
|
||
var items = await query
|
||
.OrderByDescending(b => b.CreateTime)
|
||
.Skip(request.Skip)
|
||
.Take(request.PageSize)
|
||
.Select(b => new BookingDto
|
||
{
|
||
Id = b.Id,
|
||
UserId = b.UserId,
|
||
UserNickname = b.User != null ? b.User.Nickname : null,
|
||
UserPhone = b.User != null ? b.User.Phone : null,
|
||
OrderId = b.OrderId,
|
||
OrderNo = b.Order != null ? b.Order.OrderNo : null,
|
||
PlannerId = b.PlannerId,
|
||
PlannerName = b.Planner != null ? b.Planner.Name : null,
|
||
BookingDate = b.BookingDate,
|
||
BookingTime = b.BookingTime,
|
||
Name = b.Name,
|
||
Phone = b.Phone,
|
||
Gender = b.Gender,
|
||
GenderName = GetGenderName(b.Gender),
|
||
Grade = b.Grade,
|
||
GradeName = GetGradeName(b.Grade),
|
||
Status = b.Status,
|
||
StatusName = GetBookingStatusName(b.Status),
|
||
CreateTime = b.CreateTime
|
||
})
|
||
.ToListAsync();
|
||
|
||
return PagedResult<BookingDto>.Create(items, total, request.Page, request.PageSize);
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<BookingDetailDto?> GetBookingDetailAsync(long id)
|
||
{
|
||
var booking = await _dbContext.PlannerBookings
|
||
.AsNoTracking()
|
||
.Include(b => b.User)
|
||
.Include(b => b.Planner)
|
||
.Include(b => b.Order)
|
||
.Where(b => b.Id == id && !b.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (booking == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
return new BookingDetailDto
|
||
{
|
||
Id = booking.Id,
|
||
UserId = booking.UserId,
|
||
UserNickname = booking.User?.Nickname,
|
||
UserPhone = booking.User?.Phone,
|
||
OrderId = booking.OrderId,
|
||
OrderNo = booking.Order?.OrderNo,
|
||
PlannerId = booking.PlannerId,
|
||
PlannerName = booking.Planner?.Name,
|
||
PlannerAvatar = booking.Planner?.Avatar,
|
||
PlannerIntroduction = booking.Planner?.Introduction,
|
||
BookingDate = booking.BookingDate,
|
||
BookingTime = booking.BookingTime,
|
||
Name = booking.Name,
|
||
Phone = booking.Phone,
|
||
Gender = booking.Gender,
|
||
GenderName = GetGenderName(booking.Gender),
|
||
Grade = booking.Grade,
|
||
GradeName = GetGradeName(booking.Grade),
|
||
MajorName = booking.MajorName,
|
||
ScoreChinese = booking.ScoreChinese,
|
||
ScoreMath = booking.ScoreMath,
|
||
ScoreEnglish = booking.ScoreEnglish,
|
||
ScorePhysics = booking.ScorePhysics,
|
||
ScoreChemistry = booking.ScoreChemistry,
|
||
ScoreBiology = booking.ScoreBiology,
|
||
ScoreGeography = booking.ScoreGeography,
|
||
ScorePolitics = booking.ScorePolitics,
|
||
Status = booking.Status,
|
||
StatusName = GetBookingStatusName(booking.Status),
|
||
OrderAmount = booking.Order?.Amount,
|
||
OrderStatus = booking.Order?.Status,
|
||
OrderStatusName = booking.Order != null ? GetOrderStatusName(booking.Order.Status) : null,
|
||
CreateTime = booking.CreateTime,
|
||
UpdateTime = booking.UpdateTime
|
||
};
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<bool> UpdateBookingStatusAsync(long id, int status, string? remark)
|
||
{
|
||
var booking = await _dbContext.PlannerBookings
|
||
.Where(b => b.Id == id && !b.IsDeleted)
|
||
.FirstOrDefaultAsync();
|
||
|
||
if (booking == null)
|
||
{
|
||
throw new BusinessException(ErrorCodes.BookingNotFound, "预约记录不存在");
|
||
}
|
||
|
||
// 验证状态值
|
||
if (status < 1 || status > 4)
|
||
{
|
||
throw new BusinessException(ErrorCodes.ParamError, "状态值无效");
|
||
}
|
||
|
||
booking.Status = status;
|
||
booking.UpdateTime = DateTime.Now;
|
||
|
||
await _dbContext.SaveChangesAsync();
|
||
|
||
_logger.LogInformation("更新预约状态成功,ID: {BookingId}, 状态: {Status}", id, status);
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <inheritdoc />
|
||
public async Task<List<BookingDto>> ExportBookingsAsync(BookingQueryRequest request)
|
||
{
|
||
// 构建查询,过滤软删除记录
|
||
var query = _dbContext.PlannerBookings
|
||
.AsNoTracking()
|
||
.Include(b => b.User)
|
||
.Include(b => b.Planner)
|
||
.Include(b => b.Order)
|
||
.Where(b => !b.IsDeleted);
|
||
|
||
// 应用过滤条件
|
||
query = ApplyBookingQueryFilters(query, request);
|
||
|
||
// 查询所有匹配的记录(不分页)
|
||
var items = await query
|
||
.OrderByDescending(b => b.CreateTime)
|
||
.Select(b => new BookingDto
|
||
{
|
||
Id = b.Id,
|
||
UserId = b.UserId,
|
||
UserNickname = b.User != null ? b.User.Nickname : null,
|
||
UserPhone = b.User != null ? b.User.Phone : null,
|
||
OrderId = b.OrderId,
|
||
OrderNo = b.Order != null ? b.Order.OrderNo : null,
|
||
PlannerId = b.PlannerId,
|
||
PlannerName = b.Planner != null ? b.Planner.Name : null,
|
||
BookingDate = b.BookingDate,
|
||
BookingTime = b.BookingTime,
|
||
Name = b.Name,
|
||
Phone = b.Phone,
|
||
Gender = b.Gender,
|
||
GenderName = GetGenderName(b.Gender),
|
||
Grade = b.Grade,
|
||
GradeName = GetGradeName(b.Grade),
|
||
Status = b.Status,
|
||
StatusName = GetBookingStatusName(b.Status),
|
||
CreateTime = b.CreateTime
|
||
})
|
||
.ToListAsync();
|
||
|
||
_logger.LogInformation("导出预约记录成功,数量: {Count}", items.Count);
|
||
|
||
return items;
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
#region 私有方法
|
||
|
||
/// <summary>
|
||
/// 应用预约查询过滤条件
|
||
/// </summary>
|
||
/// <param name="query">查询</param>
|
||
/// <param name="request">请求</param>
|
||
/// <returns>过滤后的查询</returns>
|
||
private IQueryable<PlannerBooking> ApplyBookingQueryFilters(IQueryable<PlannerBooking> query, BookingQueryRequest request)
|
||
{
|
||
// 按规划师ID筛选
|
||
if (request.PlannerId.HasValue)
|
||
{
|
||
query = query.Where(b => b.PlannerId == request.PlannerId.Value);
|
||
}
|
||
|
||
// 按用户ID筛选
|
||
if (request.UserId.HasValue)
|
||
{
|
||
query = query.Where(b => b.UserId == request.UserId.Value);
|
||
}
|
||
|
||
// 按预约日期范围筛选
|
||
if (request.BookingDateStart.HasValue)
|
||
{
|
||
query = query.Where(b => b.BookingDate >= request.BookingDateStart.Value);
|
||
}
|
||
if (request.BookingDateEnd.HasValue)
|
||
{
|
||
var endDate = request.BookingDateEnd.Value.AddDays(1);
|
||
query = query.Where(b => b.BookingDate < endDate);
|
||
}
|
||
|
||
// 按状态筛选
|
||
if (request.Status.HasValue)
|
||
{
|
||
query = query.Where(b => b.Status == request.Status.Value);
|
||
}
|
||
|
||
// 按姓名模糊搜索
|
||
if (!string.IsNullOrWhiteSpace(request.Name))
|
||
{
|
||
query = query.Where(b => b.Name.Contains(request.Name));
|
||
}
|
||
|
||
// 按手机号模糊搜索
|
||
if (!string.IsNullOrWhiteSpace(request.Phone))
|
||
{
|
||
query = query.Where(b => b.Phone.Contains(request.Phone));
|
||
}
|
||
|
||
return query;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取规划师状态名称
|
||
/// </summary>
|
||
/// <param name="status">状态值</param>
|
||
/// <returns>状态名称</returns>
|
||
private static string GetPlannerStatusName(int status)
|
||
{
|
||
return PlannerStatusNames.TryGetValue(status, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取预约状态名称
|
||
/// </summary>
|
||
/// <param name="status">状态值</param>
|
||
/// <returns>状态名称</returns>
|
||
private static string GetBookingStatusName(int status)
|
||
{
|
||
return BookingStatusNames.TryGetValue(status, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取性别名称
|
||
/// </summary>
|
||
/// <param name="gender">性别值</param>
|
||
/// <returns>性别名称</returns>
|
||
private static string GetGenderName(int gender)
|
||
{
|
||
return GenderNames.TryGetValue(gender, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取年级名称
|
||
/// </summary>
|
||
/// <param name="grade">年级值</param>
|
||
/// <returns>年级名称</returns>
|
||
private static string GetGradeName(int grade)
|
||
{
|
||
return GradeNames.TryGetValue(grade, out var name) ? name : "未知";
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取订单状态名称
|
||
/// </summary>
|
||
/// <param name="status">状态值</param>
|
||
/// <returns>状态名称</returns>
|
||
private static string GetOrderStatusName(int status)
|
||
{
|
||
return OrderStatusNames.TryGetValue(status, out var name) ? name : "未知";
|
||
}
|
||
|
||
#endregion
|
||
}
|