/***********************************************************************
* Project: CoreCms
* ProjectName: 核心内容管理系统
* Web: https://www.corecms.net
* Author: 大灰灰
* Email: jianweie@163.com
* CreateTime: 2025/9/2 12:47:30
* Description: 暂无
***********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading.Tasks;
using CoreCms.Net.Caching.AutoMate.RedisCache;
using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository;
using CoreCms.Net.IRepository.UnitOfWork;
using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.ViewModels.Basics;
using CoreCms.Net.Model.ViewModels.UI;
using CoreCms.Net.Model.ViewModels.SQ;
using CoreCms.Net.Utility.Helper;
using SqlSugar;
using System.Linq;
namespace CoreCms.Net.Services
{
///
/// 房间表 接口实现
///
public class SQRoomsServices : BaseServices, ISQRoomsServices
{
private readonly ISQRoomsRepository _dal;
private readonly IUnitOfWork _unitOfWork;
private readonly IRedisOperationRepository _redisOperationRepository;
private readonly ISQRoomPricingServices _pricingServices;
private readonly ISQReservationsServices _reservationsServices;
private readonly ISQRoomUnavailableTimesServices _unavailableTimesServices;
public SQRoomsServices(IUnitOfWork unitOfWork, ISQRoomsRepository dal,
IRedisOperationRepository redisOperationRepository,
ISQRoomPricingServices pricingServices,
ISQReservationsServices reservationsServices,
ISQRoomUnavailableTimesServices unavailableTimesServices)
{
this._dal = dal;
base.BaseDal = dal;
_unitOfWork = unitOfWork;
_redisOperationRepository = redisOperationRepository;
_pricingServices = pricingServices;
_reservationsServices = reservationsServices;
_unavailableTimesServices = unavailableTimesServices;
}
#region 实现重写增删改查操作==========================================================
///
/// 重写异步插入方法
///
/// 实体数据
///
public new async Task InsertAsync(SQRooms entity)
{
return await _dal.InsertAsync(entity);
}
///
/// 重写异步更新方法方法
///
///
///
public new async Task UpdateAsync(SQRooms entity)
{
return await _dal.UpdateAsync(entity);
}
///
/// 重写异步更新方法方法
///
///
///
public new async Task UpdateAsync(List entity)
{
return await _dal.UpdateAsync(entity);
}
///
/// 重写删除指定ID的数据
///
///
///
public new async Task DeleteByIdAsync(object id)
{
return await _dal.DeleteByIdAsync(id);
}
///
/// 重写删除指定ID集合的数据(批量删除)
///
///
///
public new async Task DeleteByIdsAsync(int[] ids)
{
return await _dal.DeleteByIdsAsync(ids);
}
#endregion
#region 获取缓存的所有数据==========================================================
///
/// 获取缓存的所有数据
///
///
public async Task> GetCaChe()
{
return await _dal.GetCaChe();
}
///
/// 更新cache
///
public async Task> UpdateCaChe()
{
return await _dal.UpdateCaChe();
}
#endregion
#region 重写根据条件查询分页数据
///
/// 重写根据条件查询分页数据
///
/// 判断集合
/// 排序方式
/// 当前页面索引
/// 分布大小
///
/// 是否使用WITH(NOLOCK)
///
public new async Task> QueryPageAsync(Expression> predicate,
Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1,
int pageSize = 20, bool blUseNoLock = false)
{
return await _dal.QueryPageAsync(predicate, orderByExpression, orderByType, pageIndex, pageSize, blUseNoLock);
}
///
///
///
///
public async Task> GetRoomList()
{
var key = $"room:GetRoomList";
var list = await _redisOperationRepository.Get>(key);
if (list == null)
{
list = await _dal.QueryAsync(true);
await _redisOperationRepository.Set(key, list, TimeSpan.FromSeconds(60));
}
return list;
}
#endregion
#region 按时段预约相关方法
///
/// 获取房间列表及时段状态
///
public async Task> GetRoomListWithSlotsAsync(DateTime date, bool showOnlyAvailable = false, int? currentTimeSlot = null)
{
var dayStart = date.Date;
var dayEnd = dayStart.AddDays(1).AddSeconds(-1);
var now = DateTime.Now;
// 查询所有可用房间
var allRooms = await _dal.QueryListByClauseAsync(r => r.status == true, r => r.sort_order ?? r.id, OrderByType.Asc);
if (allRooms == null || allRooms.Count == 0)
{
return new List();
}
var result = new List();
foreach (var room in allRooms)
{
var roomDto = new SQRoomListDto
{
id = room.id,
name = room.name,
room_type_name = room.room_type_name ?? room.room_type,
image_url = room.image_url,
capacity = room.capacity,
description = room.description,
status = GlobalConstVars.RoomStatusAvailable,
is_available = true,
can_reserve = false,
time_slots = new List()
};
// 获取房间所有时段的价格配置
var pricingList = await _pricingServices.GetRoomAllPricingAsync(room.id, date);
// 查询当天的预约记录
var reservations = await _reservationsServices.QueryListByClauseAsync(
r => r.room_id == room.id && r.status < 3 && r.start_time < dayEnd && r.end_time > dayStart,
r => r.start_time, OrderByType.Asc);
// 查询不可用时段
var unavailableTimes = await _unavailableTimesServices.QueryListByClauseAsync(
t => t.room_id == room.id && t.start_time < dayEnd && t.end_time > dayStart,
t => t.start_time, OrderByType.Asc);
// 构建4个时段的状态
for (int slotType = 0; slotType <= 3; slotType++)
{
var (slotStart, slotEnd) = TimeSlotHelper.GetTimeRange(dayStart, slotType);
var pricing = pricingList.FirstOrDefault(p => p.time_slot_type == slotType);
var slotDto = new SQTimeSlotDto
{
slot_type = slotType,
slot_name = TimeSlotHelper.GetTimeSlotName(slotType),
status = GlobalConstVars.RoomStatusAvailable,
standard_price = pricing?.standard_price ?? 0,
member_price = pricing?.member_price ?? 0,
price_desc_standard = pricing?.price_desc_standard,
price_desc_member = pricing?.price_desc_member
};
// 检查时段是否已过期(仅当查询日期是今天时)
bool isPassed = dayStart.Date == DateTime.Today && TimeSlotHelper.IsTimeSlotPassed(dayStart, slotType);
if (isPassed)
{
// 时段已过期,标记为不可用
slotDto.status = GlobalConstVars.RoomStatusUnavailable;
}
else
{
// 检查不可用时段,并获取禁用类型
var unavailableRecord = unavailableTimes?.FirstOrDefault(u =>
(u.time_slot_type.HasValue && u.time_slot_type.Value == slotType) ||
(u.start_time < slotEnd && u.end_time > slotStart));
if (unavailableRecord != null)
{
slotDto.status = GlobalConstVars.RoomStatusUnavailable;
slotDto.unavailable_type = unavailableRecord.type; // 设置禁用类型
}
else
{
// 检查是否已预约
bool isReserved = reservations?.Any(r =>
r.start_time < slotEnd && r.end_time > slotStart) ?? false;
if (isReserved)
{
slotDto.status = GlobalConstVars.RoomStatusReserved;
// 检查是否正在使用中
bool isUsing = reservations.Any(r => r.start_time <= now && r.end_time > now);
if (isUsing && dayStart.Date == DateTime.Today)
{
slotDto.status = GlobalConstVars.RoomStatusUsing;
roomDto.status = GlobalConstVars.RoomStatusUsing;
roomDto.is_available = false;
}
}
else if (slotDto.status == GlobalConstVars.RoomStatusAvailable)
{
roomDto.can_reserve = true;
}
}
}
roomDto.time_slots.Add(slotDto);
}
// 设置价格说明(使用第一个可用时段的价格作为展示)
var firstPricing = pricingList.FirstOrDefault();
if (firstPricing != null)
{
roomDto.standard_price_desc = firstPricing.price_desc_standard;
roomDto.member_price_desc = firstPricing.price_desc_member;
}
// 如果启用筛选,只显示指定时段可用的房间
if (showOnlyAvailable && currentTimeSlot.HasValue)
{
var currentSlot = roomDto.time_slots.FirstOrDefault(s => s.slot_type == currentTimeSlot.Value);
if (currentSlot == null || currentSlot.status != GlobalConstVars.RoomStatusAvailable)
{
continue;
}
}
result.Add(roomDto);
}
return result;
}
///
/// 获取房间详情
///
public async Task GetRoomDetailAsync(int roomId, DateTime date)
{
// 1. 查询房间信息
var room = await _dal.QueryByIdAsync(roomId);
if (room == null)
{
return null;
}
// 2. 确定查询日期范围
var dayStart = date.Date;
var dayEnd = dayStart.AddDays(1).AddSeconds(-1);
var now = DateTime.Now;
// 3. 构建房间详情DTO
var roomDetail = new SQRoomDetailDto
{
id = room.id,
name = room.name,
room_type = room.room_type,
room_type_name = room.room_type_name ?? room.room_type,
image_url = room.image_url,
price_per_hour = room.price_per_hour,
capacity = room.capacity,
description = room.description,
status = GlobalConstVars.RoomStatusAvailable,
is_available = true,
can_reserve = false
};
// 4. 解析多图(image_detailed_url,按逗号分割)
if (!string.IsNullOrEmpty(room.image_detailed_url))
{
roomDetail.images = room.image_detailed_url
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(img => img.Trim())
.ToList();
}
// 5. 解析设施列表(amenities,按逗号分割)
if (!string.IsNullOrEmpty(room.amenities))
{
roomDetail.amenities = room.amenities
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(a => a.Trim())
.ToList();
}
// 6. 获取房间所有时段的价格配置
var pricingList = await _pricingServices.GetRoomAllPricingAsync(room.id, date);
// 7. 查询当天的预约记录
var reservations = await _reservationsServices.QueryListByClauseAsync(
r => r.room_id == roomId && r.status < 3 && r.start_time < dayEnd && r.end_time > dayStart,
r => r.start_time, OrderByType.Asc);
// 8. 查询不可用时段
var unavailableTimes = await _unavailableTimesServices.QueryListByClauseAsync(
t => t.room_id == roomId && t.start_time < dayEnd && t.end_time > dayStart,
t => t.start_time, OrderByType.Asc);
// 9. 构建4个时段的状态(与列表接口逻辑一致,并整合预约信息)
for (int slotType = 0; slotType <= 3; slotType++)
{
var (slotStart, slotEnd) = TimeSlotHelper.GetTimeRange(dayStart, slotType);
var pricing = pricingList.FirstOrDefault(p => p.time_slot_type == slotType);
var slotDto = new SQTimeSlotDto
{
slot_type = slotType,
slot_name = TimeSlotHelper.GetTimeSlotName(slotType),
status = GlobalConstVars.RoomStatusAvailable,
standard_price = pricing?.standard_price ?? 0,
member_price = pricing?.member_price ?? 0,
price_desc_standard = pricing?.price_desc_standard,
price_desc_member = pricing?.price_desc_member
};
// 检查时段是否已过期(仅当查询日期是今天时)
bool isPassed = dayStart.Date == DateTime.Today && TimeSlotHelper.IsTimeSlotPassed(dayStart, slotType);
if (isPassed)
{
// 时段已过期,标记为不可用
slotDto.status = GlobalConstVars.RoomStatusUnavailable;
}
else
{
// 检查不可用时段
bool isUnavailable = unavailableTimes?.Any(u =>
(u.time_slot_type.HasValue && u.time_slot_type.Value == slotType) ||
(u.start_time < slotEnd && u.end_time > slotStart)) ?? false;
if (isUnavailable)
{
slotDto.status = GlobalConstVars.RoomStatusUnavailable;
}
else
{
// 查找属于该时段的预约(预约时间与时段有重叠)
var slotReservations = reservations?.Where(r =>
r.start_time < slotEnd && r.end_time > slotStart).ToList() ?? new List();
if (slotReservations.Count > 0)
{
slotDto.status = GlobalConstVars.RoomStatusReserved;
// 检查是否正在使用中
bool isUsing = slotReservations.Any(r => r.start_time <= now && r.end_time > now);
if (isUsing && dayStart.Date == DateTime.Today)
{
slotDto.status = GlobalConstVars.RoomStatusUsing;
roomDetail.status = GlobalConstVars.RoomStatusUsing;
roomDetail.is_available = false;
}
// 填充该时段内的预约信息
slotDto.reservations = slotReservations.Select(r => new SQTimeSlotReservationDto
{
reservation_id = r.id,
start_time = r.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
end_time = r.end_time.ToString("yyyy-MM-dd HH:mm:ss"),
status = r.status,
title = r.title,
game_type = r.game_type
}).ToList();
}
else if (slotDto.status == GlobalConstVars.RoomStatusAvailable)
{
roomDetail.can_reserve = true;
}
}
}
roomDetail.time_slots.Add(slotDto);
}
// 10. 设置价格说明(使用第一个可用时段的价格作为展示)
var firstPricing = pricingList.FirstOrDefault();
if (firstPricing != null)
{
roomDetail.standard_price_desc = firstPricing.price_desc_standard;
roomDetail.member_price_desc = firstPricing.price_desc_member;
}
// 11. 填充今日预约情况(保留兼容性,但建议使用 time_slots 中的 reservations)
if (reservations != null && reservations.Count > 0)
{
roomDetail.today_reservations = reservations.Select(r => new SQRoomDetailReservationDto
{
start_time = r.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
end_time = r.end_time.ToString("yyyy-MM-dd HH:mm:ss"),
status = r.status
}).ToList();
}
// 12. 最终状态检查:如果有任何不可用时段,设置整体状态
if (unavailableTimes != null && unavailableTimes.Count > 0)
{
// 只有当所有时段都不可用时,才设置为 unavailable
bool allUnavailable = roomDetail.time_slots.All(s => s.status == GlobalConstVars.RoomStatusUnavailable);
if (allUnavailable)
{
roomDetail.status = GlobalConstVars.RoomStatusUnavailable;
roomDetail.is_available = false;
}
}
return roomDetail;
}
#endregion
}
}