From c945442160010d9327cd5c1335884f3d8953ce55 Mon Sep 17 00:00:00 2001 From: zpc Date: Wed, 24 Sep 2025 13:15:01 +0800 Subject: [PATCH] 232 --- .../SQ/ISQReservationsServices.cs | 22 ++++- .../Entities/SQ/SQReservationParticipants.cs | 6 ++ .../ViewModels/SQ/SQReservationsDto.cs | 11 +++ .../SQ/SQReservationsServices.cs | 63 ++++++++++++- CoreCms.Net.Task/SQReservationJob.cs | 90 +++++-------------- .../Controllers/SQController.cs | 63 +++++++------ 6 files changed, 156 insertions(+), 99 deletions(-) diff --git a/CoreCms.Net.IServices/SQ/ISQReservationsServices.cs b/CoreCms.Net.IServices/SQ/ISQReservationsServices.cs index 5e296bf..fe8869f 100644 --- a/CoreCms.Net.IServices/SQ/ISQReservationsServices.cs +++ b/CoreCms.Net.IServices/SQ/ISQReservationsServices.cs @@ -12,14 +12,16 @@ using System; using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; + using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.ViewModels.Basics; using CoreCms.Net.Model.ViewModels.UI; + using SqlSugar; namespace CoreCms.Net.IServices { - /// + /// /// 预约表 服务工厂接口 /// public interface ISQReservationsServices : IBaseServices @@ -63,7 +65,7 @@ namespace CoreCms.Net.IServices #endregion - + #region 获取缓存的所有数据========================================================== /// @@ -95,5 +97,21 @@ namespace CoreCms.Net.IServices Expression> orderByExpression, OrderByType orderByType, int pageIndex = 1, int pageSize = 20, bool blUseNoLock = false); #endregion + + #region 预约模板消息通知========================================================== + /// + /// 组局失败通知(批量入队模板消息) + /// + /// 预约 + /// 需通知的参与人集合 + Task NotifyReservationFailedAsync(SQReservations reservation, IEnumerable participants, string tips = "组局人数未满,自动解散!"); + + /// + /// 组局成功通知(批量入队模板消息) + /// + /// 预约 + /// 需通知的参与人集合 + Task NotifyReservationSuccessAsync(SQReservations reservation, IEnumerable participants); + #endregion } } diff --git a/CoreCms.Net.Model/Entities/SQ/SQReservationParticipants.cs b/CoreCms.Net.Model/Entities/SQ/SQReservationParticipants.cs index 75609bd..11b5db6 100644 --- a/CoreCms.Net.Model/Entities/SQ/SQReservationParticipants.cs +++ b/CoreCms.Net.Model/Entities/SQ/SQReservationParticipants.cs @@ -139,5 +139,11 @@ namespace CoreCms.Net.Model.Entities [Display(Name = "是否赴约")] [Required(ErrorMessage = "请输入{0}")] public System.Int32 is_arrive { get; set; } + + /// + /// 是否评论过 + /// + [Display(Name = "是否评论过")] + public System.Int32 is_evaluation { get; set; } } } diff --git a/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs b/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs index 337d9f6..b4c356a 100644 --- a/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs +++ b/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs @@ -16,12 +16,23 @@ namespace CoreCms.Net.Model.ViewModels.SQ [AutoMap(typeof(SQReservations))] public class SQReservationsDto : SQReservations { + public List Participants { get; set; } } [AutoMap(typeof(SQReservations))] public class SQReservationsApiDto : SQReservationsBaseDto { + /// + /// 所属角色 0 参与者 1 发起者 + /// + public int Role { get; set; } + + /// + /// 是否 赴约 0 默认,1赴约,2未赴约 + /// + public int is_arrive { get; set; } + } /// /// diff --git a/CoreCms.Net.Services/SQ/SQReservationsServices.cs b/CoreCms.Net.Services/SQ/SQReservationsServices.cs index aaa46db..3d426f8 100644 --- a/CoreCms.Net.Services/SQ/SQReservationsServices.cs +++ b/CoreCms.Net.Services/SQ/SQReservationsServices.cs @@ -13,12 +13,15 @@ using System.Collections.Generic; using System.Linq.Expressions; using System.Threading.Tasks; using CoreCms.Net.Configuration; +using CoreCms.Net.Caching.AutoMate.RedisCache; 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 Newtonsoft.Json; +using Newtonsoft.Json.Linq; using SqlSugar; @@ -31,12 +34,14 @@ namespace CoreCms.Net.Services { private readonly ISQReservationsRepository _dal; private readonly IUnitOfWork _unitOfWork; + private readonly IRedisOperationRepository _redisOperationRepository; - public SQReservationsServices(IUnitOfWork unitOfWork, ISQReservationsRepository dal) + public SQReservationsServices(IUnitOfWork unitOfWork, ISQReservationsRepository dal, IRedisOperationRepository redisOperationRepository) { this._dal = dal; base.BaseDal = dal; _unitOfWork = unitOfWork; + _redisOperationRepository = redisOperationRepository; } #region 实现重写增删改查操作========================================================== @@ -93,7 +98,7 @@ namespace CoreCms.Net.Services #endregion - #region 获取缓存的所有数据========================================================== + #region 获取缓存的所有数据========================================================== /// /// 获取缓存的所有数据 @@ -114,7 +119,7 @@ namespace CoreCms.Net.Services #endregion - #region 重写根据条件查询分页数据 + #region 重写根据条件查询分页数据 /// /// 重写根据条件查询分页数据 /// @@ -133,5 +138,57 @@ namespace CoreCms.Net.Services } #endregion + #region 预约模板消息通知========================================================== + public async Task NotifyReservationFailedAsync(SQReservations reservation, IEnumerable participants,string tips= "组局人数未满,自动解散!") + { + if (reservation == null || participants == null) + { + return; + } + foreach (var user in participants) + { + var parameters = new JObject(); + parameters.Add("title", reservation.title); + parameters.Add("context", "组局失败!"); + parameters.Add("createTime", reservation.start_time); + parameters.Add("tips", "组局人数未满,自动解散!"); + var @params = new JObject(); + @params.Add("parameters", parameters); + var data = new + { + userId = user.user_id, + code = GlobalEnumVars.WeChatMsgTemplateType.reservation_change.ToString(), + parameters = @params + }; + await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.SendWxTemplateMessage, JsonConvert.SerializeObject(data)); + } + } + + public async Task NotifyReservationSuccessAsync(SQReservations reservation, IEnumerable participants) + { + if (reservation == null || participants == null) + { + return; + } + foreach (var user in participants) + { + var parameters = new JObject(); + parameters.Add("title", reservation.title); + parameters.Add("roomName", reservation.room_name); + parameters.Add("createTime", reservation.start_time); + parameters.Add("tips", "组局成功!"); + var @params = new JObject(); + @params.Add("parameters", parameters); + var data = new + { + userId = user.user_id, + code = GlobalEnumVars.WeChatMsgTemplateType.reservation_success.ToString(), + parameters = @params + }; + await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.SendWxTemplateMessage, JsonConvert.SerializeObject(data)); + } + } + #endregion + } } diff --git a/CoreCms.Net.Task/SQReservationJob.cs b/CoreCms.Net.Task/SQReservationJob.cs index e79664d..4552589 100644 --- a/CoreCms.Net.Task/SQReservationJob.cs +++ b/CoreCms.Net.Task/SQReservationJob.cs @@ -59,25 +59,25 @@ namespace CoreCms.Net.Task Console.WriteLine($"[SQReservationJob] 步骤1:批量更新记录数 = {changedCount}"); await _reservationsServices.UpdateAsync(endedList); } - Console.WriteLine("[SQReservationJob] 步骤2:将开始时间已到且未结束的预约置为进行中(2)"); - // 2) 将开始时间已到且未结束的预约置为进行中(2) - var startedList = await _reservationsServices.QueryListByClauseAsync( - r => r.status == 1 && r.start_time <= now && r.end_time > now, - r => r.id, OrderByType.Asc); - Console.WriteLine($"[SQReservationJob] 步骤2:查询到待置为进行中记录数量 = {startedList?.Count ?? 0}"); - if (startedList != null && startedList.Count > 0) - { - var changedCount = 0; - foreach (var item in startedList) - { - Console.WriteLine($"[SQReservationJob] 步骤2:预约ID={item.id} 从状态1->2,start_time={item.start_time:yyyy-MM-dd HH:mm:ss} end_time={item.end_time:yyyy-MM-dd HH:mm:ss}"); - item.status = 2; - item.updated_at = now; - changedCount++; - } - Console.WriteLine($"[SQReservationJob] 步骤2:批量更新记录数 = {changedCount}"); - await _reservationsServices.UpdateAsync(startedList); - } + //Console.WriteLine("[SQReservationJob] 步骤2:将开始时间已到且未结束的预约置为进行中(2)"); + //// 2) 将开始时间已到且未结束的预约置为进行中(2) + //var startedList = await _reservationsServices.QueryListByClauseAsync( + // r => r.status == 1 && r.start_time <= now && r.end_time > now, + // r => r.id, OrderByType.Asc); + //Console.WriteLine($"[SQReservationJob] 步骤2:查询到待置为进行中记录数量 = {startedList?.Count ?? 0}"); + //if (startedList != null && startedList.Count > 0) + //{ + // var changedCount = 0; + // foreach (var item in startedList) + // { + // Console.WriteLine($"[SQReservationJob] 步骤2:预约ID={item.id} 从状态1->2,start_time={item.start_time:yyyy-MM-dd HH:mm:ss} end_time={item.end_time:yyyy-MM-dd HH:mm:ss}"); + // item.status = 2; + // item.updated_at = now; + // changedCount++; + // } + // Console.WriteLine($"[SQReservationJob] 步骤2:批量更新记录数 = {changedCount}"); + // await _reservationsServices.UpdateAsync(startedList); + //} // 2.5) 到达开始时间但人数未满的预约置为取消(4) @@ -112,35 +112,10 @@ namespace CoreCms.Net.Task Console.WriteLine($"[SQReservationJob] 步骤2.5:准备通知预约ID={item.id} 的参与用户"); var userList = await _participantsServices.QueryListByClauseAsync(p => p.reservation_id == item.id && p.status == 0); Console.WriteLine($"[SQReservationJob] 步骤2.5:预约ID={item.id} 需通知用户数量 = {userList.Count}"); - var pushed = 0; - foreach (var user in userList) - { - JObject parameters = new JObject(); - parameters.Add("title", item.title); - parameters.Add("context", $"组局失败!"); - parameters.Add("createTime", item.start_time); - parameters.Add("tips", $"组局人数未满,自动解散!"); - var @params = new JObject(); - @params.Add("parameters", parameters); - var data = new - { - userId = user.user_id, - code = "reservation_change", - parameters = @params - }; - await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.SendWxTemplateMessage, JsonConvert.SerializeObject(data)); - pushed++; - Console.WriteLine($"[SQReservationJob] 步骤2.5:已入队通知 -> reservation_change, user_id={user.user_id}"); - } - Console.WriteLine($"[SQReservationJob] 步骤2.5:预约ID={item.id} 通知入队完成,总计 {pushed} 条"); - - + await _reservationsServices.NotifyReservationFailedAsync(item, userList); + Console.WriteLine($"[SQReservationJob] 步骤2.5:预约ID={item.id} 组局失败通知入队完成"); } - } - - - } // 3) 开始前30分钟内,人数已凑齐则置为锁定(1) @@ -176,27 +151,8 @@ namespace CoreCms.Net.Task Console.WriteLine($"[SQReservationJob] 步骤3:准备通知预约ID={item.id} 的参与用户"); var userList = await _participantsServices.QueryListByClauseAsync(p => p.reservation_id == item.id && p.status == 0); Console.WriteLine($"[SQReservationJob] 步骤3:预约ID={item.id} 需通知用户数量 = {userList.Count}"); - var pushed = 0; - foreach (var user in userList) - { - JObject parameters = new JObject(); - parameters.Add("title", item.title); - parameters.Add("roomName", item.room_name); - parameters.Add("createTime", item.start_time); - parameters.Add("tips", $"组局成功!"); - var @params = new JObject(); - @params.Add("parameters", parameters); - var data = new - { - userId = user.user_id, - code = "reservation_success", - parameters = @params - }; - await _redisOperationRepository.ListLeftPushAsync(RedisMessageQueueKey.SendWxTemplateMessage, JsonConvert.SerializeObject(data)); - pushed++; - Console.WriteLine($"[SQReservationJob] 步骤3:已入队通知 -> reservation_success, user_id={user.user_id}"); - } - Console.WriteLine($"[SQReservationJob] 步骤3:预约ID={item.id} 通知入队完成,总计 {pushed} 条"); + await _reservationsServices.NotifyReservationSuccessAsync(item, userList); + Console.WriteLine($"[SQReservationJob] 步骤3:预约ID={item.id} 组局成功通知入队完成"); } diff --git a/CoreCms.Net.Web.WebApi/Controllers/SQController.cs b/CoreCms.Net.Web.WebApi/Controllers/SQController.cs index f90308e..302c841 100644 --- a/CoreCms.Net.Web.WebApi/Controllers/SQController.cs +++ b/CoreCms.Net.Web.WebApi/Controllers/SQController.cs @@ -107,7 +107,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices { 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"); + 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(); @@ -132,7 +132,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices { 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 "); + var list = await _dbBase.Ado.SqlQueryAsync($"SELECT r.*, p.role AS Role, p.is_arrive, CASE WHEN r.status = 1 THEN 0 WHEN r.status = 2 THEN 1 WHEN r.status = 0 THEN 2 WHEN r.status = 3 THEN 3 END AS orderid FROM SQReservations r LEFT JOIN SQReservationParticipants p ON r.id = p.reservation_id WHERE r.status < 4 AND p.user_id = {userId} AND p.status = 0 AND DATEADD(day, 5, end_time) > GETDATE() ORDER BY orderid asc, r.start_time ASC "); if (list != null && list.Count > 0) { var roomList = await _SQRoomsServices.GetRoomList(); @@ -289,6 +289,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices Msg = "未找到对局记录" }; } + //_sQReservationReputationServices. SQReservationEvaluate sQReservationEvaluate = new SQReservationEvaluate() { created_at = DateTime.Now, @@ -557,7 +558,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices credit_limit = dto.credit_limit, player_count = dto.player_count, deposit_fee = dto.deposit_fee, - duration_minutes = dto.duration_minutes, + duration_minutes = (int)(end_time - start_time).TotalMinutes, extra_info = dto.extra_info, game_rule = dto.game_rule, gender_limit = dto.gender_limit, @@ -567,6 +568,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices remarks = "", status = 0, title = dto.title, + // 其他字段可根据需要补充 }; var reservationId = await _dbBase.Insertable(reservation).ExecuteReturnIdentityAsync(); @@ -628,7 +630,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices // 2. 校验用户是否已加入该预约 var exists = await _SQReservationParticipantsServices.QueryByClauseAsync( - p => p.reservation_id == reservationId && p.user_id == userId, + p => p.reservation_id == reservationId && p.user_id == userId && p.status == 0, p => p.id, OrderByType.Asc); if (exists != null) { @@ -697,7 +699,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices //3.校验预约是否已满(如有容量限制,可补充) var participantsCount = await _SQReservationParticipantsServices.QueryListByClauseAsync( - p => p.reservation_id == reservationId, p => p.id, OrderByType.Asc); + p => p.reservation_id == reservationId && p.status == 0, p => p.id, OrderByType.Asc); if (participantsCount.Count >= reservation.player_count) { return new WebApiDto() @@ -764,7 +766,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices Msg = "预约不存在" }; } - if (reservation.start_time.AddMinutes(-30) > DateTime.Now) + if (reservation.start_time.AddMinutes(-30) < DateTime.Now) { return new WebApiDto() { @@ -819,30 +821,31 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices }; } - // 6. 更新预约状态为4(用户取消) - var updateResult = await _SQReservationsServices.UpdateAsync( - it => new SQReservations - { - status = 4, // 用户取消 - updated_at = DateTime.Now, - remarks = string.IsNullOrEmpty(dto.cancel_reason) ? "未支付鸽子费" : dto.cancel_reason - }, - it => it.id == dto.reservation_id); - - if (!updateResult) - { - return new WebApiDto() - { - Code = 500, - Data = null, - Msg = "取消预约失败" - }; - } - // 7. 更新参与人状态为已退出(如果是发起者取消整个预约,所有参与人都标记为退出) if (participant.role == 1) // 发起者取消 { - // 发起者取消整个预约,所有参与人都标记为退出 + + // 7.1.如果是发起者取消,则当前对局全部取消 + var updateResult = await _SQReservationsServices.UpdateAsync( + it => new SQReservations + { + status = 4, // 用户取消 + updated_at = DateTime.Now, + remarks = string.IsNullOrEmpty(dto.cancel_reason) ? "未支付鸽子费" : dto.cancel_reason + }, + it => it.id == dto.reservation_id); + + if (!updateResult) + { + return new WebApiDto() + { + Code = 500, + Data = null, + Msg = "取消预约失败" + }; + } + + // 7.2发起者取消整个预约,所有参与人都标记为退出 await _SQReservationParticipantsServices.UpdateAsync( it => new SQReservationParticipants { @@ -850,6 +853,12 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices quit_time = DateTime.Now }, it => it.reservation_id == dto.reservation_id); + //判断是否有参与者 + var list = await _SQReservationParticipantsServices.QueryListByClauseAsync(it => it.reservation_id == dto.reservation_id && it.role == 0 && it.status == 0); + if (list.Count > 0) + { + await _SQReservationsServices.NotifyReservationFailedAsync(reservation, list, "发起者解散组局!"); + } } else // 参与者取消 {