diff --git a/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs b/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs index b4c356a..664f54d 100644 --- a/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs +++ b/CoreCms.Net.Model/ViewModels/SQ/SQReservationsDto.cs @@ -175,4 +175,28 @@ namespace CoreCms.Net.Model.ViewModels.SQ public string cancel_reason { get; set; } } + /// + /// 签到参与人项(不包含发起者) + /// + public class SQReservationCheckInAttendeeDto + { + /// + /// 用户ID + /// + public int user_id { get; set; } + /// + /// 是否出席(true=赴约,false=未赴约) + /// + public bool isAttended { get; set; } + } + + /// + /// 预约签到 DTO(仅发起者可调用) + /// + public class SQReservationCheckInDto + { + [Required(ErrorMessage = "请输入预约ID")] + public int reservation_id { get; set; } + public List attendeds { get; set; } + } } diff --git a/CoreCms.Net.Web.WebApi/Controllers/SQController.cs b/CoreCms.Net.Web.WebApi/Controllers/SQController.cs index 302c841..93db754 100644 --- a/CoreCms.Net.Web.WebApi/Controllers/SQController.cs +++ b/CoreCms.Net.Web.WebApi/Controllers/SQController.cs @@ -66,15 +66,9 @@ public class SQController : ControllerBase , IHttpContextUser user , IUnitOfWork unitOfWork , ICoreCmsUserBlacklistServices coreCmsUserBlacklistServices - , -ISQReservationEvaluateServices sQReservationEvaluateServices - , -ISQReservationReputationServices sQReservationReputationServices - , -ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices - - - + , ISQReservationEvaluateServices sQReservationEvaluateServices + , ISQReservationReputationServices sQReservationReputationServices + , ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices ) { _webHostEnvironment = webHostEnvironment; @@ -132,7 +126,7 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices { var userId = _user.ID; - 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 "); + 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,2, end_time) > GETDATE() ORDER BY orderid asc, r.start_time ASC "); if (list != null && list.Count > 0) { var roomList = await _SQRoomsServices.GetRoomList(); @@ -880,4 +874,150 @@ ISQRoomUnavailableTimesServices sQRoomUnavailableTimesServices }; } + /// + /// 预约签到(仅发起者可操作,且只能签到一次) + /// + /// 签到参数:不包含发起者的参会名单 + /// + [HttpPost] + [Authorize] + public async Task 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(); + 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)); + } + + // 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 = "签到失败" + }; + } + } + } diff --git a/CoreCms.Net.Web.WebApi/Doc.xml b/CoreCms.Net.Web.WebApi/Doc.xml index 5dcb3b7..af29694 100644 --- a/CoreCms.Net.Web.WebApi/Doc.xml +++ b/CoreCms.Net.Web.WebApi/Doc.xml @@ -849,6 +849,13 @@ 取消预约参数 + + + 预约签到(仅发起者可操作,且只能签到一次) + + 签到参数:不包含发起者的参会名单 + + 门店调用接口数据