1205 lines
43 KiB
C#
1205 lines
43 KiB
C#
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 = "签到失败"
|
||
};
|
||
}
|
||
}
|
||
|
||
}
|