2174 lines
73 KiB
C#
2174 lines
73 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;
|
||
using Newtonsoft.Json;
|
||
using CoreCms.Net.Configuration;
|
||
using CoreCms.Net.Utility.Helper;
|
||
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;
|
||
private readonly ISQRoomPricingServices _sQRoomPricingServices;
|
||
private readonly ISQMessageServices _sQMessageServices;
|
||
private readonly ISQEarningsServices _sQEarningsServices;
|
||
private readonly ICoreCmsSettingServices _settingServices;
|
||
|
||
// 营业时间常量配置
|
||
private const string BUSINESS_OPEN_TIME = "09:00";
|
||
private const string BUSINESS_CLOSE_TIME = "23:00";
|
||
|
||
/// <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
|
||
, ISQRoomPricingServices sQRoomPricingServices
|
||
, ISQMessageServices sQMessageServices
|
||
, ISQEarningsServices sQEarningsServices
|
||
, ICoreCmsSettingServices settingServices
|
||
)
|
||
{
|
||
_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;
|
||
_sQRoomPricingServices = sQRoomPricingServices;
|
||
_sQMessageServices = sQMessageServices;
|
||
_sQEarningsServices = sQEarningsServices;
|
||
_settingServices = settingServices;
|
||
}
|
||
|
||
|
||
/// <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()
|
||
AND NOT EXISTS (
|
||
SELECT 1 FROM SQReservationEvaluate e
|
||
WHERE e.reservation_id = r.id AND e.user_id = {userId}
|
||
)
|
||
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);
|
||
//
|
||
List<int> userBlacklist = new List<int>();
|
||
if (userId > 0)
|
||
{
|
||
//_sQRoomUnavailableTimesServices.get
|
||
userBlacklist = await _coreCmsUserBlacklistServices.GetUserBlacklists(userId);
|
||
if (userBlacklist.Count > 0)
|
||
{
|
||
string sqlWhere = string.Join(",", userBlacklist);
|
||
var participants = await _dbBase.Ado.SqlQueryAsync<int>($"select sq.id from SQReservations sq left join SQReservationParticipants p on sq.id=p.reservation_id and p.role=1 where sq.status<3 and p.user_id in ({sqlWhere})");
|
||
if (participants.Count > 0)
|
||
{
|
||
where = where.And(it => !participants.Contains(it.id));
|
||
}
|
||
|
||
}
|
||
}
|
||
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>
|
||
/// 根据预约ID获取详情(结构同首页预约列表单项)
|
||
/// </summary>
|
||
/// <param name="id">预约ID</param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<WebApiDto> GetReservationDetail([FromQuery] int id)
|
||
{
|
||
var userId = _user.ID;
|
||
var model = await _SQReservationsServices.QueryByIdAsync(id);
|
||
if (model == null)
|
||
{
|
||
return new WebApiDto
|
||
{
|
||
Code = -1,
|
||
Msg = "预约不存在",
|
||
};
|
||
}
|
||
|
||
var dto = _mapper.Map<SQReservationsApiDto>(model);
|
||
var roomList = await _SQRoomsServices.GetRoomList();
|
||
var baseList = new List<SQReservationsBaseDto> { dto };
|
||
await baseList.LoadSQReservationParticipantsApiDto(userId, _dbBase, _coreCmsUserBlacklistServices, roomList, _mapper);
|
||
|
||
return new WebApiDto
|
||
{
|
||
Data = dto,
|
||
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;
|
||
if (dto?.LatestDateTime > 0)
|
||
{
|
||
dto.latest_arrival_time = DateTimeOffset.FromUnixTimeSeconds(dto.LatestDateTime ?? 0).AddHours(8).DateTime;
|
||
}
|
||
|
||
// 1. 参数校验
|
||
if (dto == null || dto.room_id <= 0 || start_time >= end_time)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "参数错误"
|
||
};
|
||
}
|
||
|
||
// 1.1 验证预约时长(最短1小时,最长12小时)
|
||
var duration = (end_time - start_time).TotalHours;
|
||
if (duration < 1)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "预约时长不能少于1小时"
|
||
};
|
||
}
|
||
if (duration > 12)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "预约时长不能超过12小时"
|
||
};
|
||
}
|
||
|
||
// 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 = "该时间段房间已被预约"
|
||
};
|
||
}
|
||
string paymentId = "";
|
||
if (dto.deposit_fee > 0)
|
||
{
|
||
var imdata = JsonConvert.DeserializeObject<Dictionary<string, object>>(dto.important_data);
|
||
if (imdata == null || !imdata.ContainsKey("paymentId") || string.IsNullOrEmpty(imdata["paymentId"].ToString()))
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "押金支付信息错误!"
|
||
};
|
||
}
|
||
//订单编号
|
||
paymentId = imdata["paymentId"].ToString();
|
||
if (string.IsNullOrEmpty(paymentId))
|
||
{
|
||
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,
|
||
latest_arrival_time = dto.latest_arrival_time,
|
||
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,
|
||
is_solo_mode = dto.player_count == 1,
|
||
|
||
// 其他字段可根据需要补充
|
||
};
|
||
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,
|
||
paymentId = paymentId,
|
||
};
|
||
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 = "参数错误"
|
||
};
|
||
}
|
||
|
||
// 1.1 验证预约时长(最短1小时,最长12小时)
|
||
var duration = (end_time - start_time).TotalHours;
|
||
if (duration < 1)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = new { canCreate = false },
|
||
Msg = "预约时长不能少于1小时"
|
||
};
|
||
}
|
||
if (duration > 12)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = new { canCreate = false },
|
||
Msg = "预约时长不能超过12小时"
|
||
};
|
||
}
|
||
|
||
// 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 = "您已加入该预约"
|
||
};
|
||
}
|
||
|
||
// 2.0.2 校验是否为"无需组局"模式
|
||
if (reservation.is_solo_mode)
|
||
{
|
||
return new WebApiDto
|
||
{
|
||
Code = 403,
|
||
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 = "预约已满"
|
||
};
|
||
}
|
||
string paymentId = "";
|
||
if (reservation.deposit_fee > 0)
|
||
{
|
||
var imdata = JsonConvert.DeserializeObject<Dictionary<string, object>>(dto.important_data);
|
||
if (imdata == null || !imdata.ContainsKey("paymentId") || string.IsNullOrEmpty(imdata["paymentId"].ToString()))
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "押金支付信息错误!"
|
||
};
|
||
}
|
||
//订单编号
|
||
paymentId = imdata["paymentId"].ToString();
|
||
}
|
||
// 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,
|
||
paymentId = paymentId,
|
||
};
|
||
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 有押金时,已支付押金(is_refund=2)的参与者为发起退款(3)
|
||
if (reservation.deposit_fee.HasValue && reservation.deposit_fee.Value > 0)
|
||
{
|
||
await _SQReservationParticipantsServices.UpdateAsync(
|
||
it => new SQReservationParticipants
|
||
{
|
||
is_refund = 3
|
||
},
|
||
it => it.reservation_id == dto.reservation_id && it.status == 0 && it.is_refund == 2 && it.paymentId != null && it.paymentId != "");
|
||
}
|
||
|
||
// 7.3发起者取消整个预约,所有参与人都标记为退出
|
||
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);
|
||
// 有押金且已支付押金时,标记该参与者为发起退款(3)
|
||
if (reservation.deposit_fee.HasValue && reservation.deposit_fee.Value > 0)
|
||
{
|
||
await _SQReservationParticipantsServices.UpdateAsync(
|
||
it => new SQReservationParticipants
|
||
{
|
||
is_refund = 3
|
||
},
|
||
it => it.reservation_id == dto.reservation_id && it.user_id == userId && it.is_refund == 2 && it.paymentId != null && it.paymentId != "");
|
||
}
|
||
}
|
||
|
||
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();
|
||
var qiandaoUserIds = dto.attendeds
|
||
.Where(a => a != null && a.isAttended)
|
||
.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,
|
||
status = 1
|
||
},
|
||
it => it.reservation_id == dto.reservation_id && it.status == 0 && falseUserIds.Contains(it.user_id));
|
||
//如果有鸽子费,需要将鸽子费平分到 已到的用户,添加到收益中
|
||
|
||
//_sQReservationReputationServices.
|
||
//AddReputationAsync(falseUserIds, -5, $"未按时赴约,扣除5点信誉分(预约ID:{dto.reservation_id})");
|
||
//添加鸽子次数
|
||
foreach (var user_id in falseUserIds)
|
||
{
|
||
var user = await _userServices.QueryByIdAsync(user_id);
|
||
if (user != null)
|
||
{
|
||
//扣除信誉分
|
||
await _sQReservationReputationServices.InsertAsync(new SQReservationReputation()
|
||
{
|
||
created_at = DateTime.Now,
|
||
remark = $"{reservation.title}对局未签到",
|
||
reputation_value = (decimal)-0.5,
|
||
reservation_id = dto.reservation_id,
|
||
updated_at = DateTime.Now,
|
||
user_id = user_id
|
||
});
|
||
user.dove_count++;
|
||
if (user.credit_score > 0)
|
||
{
|
||
user.credit_score = (user.credit_score - (decimal)0.5);
|
||
}
|
||
if (user.credit_score <= 0)
|
||
{
|
||
user.credit_score = 0;
|
||
}
|
||
}
|
||
await _userServices.UpdateAsync(user);
|
||
}
|
||
}
|
||
|
||
//确保发起者始终为已赴约(1)
|
||
if (!qiandaoUserIds.Contains(userId))
|
||
{
|
||
qiandaoUserIds.Add(userId);
|
||
}
|
||
if (qiandaoUserIds.Count > 0)
|
||
{
|
||
|
||
foreach (var user_id in qiandaoUserIds)
|
||
{
|
||
var user = await _userServices.QueryByIdAsync(user_id);
|
||
if (user != null)
|
||
{
|
||
|
||
user.dove_count++;
|
||
if (user.credit_score < 5)
|
||
{
|
||
user.credit_score = (user.credit_score + (decimal)0.2);
|
||
if (user.credit_score > 5)
|
||
{
|
||
user.credit_score = 5;
|
||
}
|
||
//增加信记录
|
||
await _sQReservationReputationServices.InsertAsync(new SQReservationReputation()
|
||
{
|
||
created_at = DateTime.Now,
|
||
remark = $"{reservation.title} 完成组局",
|
||
reputation_value = (decimal)0.2,
|
||
reservation_id = dto.reservation_id,
|
||
updated_at = DateTime.Now,
|
||
user_id = user_id
|
||
});
|
||
await _userServices.UpdateAsync(user);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// 4) 确保发起者始终为已赴约(1)
|
||
await _SQReservationParticipantsServices.UpdateAsync(
|
||
it => new SQReservationParticipants
|
||
{
|
||
is_arrive = 1,
|
||
check_reservation = DateTime.Now
|
||
},
|
||
it => it.reservation_id == dto.reservation_id && it.status == 0 && it.user_id == userId);
|
||
|
||
if (reservation.deposit_fee > 0)
|
||
{
|
||
// 有押金,标记到场人员为“发起退款(3)”,由定时任务统一处理实际退款
|
||
await _SQReservationParticipantsServices.UpdateAsync(
|
||
it => new SQReservationParticipants
|
||
{
|
||
is_refund = 3
|
||
},
|
||
it => it.reservation_id == dto.reservation_id && it.status == 0 && it.is_arrive == 1 && it.is_refund == 2 && it.paymentId != null && it.paymentId != "");
|
||
}
|
||
_dbBase.Ado.CommitTran();
|
||
|
||
return new WebApiDto
|
||
{
|
||
Code = 0,
|
||
Data = null,
|
||
Msg = "签到成功"
|
||
};
|
||
}
|
||
catch (Exception)
|
||
{
|
||
_dbBase.Ado.RollbackTran();
|
||
return new WebApiDto
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "签到失败"
|
||
};
|
||
}
|
||
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 订单支付记录(分页)
|
||
/// </summary>
|
||
[HttpGet]
|
||
[Authorize]
|
||
public async Task<WebApiDto> GetPaymentRecords([FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20)
|
||
{
|
||
var userId = _user.ID;
|
||
if (pageIndex < 1) pageIndex = 1;
|
||
if (pageSize <= 0) pageSize = 20;
|
||
|
||
var sql = $@"SELECT sq.title, p.paymentId, p.is_refund, p.join_time, p.status,
|
||
CASE p.is_refund WHEN 1 THEN N'待支付' WHEN 2 THEN N'已支付' WHEN 3 THEN N'待退款' WHEN 4 THEN N'已退款' ELSE N'退款异常' END AS is_refund_text
|
||
FROM SQReservationParticipants p
|
||
LEFT JOIN SQReservations sq ON p.reservation_id = sq.id
|
||
WHERE p.user_id = {userId} AND p.is_refund > 0 AND p.paymentId IS NOT NULL AND p.paymentId <> ''
|
||
ORDER BY p.id DESC
|
||
OFFSET {(pageIndex - 1) * pageSize} ROWS FETCH NEXT {pageSize} ROWS ONLY";
|
||
|
||
var list = await _dbBase.Ado.SqlQueryAsync<SQPaymentRecordDto>(sql);
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = 0,
|
||
Data = list,
|
||
Msg = "ok"
|
||
};
|
||
}
|
||
|
||
#region 预约房间页面相关接口
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// 获取房间详情
|
||
/// </summary>
|
||
/// <param name="roomId">房间ID</param>
|
||
/// <param name="date">查询日期(Unix时间戳-秒级),默认今天</param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<WebApiDto> GetRoomDetail([FromQuery] int roomId, [FromQuery] long date = 0)
|
||
{
|
||
try
|
||
{
|
||
if (roomId <= 0)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "参数错误:房间ID无效"
|
||
};
|
||
}
|
||
var queryDate = DateTime.Now;
|
||
if (date > 0)
|
||
{
|
||
|
||
|
||
// 反序列化时明确作为 UTC 时间戳处理
|
||
var targetDate = DateTimeOffset.FromUnixTimeSeconds(date).UtcDateTime;
|
||
|
||
// 或者如果需要北京时间
|
||
var chinaTz = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
|
||
queryDate = TimeZoneInfo.ConvertTimeFromUtc(targetDate, chinaTz);
|
||
}
|
||
|
||
|
||
// 调用Service层方法
|
||
var result = await _SQRoomsServices.GetRoomDetailAsync(roomId, queryDate);
|
||
|
||
if (result == null)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 404,
|
||
Data = null,
|
||
Msg = "房间不存在"
|
||
};
|
||
}
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = 0,
|
||
Data = result,
|
||
Msg = "ok"
|
||
};
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = $"查询失败:{ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 按时段预约相关接口
|
||
|
||
/// <summary>
|
||
/// 获取未来7天日期列表
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<WebApiDto> GetAvailableDates()
|
||
{
|
||
var dates = new List<SQAvailableDateDto>();
|
||
var today = DateTime.Today;
|
||
// 明确指定使用中国时区
|
||
var chinaTimeZone = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
|
||
for (int i = 0; i < 7; i++) // 今天+未来6天
|
||
{
|
||
var date = today.AddDays(i);
|
||
|
||
var weekDay = date.ToString("dddd", new System.Globalization.CultureInfo("zh-CN"));
|
||
var dateText = i == 0 ? "今天" : i == 1 ? "明天" : i == 2 ? "后天" : date.ToString("ddd", new System.Globalization.CultureInfo("zh-CN"));
|
||
// 转换为 DateTimeOffset 并指定为北京时间
|
||
var beijingOffset = new DateTimeOffset(date, chinaTimeZone.GetUtcOffset(date));
|
||
dates.Add(new SQAvailableDateDto
|
||
{
|
||
date = (beijingOffset).ToUnixTimeSeconds(),
|
||
dateText = dateText,
|
||
dateDisplay = $"{date.ToString("MM月dd")}"
|
||
});
|
||
}
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = 0,
|
||
Data = dates,
|
||
Msg = "ok"
|
||
};
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取房间列表及时段状态(新版)
|
||
/// </summary>
|
||
/// <param name="date">查询日期(Unix时间戳-秒级)</param>
|
||
/// <param name="showOnlyAvailable">是否只显示当前时段可用的房间</param>
|
||
/// <param name="currentTimeSlot">当前时段类型(配合showOnlyAvailable使用)</param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<WebApiDto> GetRoomListWithSlotsNew([FromQuery] long date, [FromQuery] bool showOnlyAvailable = false, [FromQuery] int? currentTimeSlot = null)
|
||
{
|
||
try
|
||
{
|
||
if (date == 0)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = "参数错误:请提供日期"
|
||
};
|
||
}
|
||
// 反序列化时明确作为 UTC 时间戳处理
|
||
var targetDate = DateTimeOffset.FromUnixTimeSeconds(date).UtcDateTime;
|
||
|
||
// 或者如果需要北京时间
|
||
var chinaTz = TimeZoneInfo.FindSystemTimeZoneById("China Standard Time");
|
||
var beijingDate = TimeZoneInfo.ConvertTimeFromUtc(targetDate, chinaTz);
|
||
|
||
|
||
// 调用Service层方法
|
||
var result = await _SQRoomsServices.GetRoomListWithSlotsAsync(beijingDate, showOnlyAvailable, currentTimeSlot);
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = 0,
|
||
Data = result,
|
||
Msg = "ok"
|
||
};
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = null,
|
||
Msg = $"查询失败:{ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 校验是否可以创建预约(新版,按时段)
|
||
/// </summary>
|
||
/// <param name="dto">创建预约DTO</param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
[Authorize]
|
||
public async Task<WebApiDto> ValidateReservationBySlot([FromBody] SQReservationsAddBySlotDto dto)
|
||
{
|
||
var userId = _user.ID;
|
||
|
||
try
|
||
{
|
||
var (canCreate, reason) = await _SQReservationsServices.ValidateReservationBySlotAsync(dto, userId);
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = canCreate ? 0 : 500,
|
||
Data = new { canCreate, reason },
|
||
Msg = reason
|
||
};
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
return new WebApiDto()
|
||
{
|
||
Code = 500,
|
||
Data = new { canCreate = false, reason = ex.Message },
|
||
Msg = $"校验失败:{ex.Message}"
|
||
};
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取营业时间配置(已存在,保持不变)
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<WebApiDto> GetBusinessHours()
|
||
{
|
||
|
||
var businessHours = new SQBusinessHoursDto
|
||
{
|
||
open_time = BUSINESS_OPEN_TIME,
|
||
close_time = BUSINESS_CLOSE_TIME,
|
||
is_24_hours = false,
|
||
description = $"早{BUSINESS_OPEN_TIME.Split(':')[0]}点 至 晚{BUSINESS_CLOSE_TIME.Split(':')[0]}点"
|
||
};
|
||
|
||
return new WebApiDto()
|
||
{
|
||
Code = 0,
|
||
Data = businessHours,
|
||
Msg = "ok"
|
||
};
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region 私有辅助方法
|
||
|
||
/// <summary>
|
||
/// 计算房间时段占用情况
|
||
/// </summary>
|
||
/// <param name="reservations">预约列表</param>
|
||
/// <param name="dayStart">查询日期开始</param>
|
||
/// <param name="dayEnd">查询日期结束</param>
|
||
/// <returns></returns>
|
||
private SQRoomTimeSlotsDto CalculateTimeSlots(List<SQReservations> reservations, DateTime dayStart, DateTime dayEnd)
|
||
{
|
||
var timeSlots = new SQRoomTimeSlotsDto
|
||
{
|
||
dawn = new SQRoomTimeSlotDto(),
|
||
morning = new SQRoomTimeSlotDto(),
|
||
afternoon = new SQRoomTimeSlotDto(),
|
||
evening = new SQRoomTimeSlotDto()
|
||
};
|
||
|
||
if (reservations == null || reservations.Count == 0)
|
||
{
|
||
return timeSlots;
|
||
}
|
||
|
||
// 定义时段范围
|
||
var dawnStart = dayStart.AddHours(0);
|
||
var dawnEnd = dayStart.AddHours(6);
|
||
var morningStart = dayStart.AddHours(6);
|
||
var morningEnd = dayStart.AddHours(12);
|
||
var afternoonStart = dayStart.AddHours(12);
|
||
var afternoonEnd = dayStart.AddHours(18);
|
||
var eveningStart = dayStart.AddHours(18);
|
||
var eveningEnd = dayStart.AddHours(24);
|
||
|
||
foreach (var reservation in reservations)
|
||
{
|
||
// 检查凌晨时段
|
||
if (reservation.start_time < dawnEnd && reservation.end_time > dawnStart)
|
||
{
|
||
timeSlots.dawn.is_occupied = true;
|
||
timeSlots.dawn.reservations.Add(new SQRoomTimeSlotReservationDto
|
||
{
|
||
start_time = reservation.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
end_time = reservation.end_time.ToString("yyyy-MM-dd HH:mm:ss")
|
||
});
|
||
}
|
||
|
||
// 检查上午时段
|
||
if (reservation.start_time < morningEnd && reservation.end_time > morningStart)
|
||
{
|
||
timeSlots.morning.is_occupied = true;
|
||
timeSlots.morning.reservations.Add(new SQRoomTimeSlotReservationDto
|
||
{
|
||
start_time = reservation.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
end_time = reservation.end_time.ToString("yyyy-MM-dd HH:mm:ss")
|
||
});
|
||
}
|
||
|
||
// 检查下午时段
|
||
if (reservation.start_time < afternoonEnd && reservation.end_time > afternoonStart)
|
||
{
|
||
timeSlots.afternoon.is_occupied = true;
|
||
timeSlots.afternoon.reservations.Add(new SQRoomTimeSlotReservationDto
|
||
{
|
||
start_time = reservation.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
end_time = reservation.end_time.ToString("yyyy-MM-dd HH:mm:ss")
|
||
});
|
||
}
|
||
|
||
// 检查晚上时段
|
||
if (reservation.start_time < eveningEnd && reservation.end_time > eveningStart)
|
||
{
|
||
timeSlots.evening.is_occupied = true;
|
||
timeSlots.evening.reservations.Add(new SQRoomTimeSlotReservationDto
|
||
{
|
||
start_time = reservation.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
|
||
end_time = reservation.end_time.ToString("yyyy-MM-dd HH:mm:ss")
|
||
});
|
||
}
|
||
}
|
||
|
||
return timeSlots;
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 站内信消息接口
|
||
|
||
/// <summary>
|
||
/// 获取用户消息列表
|
||
/// </summary>
|
||
/// <param name="pageIndex">页码,从1开始</param>
|
||
/// <param name="pageSize">每页数量</param>
|
||
/// <param name="messageType">消息类型:0=全部,1=私信</param>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
[Authorize]
|
||
public async Task<JsonResult> GetMessageList(int pageIndex = 1, int pageSize = 20, int messageType = 0)
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var list = await _sQMessageServices.GetUserMessageListAsync(userId, messageType, pageIndex, pageSize);
|
||
|
||
jm.code = 0;
|
||
jm.msg = "获取成功";
|
||
jm.data = list;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取消息列表失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取未读消息数量
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
[Authorize]
|
||
public async Task<JsonResult> GetUnreadCount()
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var count = await _sQMessageServices.GetUnreadCountAsync(userId);
|
||
|
||
jm.code = 0;
|
||
jm.msg = "获取成功";
|
||
jm.data = new { count };
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取未读数量失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 标记所有消息为已读
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
[Authorize]
|
||
public async Task<JsonResult> MarkAllAsRead()
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var result = await _sQMessageServices.MarkAllAsReadAsync(userId);
|
||
|
||
if (result)
|
||
{
|
||
jm.code = 0;
|
||
jm.msg = "标记成功";
|
||
}
|
||
else
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "标记失败";
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "操作失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 收益相关接口
|
||
|
||
/// <summary>
|
||
/// 获取收益统计信息
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
[Authorize]
|
||
public async Task<JsonResult> GetEarningsSummary()
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var result = await _sQEarningsServices.GetEarningsSummaryAsync(userId);
|
||
|
||
jm.code = 0;
|
||
jm.msg = "ok";
|
||
jm.data = result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取收益规则说明
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
[HttpGet]
|
||
public async Task<JsonResult> GetEarningsRule()
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
// 从配置中获取收益规则说明
|
||
var allConfigs = await _settingServices.GetConfigDictionaries();
|
||
var content = CommonHelper.GetConfigDictionary(allConfigs, SystemSettingConstVars.EarningsRule);
|
||
|
||
// 如果配置为空,返回默认内容
|
||
if (string.IsNullOrWhiteSpace(content))
|
||
{
|
||
content = "收益规则说明:\n1. 收益来源于房间预约成功后的分成\n2. 收益可随时提现\n3. 提现将在3-5个工作日内到账\n4. 最低提现金额为0.01元";
|
||
}
|
||
|
||
jm.code = 0;
|
||
jm.msg = "ok";
|
||
jm.data = new { content };
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取收益记录列表
|
||
/// </summary>
|
||
/// <param name="pageIndex">页码,从1开始</param>
|
||
/// <param name="pageSize">每页数量</param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
[Authorize]
|
||
public async Task<JsonResult> GetEarningsRecordList([FromBody] PageRequest request)
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var pageIndex = request?.pageIndex ?? 1;
|
||
var pageSize = request?.pageSize ?? 20;
|
||
|
||
var result = await _sQEarningsServices.GetEarningsRecordListAsync(userId, pageIndex, pageSize);
|
||
|
||
jm.code = 0;
|
||
jm.msg = "ok";
|
||
jm.data = result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取提现记录列表
|
||
/// </summary>
|
||
/// <param name="request">分页请求</param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
[Authorize]
|
||
public async Task<JsonResult> GetWithdrawRecordList([FromBody] PageRequest request)
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var pageIndex = request?.pageIndex ?? 1;
|
||
var pageSize = request?.pageSize ?? 20;
|
||
|
||
var result = await _sQEarningsServices.GetWithdrawRecordListAsync(userId, pageIndex, pageSize);
|
||
|
||
jm.code = 0;
|
||
jm.msg = "ok";
|
||
jm.data = result;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "获取失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 申请提现
|
||
/// </summary>
|
||
/// <param name="request">提现请求</param>
|
||
/// <returns></returns>
|
||
[HttpPost]
|
||
[Authorize]
|
||
public async Task<JsonResult> ApplyWithdraw([FromBody] ApplyWithdrawRequest request)
|
||
{
|
||
var jm = new WebApiCallBack();
|
||
|
||
try
|
||
{
|
||
var userId = _user.ID;
|
||
if (userId <= 0)
|
||
{
|
||
jm.code = 401;
|
||
jm.msg = "请先登录";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
if (request == null || request.amount <= 0)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "请输入正确的提现金额";
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
var result = await _sQEarningsServices.ApplyWithdrawAsync(userId, request.amount);
|
||
|
||
jm.code = result.status ? 0 : 1;
|
||
jm.msg = result.msg;
|
||
jm.data = result.data;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
jm.code = 1;
|
||
jm.msg = "提现申请失败";
|
||
jm.data = ex.Message;
|
||
}
|
||
|
||
return new JsonResult(jm);
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// 分页请求
|
||
/// </summary>
|
||
public class PageRequest
|
||
{
|
||
/// <summary>
|
||
/// 页码,从1开始
|
||
/// </summary>
|
||
public int pageIndex { get; set; } = 1;
|
||
|
||
/// <summary>
|
||
/// 每页数量
|
||
/// </summary>
|
||
public int pageSize { get; set; } = 20;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 申请提现请求
|
||
/// </summary>
|
||
public class ApplyWithdrawRequest
|
||
{
|
||
/// <summary>
|
||
/// 提现金额
|
||
/// </summary>
|
||
public decimal amount { get; set; }
|
||
}
|
||
|