using AutoMapper; using CoreCms.Net.Auth.HttpContextUser; using CoreCms.Net.IRepository.UnitOfWork; using CoreCms.Net.IServices; using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.Entities.Expression; using CoreCms.Net.Model.ViewModels.Basics; using CoreCms.Net.Model.ViewModels.SQ; using CoreCms.Net.Model.ViewModels.UI; using CoreCms.Net.Services; using CoreCms.Net.Services.SQ; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using NPOI.SS.Formula.Functions; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using CoreCms.Net.Services.SQ; using CoreCms.Net.Utility.Extensions; using ToolGood.Words.internals; using NPOI.SS.Formula.PTG; using NPOI.OpenXmlFormats.Dml; using Humanizer; namespace CoreCms.Net.Web.WebApi.Controllers; /// /// 预约接口 /// [Route("api/[controller]/[action]")] [ApiController] public class SQController : ControllerBase { private readonly IWebHostEnvironment _webHostEnvironment; private readonly ISQReservationsServices _SQReservationsServices; private readonly ISQRoomsServices _SQRoomsServices; private readonly ISysDictionaryDataServices _sysDictionaryDataServices; private readonly ISysDictionaryServices _sysDictionaryServices; private readonly ISQReservationParticipantsServices _SQReservationParticipantsServices; private readonly IMapper _mapper; private readonly ICoreCmsUserServices _userServices; private readonly IHttpContextUser _user; private readonly SqlSugarScope _dbBase; private readonly ICoreCmsUserBlacklistServices _coreCmsUserBlacklistServices; private readonly ISQReservationReputationServices _sQReservationReputationServices; private readonly ISQReservationEvaluateServices _sQReservationEvaluateServices; private readonly ISQRoomUnavailableTimesServices _sQRoomUnavailableTimesServices; /// /// 构造函数 /// public SQController(IWebHostEnvironment webHostEnvironment , ISQReservationsServices SQReservationsServices , ISQRoomsServices SQRoomsServices , ISysDictionaryServices sysDictionaryServices , ISysDictionaryDataServices sysDictionaryDataServices , ISQReservationParticipantsServices sQReservationParticipantsServices , IMapper mapper , ICoreCmsUserServices userServices , IHttpContextUser user , IUnitOfWork unitOfWork , ICoreCmsUserBlacklistServices coreCmsUserBlacklistServices , ISQReservationEvaluateServices sQReservationEvaluateServices , ISQReservationReputationServices sQReservationReputationServices , ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices ) { _webHostEnvironment = webHostEnvironment; _SQReservationsServices = SQReservationsServices; _SQRoomsServices = SQRoomsServices; _sysDictionaryServices = sysDictionaryServices; _sysDictionaryDataServices = sysDictionaryDataServices; _SQReservationParticipantsServices = sQReservationParticipantsServices; _mapper = mapper; _userServices = userServices; _user = user; _dbBase = unitOfWork.GetDbClient(); _coreCmsUserBlacklistServices = coreCmsUserBlacklistServices; _sQReservationEvaluateServices = sQReservationEvaluateServices; _sQReservationReputationServices = sQReservationReputationServices; _sQRoomUnavailableTimesServices = sQRoomUnavailableTimesServices; } /// /// 我的预约记录 /// /// 0 参与者,1发起者 /// 起始页 /// 页大小 /// [HttpGet] [Authorize] public async Task GetMyReservation([FromQuery] int type = 0, [FromQuery] int index = 1, [FromQuery] int size = 10) { var userId = _user.ID; var list = await _dbBase.Ado.SqlQueryAsync($"select r.*,p.id pid, p.status pstatus,p.join_time, p.quit_time ,p.is_refund from SQReservationParticipants p inner join SQReservations r on p.reservation_id=r.id where p.user_id={userId} and p.role={type} order by p.id desc OFFSET {(index - 1) * size} ROWS FETCH NEXT {size} ROWS ONLY"); if (list != null && list.Count > 0) { var roomList = await _SQRoomsServices.GetRoomList(); // 转为基类列表 var baseList = list.Cast().ToList(); await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper); } return new WebApiDto() { Data = list, Code = 0, }; } /// /// 获取正在进行的预约 /// /// [HttpGet] [Authorize] public async Task GetMyUseReservation() { var userId = _user.ID; var list = await _dbBase.Ado.SqlQueryAsync($"select top 3 r.* from SQReservations r left join SQReservationParticipants p on r.id=p.reservation_id where r.status<2 and p.user_id={userId} and p.status=0 order by r.start_time "); if (list != null && list.Count > 0) { var roomList = await _SQRoomsServices.GetRoomList(); // 转为基类列表 var baseList = list.Cast().ToList(); await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper); } return new WebApiDto() { Data = list, Code = 0, }; } /// /// 首页预约列表 /// /// /// /// [HttpGet] public async Task GetReservationList([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20) { var userId = _user.ID; var now = DateTime.Now; var roomList = await _SQRoomsServices.GetRoomList(); var where = PredicateBuilder.True(); where = where.And(it => it.end_time > now); where = where.And(it => it.status < 2); var list = await _SQReservationsServices.QueryPageAsync(where, it => it.start_time, OrderByType.Asc, pageIndex, pageSize, true); var pageList = _mapper.Map>(list); if (pageList != null && pageList.Count > 0) { // 转为基类列表 var baseList = pageList.Cast().ToList(); await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper); } return new WebApiDto() { Data = pageList, Code = 0, Msg = "ok", }; } /// /// 获取预约评价 /// /// /// [HttpGet] [Authorize] public async Task GetEvaluateServices([FromQuery] int reId) { var userId = _user.ID; var list = await _sQReservationEvaluateServices.QueryListByClauseAsync(it => it.reservation_id == reId && it.user_id == userId); var participants = await _dbBase.Ado.SqlQueryAsync($"select p.id,p.reservation_id,p.status,p.join_time,p.user_id, p.role,u.nickName UserName,u.avatarImage AvatarImage,ISNULL(u.play_level,4) play_level,ISNULL(u.skills_level,4) skills_level from SQReservationParticipants p inner join CoreCmsUser u on p.user_id=u.id where p.status=0 and p.reservation_id ={reId} and p.is_arrive=1 "); if (participants == null || participants.Count == 0) { return new WebApiDto() { Code = 0, Data = null }; } var userBlack = await _coreCmsUserBlacklistServices.GetUserBlacklists(userId); List obj = new List(); foreach (var item in participants) { if (item.user_id == userId) { continue; } var is_evaluate = false; decimal play_level = 0; decimal skills_level = 0; decimal user_play_level = 4; decimal user_skills_level = 4; DateTime? now = null; var userBlackStatus = false; if (list.Count > 0) { var e = list.Find(it => it.to_user_id == item.user_id); if (e != null) { is_evaluate = true; play_level = e.play_level; skills_level = e.skills_level; now = e.created_at; user_play_level = e.play_level; user_skills_level = e.skills_level; } } if (userBlack.Count > 0) { if (userBlack.Any(it => it == item.user_id)) { userBlackStatus = true; } } var o = new { item.UserName, item.user_id, item.AvatarImage, userBlackStatus, user_play_level, user_skills_level, is_evaluate, play_level, skills_level, evaluate_at = now }; obj.Add(o); } return new WebApiDto() { Code = 0, Data = obj }; } /// /// 评价用户 /// /// /// [HttpPost] [Authorize] public async Task AddEvaluateServices([FromBody] SQReservationEvaluateDto evaluate) { var userId = _user.ID; var reId = evaluate.reservation_id; var list = await _sQReservationEvaluateServices.QueryListByClauseAsync(it => it.reservation_id == reId && it.user_id == userId); var participants = await _dbBase.Ado.SqlQueryAsync($"select p.id,p.reservation_id,p.status,p.join_time,p.user_id, p.role,u.nickName UserName,u.avatarImage AvatarImage,ISNULL(u.play_level,4) play_level,ISNULL(u.skills_level,4) skills_level from SQReservationParticipants p inner join CoreCmsUser u on p.user_id=u.id where p.status=0 and p.reservation_id ={reId} and p.is_arrive=1 "); if (participants == null) { return new WebApiDto() { Code = 0, Data = null }; } List obj = new List(); var p = participants.Find(it => it.user_id == evaluate.to_user_id); if (p == null) { return new WebApiDto() { Code = 500, Data = null, Msg = "未找到对局记录" }; } SQReservationEvaluate sQReservationEvaluate = new SQReservationEvaluate() { created_at = DateTime.Now, play_level = evaluate.play_level, reservation_id = evaluate.reservation_id, role = p.role, skills_level = evaluate.skills_level, to_user_id = evaluate.to_user_id, user_id = userId, }; await _sQReservationEvaluateServices.InsertAsync(sQReservationEvaluate); var play_level = _dbBase.Ado.SqlQuerySingle($"select ISNULL(sum(play_level),0) level,count(1) rs_count from SQReservationEvaluate where to_user_id={evaluate.to_user_id} "); var skills_level = _dbBase.Ado.SqlQuerySingle($"select ISNULL(sum(skills_level),0) level,count(1) rs_count from SQReservationEvaluate where to_user_id={evaluate.to_user_id} "); //先加4 play_level.level += 4; if (play_level.rs_count > 0) { if (play_level.rs_count == 1) { play_level.rs_count++; } play_level.level = play_level.level / play_level.rs_count; } //先加4 skills_level.level += 4; if (skills_level.rs_count > 0) { if (skills_level.rs_count == 1) { skills_level.rs_count++; } skills_level.level = skills_level.level / skills_level.rs_count; } if (play_level.rs_count > 0 || skills_level.rs_count > 0) { await _userServices.UpdateAsync(it => new CoreCmsUser { play_level = play_level.level, skills_level = skills_level.level }, it => it.id == evaluate.to_user_id); } return new WebApiDto() { Code = 0, Data = null, Msg = "评价成功" }; } /// /// 获取我的声誉记录 /// /// /// /// [HttpGet] [Authorize] public async Task GetReputationByUser([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20) { var list = await _sQReservationReputationServices.QueryPageAsync(it => it.user_id == _user.ID, it => it.created_at, OrderByType.Desc, pageIndex, pageSize, true); var o = new List(); foreach (var item in list) { var c = new { item.created_at, reputation_value = item.reputation_value.ToString("#.#"), title = item.remark }; o.Add(c); } return new WebApiDto() { Code = 0, Data = o, Msg = "ok", }; } /// /// 获取评价我的记录 /// /// 页码 /// 每页数量 /// [HttpGet] [Authorize] public async Task GetEvaluateToMe([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20) { var userId = _user.ID; var list = await _sQReservationEvaluateServices.QueryPageAsync( it => it.to_user_id == userId, it => it.created_at, OrderByType.Desc, pageIndex, pageSize, true ); return new WebApiDto() { Code = 0, Data = list, Msg = "ok" }; } /// /// 获取可预约的房间列表 /// /// 开始时间 时间戳 /// 结束时间 时间戳 /// [HttpGet] public async Task GetReservationRoomList([FromQuery] long startTime, [FromQuery] long endTime) { if (startTime == 0 || endTime == 0) { return new WebApiDto() { Code = 500, Data = null, Msg = "参数错误" }; } // 时间戳转DateTime var start = DateTimeOffset.FromUnixTimeSeconds(startTime).DateTime; var end = DateTimeOffset.FromUnixTimeSeconds(endTime).DateTime; // 1. 查询所有可用房间 var allRooms = await _SQRoomsServices.GetRoomList(); // 2. 查询有不可用时间段冲突的房间 var unavailableRoomIds = (await _sQRoomUnavailableTimesServices.QueryListByClauseAsync( t => t.start_time < end && t.end_time > start )).Select(t => t.room_id).Distinct().ToList(); // 3. 查询已被预约的房间(未取消的预约,时间有重叠) var reservedRoomIds = (await _SQReservationsServices.QueryListByClauseAsync( r => r.status < 2 && r.start_time < end && r.end_time > start )).Select(r => r.room_id).Distinct().ToList(); // 4. 可预约房间 = 所有可用房间 - 不可用房间 - 已预约房间 var availableRooms = allRooms .Where(r => r.status == true && !unavailableRoomIds.Contains(r.id) && !reservedRoomIds.Contains(r.id)) .OrderBy(r => r.name) .Select(it => new { name = it.name + $" {it.price_per_hour.ToString("#.##")}/小时", it.id, it.capacity }) .ToList(); return new WebApiDto() { Code = 0, Data = availableRooms, Msg = "ok" }; } /// /// 用户预约接口 /// /// /// [HttpPost] [Authorize] public async Task AddSQReservation([FromBody] SQReservationsAddDto dto) { var userId = _user.ID; var start_time = DateTimeOffset.FromUnixTimeSeconds(dto.start_time).DateTime; var end_time = DateTimeOffset.FromUnixTimeSeconds(dto.end_time).DateTime; // 1. 参数校验 if (dto == null || dto.room_id <= 0 || start_time >= end_time) { return new WebApiDto() { Code = 500, Data = null, Msg = "参数错误" }; } // 2. 检查房间是否存在 var room = await _SQRoomsServices.QueryByClauseAsync(r => r.id == dto.room_id, r => r.id, OrderByType.Asc); if (room == null) { return new WebApiDto() { Code = 500, Data = null, Msg = "房间不存在" }; } // 3. 检查房间是否可预约(不可用时间段) var hasUnavailable = await _sQRoomUnavailableTimesServices.QueryListByClauseAsync( t => t.room_id == dto.room_id && t.start_time < end_time && t.end_time > start_time, t => t.id, OrderByType.Asc); if (hasUnavailable != null && hasUnavailable.Count > 0) { return new WebApiDto() { Code = 500, Data = null, Msg = "该时间段房间不可预约" }; } // 4. 检查房间是否已被预约(未取消的预约,时间有重叠) var hasReserved = await _SQReservationsServices.QueryListByClauseAsync( r => r.room_id == dto.room_id && r.status < 2 && r.start_time < end_time && r.end_time > start_time, r => r.id, OrderByType.Asc); if (hasReserved != null && hasReserved.Count > 0) { return new WebApiDto() { Code = 500, Data = null, Msg = "该时间段房间已被预约" }; } // 5. 创建预约记录 var reservation = new SQReservations { room_id = dto.room_id, room_name = room.name, start_time = start_time, end_time = end_time, game_type = dto.game_type, created_at = DateTime.Now, updated_at = DateTime.Now, // 其他字段可根据需要补充 }; var reservationId = await _dbBase.Insertable(reservation).ExecuteReturnIdentityAsync(); if (reservationId <= 0) { return new WebApiDto() { Code = 500, Data = null, Msg = "预约失败" }; } // 6. 创建预约参与人记录(发起者,role=1) var participant = new SQReservationParticipants { reservation_id = reservationId, user_id = userId, join_time = DateTime.Now, role = 1, status = 0, is_refund = dto.deposit_fee > 0 ? 1 : 0, important_data = dto.important_data }; await _SQReservationParticipantsServices.InsertAsync(participant); return new WebApiDto() { Code = 0, Data = new { reservation_id = reservationId }, Msg = "预约成功" }; } /// /// 用户加入预约接口 /// /// 预约 /// [HttpPost] [Authorize] public async Task JoinReservation([FromBody] SQReservationParticipantsAddDto dto) { var userId = _user.ID; var reservationId = dto.ReservationsId; // 1. 校验预约是否存在且未结束 var reservation = await _SQReservationsServices.QueryByClauseAsync( r => r.id == reservationId && r.end_time > DateTime.Now && r.status < 2, r => r.id, OrderByType.Asc); if (reservation == null) { return new WebApiDto { Code = 404, Data = null, Msg = "预约不存在或已结束" }; } // 2. 校验用户是否已加入该预约 var exists = await _SQReservationParticipantsServices.QueryByClauseAsync( p => p.reservation_id == reservationId && p.user_id == userId, p => p.id, OrderByType.Asc); if (exists != null) { return new WebApiDto { Code = 400, Data = null, Msg = "您已加入该预约" }; } // 2.1 校验用户是否有其它预约时间冲突 // 2.1 校验用户是否有其它预约时间冲突(只查未开始或正在进行中的预约) var now = DateTime.Now; var hasConflict = await _SQReservationParticipantsServices.QueryMuchAsync( (p, r) => new object[] { JoinType.Inner, p.reservation_id == r.id }, (p, r) => r.id, (p, r) => p.user_id == userId && p.status == 0 && // 只查未退出 r.status < 2 && // 只查未取消/未结束 r.end_time > now && // 只查未结束 r.start_time < reservation.end_time && r.end_time > reservation.start_time // 时间有重叠 ); if (hasConflict != null && hasConflict.Count > 0) { return new WebApiDto { Code = 402, Data = null, Msg = "您有其它预约时间冲突,无法加入该预约" }; } //// 查询用户所有未结束的预约参与记录 //var userReservations = await _SQReservationParticipantsServices.QueryListByClauseAsync( // p => p.user_id == userId && p.status == 0, // 只查未退出的 // p => p.id, OrderByType.Asc); //if (userReservations != null && userReservations.Count > 0) //{ // // 获取这些预约的ID // var reservationIds = userReservations.Select(p => p.reservation_id).ToList(); // // 查询这些预约的时间段 // var reservations = await _SQReservationsServices.QueryListByClauseAsync( // r => reservationIds.Contains(r.id) && r.status < 2 && r.end_time > DateTime.Now, // r => r.id, OrderByType.Asc); // // 检查时间是否有重叠 // foreach (var r in reservations) // { // if (r.start_time < reservation.end_time && r.end_time > reservation.start_time) // { // return new WebApiDto // { // Code = 402, // Data = null, // Msg = "您有其它预约时间冲突,无法加入该预约" // }; // } // } //} //3.校验预约是否已满(如有容量限制,可补充) var participantsCount = await _SQReservationParticipantsServices.QueryListByClauseAsync( p => p.reservation_id == reservationId, p => p.id, OrderByType.Asc); if (participantsCount.Count >= reservation.player_count) { return new WebApiDto() { Code = 401, Data = null, Msg = "预约已满" }; } // 4. 插入参与人记录 var participant = new SQReservationParticipants { reservation_id = reservationId, user_id = userId, join_time = DateTime.Now, role = 0, // 0为参与者 status = 0, is_refund = reservation.deposit_fee > 0 ? 1 : 0, important_data = dto.important_data }; await _SQReservationParticipantsServices.InsertAsync(participant); return new WebApiDto { Code = 0, Data = null, Msg = "加入预约成功" }; } }