This commit is contained in:
zpc 2025-09-24 13:15:01 +08:00
parent 927ac3045f
commit c945442160
6 changed files with 156 additions and 99 deletions

View File

@ -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
{
/// <summary>
/// <summary>
/// 预约表 服务工厂接口
/// </summary>
public interface ISQReservationsServices : IBaseServices<SQReservations>
@ -63,7 +65,7 @@ namespace CoreCms.Net.IServices
#endregion
#region ==========================================================
/// <summary>
@ -95,5 +97,21 @@ namespace CoreCms.Net.IServices
Expression<Func<SQReservations, object>> orderByExpression, OrderByType orderByType, int pageIndex = 1,
int pageSize = 20, bool blUseNoLock = false);
#endregion
#region ==========================================================
/// <summary>
/// 组局失败通知(批量入队模板消息)
/// </summary>
/// <param name="reservation">预约</param>
/// <param name="participants">需通知的参与人集合</param>
Task NotifyReservationFailedAsync(SQReservations reservation, IEnumerable<SQReservationParticipants> participants, string tips = "组局人数未满,自动解散!");
/// <summary>
/// 组局成功通知(批量入队模板消息)
/// </summary>
/// <param name="reservation">预约</param>
/// <param name="participants">需通知的参与人集合</param>
Task NotifyReservationSuccessAsync(SQReservations reservation, IEnumerable<SQReservationParticipants> participants);
#endregion
}
}

View File

@ -139,5 +139,11 @@ namespace CoreCms.Net.Model.Entities
[Display(Name = "是否赴约")]
[Required(ErrorMessage = "请输入{0}")]
public System.Int32 is_arrive { get; set; }
/// <summary>
/// 是否评论过
/// </summary>
[Display(Name = "是否评论过")]
public System.Int32 is_evaluation { get; set; }
}
}

View File

@ -16,12 +16,23 @@ namespace CoreCms.Net.Model.ViewModels.SQ
[AutoMap(typeof(SQReservations))]
public class SQReservationsDto : SQReservations
{
public List<SQReservationParticipantsDto> Participants { get; set; }
}
[AutoMap(typeof(SQReservations))]
public class SQReservationsApiDto : SQReservationsBaseDto
{
/// <summary>
/// 所属角色 0 参与者 1 发起者
/// </summary>
public int Role { get; set; }
/// <summary>
/// 是否 赴约 0 默认1赴约2未赴约
/// </summary>
public int is_arrive { get; set; }
}
/// <summary>
///

View File

@ -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 ==========================================================
/// <summary>
/// 获取缓存的所有数据
@ -114,7 +119,7 @@ namespace CoreCms.Net.Services
#endregion
#region
#region
/// <summary>
/// 重写根据条件查询分页数据
/// </summary>
@ -133,5 +138,57 @@ namespace CoreCms.Net.Services
}
#endregion
#region ==========================================================
public async Task NotifyReservationFailedAsync(SQReservations reservation, IEnumerable<SQReservationParticipants> 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<SQReservationParticipants> 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
}
}

View File

@ -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->2start_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->2start_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} 组局成功通知入队完成");
}

View File

@ -107,7 +107,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices
{
var userId = _user.ID;
var list = await _dbBase.Ado.SqlQueryAsync<SQReservationsMyDto>($"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<SQReservationsMyDto>($"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<SQReservationsApiDto>($"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<SQReservationsApiDto>($"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 // 参与者取消
{