Coreshop/CoreCms.Net.Web.WebApi/Controllers/SQController.cs
2025-09-26 16:47:57 +08:00

1205 lines
43 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.Utility.Extensions;
using ToolGood.Words.internals;
using NPOI.SS.Formula.PTG;
using NPOI.OpenXmlFormats.Dml;
using Humanizer;
namespace CoreCms.Net.Web.WebApi.Controllers;
/// <summary>
/// 预约接口
/// </summary>
[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;
/// <summary>
/// 构造函数
///</summary>
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;
}
/// <summary>
/// 我的预约记录
/// </summary>
/// <param name="type">0 参与者1发起者</param>
/// <param name="index">起始页</param>
/// <param name="size">页大小</param>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<WebApiDto> GetMyReservation([FromQuery] int type = 0, [FromQuery] int index = 1, [FromQuery] int size = 10)
{
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 ");
if (list != null && list.Count > 0)
{
var roomList = await _SQRoomsServices.GetRoomList();
// 转为基类列表
var baseList = list.Cast<SQReservationsBaseDto>().ToList();
await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper);
}
return new WebApiDto()
{
Data = list,
Code = 0,
};
}
/// <summary>
/// 获取正在进行的预约
/// </summary>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<WebApiDto> GetMyUseReservation()
{
var userId = _user.ID;
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,2, end_time) > GETDATE() ORDER BY orderid asc, r.start_time Desc ");
if (list != null && list.Count > 0)
{
var roomList = await _SQRoomsServices.GetRoomList();
// 转为基类列表
var baseList = list.Cast<SQReservationsBaseDto>().ToList();
await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper);
}
return new WebApiDto()
{
Data = list,
Code = 0,
};
}
/// <summary>
/// 首页预约列表
/// </summary>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
[HttpGet]
public async Task<WebApiDto> 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<SQReservations>();
where = where.And(it => it.end_time > now);
where = where.And(it => it.status < 3);
var list = await _SQReservationsServices.QueryPageAsync(where, it => it.start_time, OrderByType.Asc, pageIndex, pageSize, true);
var pageList = _mapper.Map<List<SQReservationsApiDto>>(list);
if (pageList != null && pageList.Count > 0)
{
// 转为基类列表
var baseList = pageList.Cast<SQReservationsBaseDto>().ToList();
await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper);
}
return new WebApiDto()
{
Data = pageList,
Code = 0,
Msg = "ok",
};
}
/// <summary>
/// 获取预约评价
/// </summary>
/// <param name="reId"></param>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<WebApiDto> 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<SQReservationParticipantsApiDto>($"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<object> obj = new List<object>();
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
};
}
/// <summary>
/// 评价用户
/// </summary>
/// <param name="evaluate"></param>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> 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<SQReservationParticipantsApiEavDto>($"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<object> obj = new List<object>();
var p = participants.Find(it => it.user_id == evaluate.to_user_id);
if (p == null)
{
return new WebApiDto()
{
Code = 500,
Data = null,
Msg = "未找到对局记录"
};
}
//_sQReservationReputationServices.
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<SQReservationEvaluateFDto>($"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<SQReservationEvaluateFDto>($"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 = "评价成功"
};
}
/// <summary>
/// 获取我的声誉记录
/// </summary>
/// <param name="pageIndex"></param>
/// <param name="pageSize"></param>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<WebApiDto> 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<object>();
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",
};
}
/// <summary>
/// 获取评价我的记录
/// </summary>
/// <param name="pageIndex">页码</param>
/// <param name="pageSize">每页数量</param>
/// <returns></returns>
[HttpGet]
[Authorize]
public async Task<WebApiDto> 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"
};
}
/// <summary>
/// 获取可预约的房间列表
/// </summary>
/// <param name="startTime">开始时间 时间戳</param>
/// <param name="endTime">结束时间 时间戳</param>
/// <returns></returns>
[HttpGet]
public async Task<WebApiDto> 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 < 3 && 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"
};
}
/// <summary>
/// 用户预约接口
/// </summary>
/// <param name="dto"></param>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> AddSQReservation([FromBody] SQReservationsAddDto dto)
{
var userId = _user.ID;
var start_time = DateTimeOffset.FromUnixTimeSeconds(dto.start_time).AddHours(8).DateTime;
var end_time = DateTimeOffset.FromUnixTimeSeconds(dto.end_time).AddHours(8).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 = "该时间段房间不可预约"
};
}
// 2.1 校验用户是否有其它预约时间冲突
// 2.1 校验用户是否有其它预约时间冲突(只查未开始或正在进行中的预约)
var now = DateTime.Now;
var hasConflict = await _SQReservationParticipantsServices.QueryMuchAsync<SQReservationParticipants, SQReservations, int>(
(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 < 3 && // 只查未取消/未结束
r.end_time > now && // 只查未结束
r.start_time < end_time && r.end_time > start_time // 时间有重叠
);
if (hasConflict != null && hasConflict.Count > 0)
{
return new WebApiDto
{
Code = 402,
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,
credit_limit = dto.credit_limit,
player_count = dto.player_count,
deposit_fee = dto.deposit_fee,
duration_minutes = (int)(end_time - start_time).TotalMinutes,
extra_info = dto.extra_info,
game_rule = dto.game_rule,
gender_limit = dto.gender_limit,
is_smoking = dto.is_smoking,
max_age = dto.max_age,
min_age = dto.min_age,
remarks = "",
status = 0,
title = dto.title,
// 其他字段可根据需要补充
};
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 = "预约成功"
};
}
/// <summary>
/// 用户是否可以创建预约(仅校验,不创建)
/// </summary>
/// <param name="dto">创建预约所需参数</param>
/// <returns>返回可否创建及原因</returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> CanCreateSQReservation([FromBody] SQReservationsAddDto dto)
{
var userId = _user.ID;
var start_time = DateTimeOffset.FromUnixTimeSeconds(dto.start_time).AddHours(8).DateTime;
var end_time = DateTimeOffset.FromUnixTimeSeconds(dto.end_time).AddHours(8).DateTime;
// 1. 参数校验
if (dto == null || dto.room_id <= 0 || start_time >= end_time)
{
return new WebApiDto()
{
Code = 500,
Data = new { canCreate = false },
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 = new { canCreate = false },
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 = new { canCreate = false },
Msg = "该时间段房间不可预约"
};
}
// 2.1 校验用户是否有其它预约时间冲突(只查未开始或正在进行中的预约)
var now = DateTime.Now;
var hasConflict = await _SQReservationParticipantsServices.QueryMuchAsync<SQReservationParticipants, SQReservations, int>(
(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 < 3 &&
r.end_time > now &&
r.start_time < end_time && r.end_time > start_time
);
if (hasConflict != null && hasConflict.Count > 0)
{
return new WebApiDto
{
Code = 402,
Data = new { canCreate = false },
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 = new { canCreate = false },
Msg = "该时间段房间已被预约"
};
}
// 全部通过
return new WebApiDto()
{
Code = 0,
Data = new { canCreate = true },
Msg = "ok"
};
}
/// <summary>
/// 用户加入预约接口
/// </summary>
/// <param name="dto">预约</param>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> 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.status == 0,
p => p.id, OrderByType.Asc);
if (exists != null)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = "您已加入该预约"
};
}
var user = _userServices.QueryById(userId);
// 2.0.1 校验用户条件 是否符合要求 如 性别user.sex 1男2女 年龄user.birthday这个是生日 用生日去动态计算年龄) 信用分credit_score
//reservation.credit_limit 最低信誉分 同 用户表的的 信用分
// reservation.gender_limit 0 不限 1男 2 女
// 最大 和最小 年龄 0 不限制 reservation.max_age reservation.min_age
if (user == null)
{
return new WebApiDto
{
Code = 404,
Data = null,
Msg = "用户不存在"
};
}
// 信誉分校验
if (reservation.credit_limit > 0 && user.credit_score < reservation.credit_limit)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = $"您的信誉分不足,最低要求为{reservation.credit_limit}"
};
}
// 性别限制0 不限1 男2 女
if (reservation.gender_limit == 1 || reservation.gender_limit == 2)
{
if (user.sex != reservation.gender_limit)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = "您的性别不符合该预约要求"
};
}
}
// 年龄限制(按生日计算实际年龄)
if (reservation.min_age > 0 || reservation.max_age > 0)
{
if (!user.birthday.HasValue)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = "请先完善生日信息以校验年龄"
};
}
var today = DateTime.Today;
var birth = user.birthday.Value.Date;
var age = today.Year - birth.Year;
if (birth > today.AddYears(-age)) age--;
if (reservation.min_age > 0 && age < reservation.min_age)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = $"年龄小于最小限制:{reservation.min_age}岁"
};
}
if (reservation.max_age > 0 && age > reservation.max_age)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = $"年龄超过最大限制:{reservation.max_age}岁"
};
}
}
// 2.1 校验用户是否有其它预约时间冲突
// 2.1 校验用户是否有其它预约时间冲突(只查未开始或正在进行中的预约)
var now = DateTime.Now;
var hasConflict = await _SQReservationParticipantsServices.QueryMuchAsync<SQReservationParticipants, SQReservations, int>(
(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 < 3 && // 只查未取消/未结束
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.status == 0, 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 = new { reservation_id = reservationId },
Msg = "加入预约成功"
};
}
/// <summary>
/// 取消预约接口
/// </summary>
/// <param name="dto">取消预约参数</param>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> CancelReservation([FromBody] SQReservationCancelDto dto)
{
var userId = _user.ID;
// 1. 参数校验
if (dto == null || dto.reservation_id <= 0)
{
return new WebApiDto()
{
Code = 500,
Data = null,
Msg = "参数错误"
};
}
// 2. 查询预约是否存在
var reservation = await _SQReservationsServices.QueryByClauseAsync(
r => r.id == dto.reservation_id,
r => r.id, OrderByType.Asc);
if (reservation == null)
{
return new WebApiDto()
{
Code = 404,
Data = null,
Msg = "预约不存在"
};
}
if (reservation.start_time.AddMinutes(-30) < DateTime.Now)
{
return new WebApiDto()
{
Code = 400,
Data = null,
Msg = "预约开始前30分钟无法取消"
};
}
if (reservation.status == 1) //
{
return new WebApiDto()
{
Code = 400,
Data = null,
Msg = "该预约已组局成功锁定,无法取消"
};
}
// 3. 检查预约状态是否允许取消
if (reservation.status >= 3) // 3=已结束4=取消
{
return new WebApiDto()
{
Code = 400,
Data = null,
Msg = "该预约已结束或已取消,无法再次取消"
};
}
// 4. 检查用户是否有权限取消该预约
var participant = await _SQReservationParticipantsServices.QueryByClauseAsync(
p => p.reservation_id == dto.reservation_id && p.user_id == userId,
p => p.id, OrderByType.Asc);
if (participant == null)
{
return new WebApiDto()
{
Code = 403,
Data = null,
Msg = "您没有权限取消该预约"
};
}
// 5. 检查是否已经开始(如果已经开始,只有发起者可以取消)
var now = DateTime.Now;
if (reservation.start_time <= now && participant.role != 1)
{
return new WebApiDto()
{
Code = 400,
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
{
status = 1, // 已退出
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 // 参与者取消
{
// 参与者只退出自己
await _SQReservationParticipantsServices.UpdateAsync(
it => new SQReservationParticipants
{
status = 1, // 已退出
quit_time = DateTime.Now
},
it => it.reservation_id == dto.reservation_id && it.user_id == userId);
}
return new WebApiDto()
{
Code = 0,
Data = null,
Msg = "取消预约成功"
};
}
/// <summary>
/// 预约签到(仅发起者可操作,且只能签到一次)
/// </summary>
/// <param name="dto">签到参数:不包含发起者的参会名单</param>
/// <returns></returns>
[HttpPost]
[Authorize]
public async Task<WebApiDto> CheckInReservation([FromBody] SQReservationCheckInDto dto)
{
var userId = _user.ID;
if (dto == null || dto.reservation_id <= 0)
{
return new WebApiDto
{
Code = 500,
Data = null,
Msg = "参数错误"
};
}
// 查询预约
var reservation = await _SQReservationsServices.QueryByClauseAsync(
r => r.id == dto.reservation_id,
r => r.id, OrderByType.Asc);
if (reservation == null)
{
return new WebApiDto
{
Code = 404,
Data = null,
Msg = "预约不存在"
};
}
// 已结束或已取消
if (reservation.status >= 3)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = "预约已结束或已取消,无法签到"
};
}
// 已进行中(已签到),禁止重复
if (reservation.status == 2)
{
return new WebApiDto
{
Code = 400,
Data = null,
Msg = "已签到,无法重复签到"
};
}
// 权限校验:仅发起者可签到
var initiator = await _SQReservationParticipantsServices.QueryByClauseAsync(
p => p.reservation_id == dto.reservation_id && p.user_id == userId && p.role == 1 && p.status == 0,
p => p.id, OrderByType.Asc);
if (initiator == null)
{
return new WebApiDto
{
Code = 403,
Data = null,
Msg = "仅发起者可进行签到"
};
}
dto.attendeds ??= new List<SQReservationCheckInAttendeeDto>();
var falseUserIds = dto.attendeds
.Where(a => a != null && a.isAttended == false)
.Select(a => a.user_id)
.Distinct()
.ToList();
try
{
_dbBase.Ado.BeginTran();
// 1) 预约置为进行中
var updatedReservation = await _SQReservationsServices.UpdateAsync(
it => new SQReservations
{
status = 2,
updated_at = DateTime.Now
},
it => it.id == dto.reservation_id);
if (!updatedReservation)
{
_dbBase.Ado.RollbackTran();
return new WebApiDto
{
Code = 500,
Data = null,
Msg = "签到失败:更新预约状态异常"
};
}
// 2) 默认将所有未退出的参与者标记为已赴约(1)
await _SQReservationParticipantsServices.UpdateAsync(
it => new SQReservationParticipants
{
is_arrive = 1
},
it => it.reservation_id == dto.reservation_id && it.status == 0);
// 3) 对于传入的未出席名单,标记为未赴约(2)
if (falseUserIds.Count > 0)
{
await _SQReservationParticipantsServices.UpdateAsync(
it => new SQReservationParticipants
{
is_arrive = 2
},
it => it.reservation_id == dto.reservation_id && it.status == 0 && falseUserIds.Contains(it.user_id));
//添加鸽子次数
foreach (var user_id in falseUserIds)
{
var user = await _userServices.QueryByIdAsync(user_id);
if (user != null)
{
user.dove_count++;
}
await _userServices.UpdateAsync(user);
}
}
// 4) 确保发起者始终为已赴约(1)
await _SQReservationParticipantsServices.UpdateAsync(
it => new SQReservationParticipants
{
is_arrive = 1
},
it => it.reservation_id == dto.reservation_id && it.status == 0 && it.user_id == userId);
_dbBase.Ado.CommitTran();
return new WebApiDto
{
Code = 0,
Data = null,
Msg = "签到成功"
};
}
catch (Exception)
{
_dbBase.Ado.RollbackTran();
return new WebApiDto
{
Code = 500,
Data = null,
Msg = "签到失败"
};
}
}
}