/*********************************************************************** * 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 } }