This commit is contained in:
zpc 2025-12-07 03:17:37 +08:00
parent 3857ecad81
commit 0173638400
4 changed files with 1012 additions and 17 deletions

View File

@ -17,6 +17,7 @@ using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.Entities.Expression;
using CoreCms.Net.Model.FromBody;
using CoreCms.Net.Model.ViewModels.UI;
using CoreCms.Net.Model.ViewModels.SQ;
using CoreCms.Net.Utility.Extensions;
using CoreCms.Net.Utility.Helper;
using CoreCms.Net.Web.Admin.Infrastructure;
@ -30,11 +31,14 @@ using NPOI.HSSF.UserModel;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using NLog;
using AutoMapper;
namespace CoreCms.Net.Web.Admin.Controllers
{
@ -50,16 +54,31 @@ namespace CoreCms.Net.Web.Admin.Controllers
{
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly ISQRoomPricingServices _SQRoomPricingServices;
private readonly ISQRoomsServices _SQRoomsServices;
private readonly ISQReservationsServices _SQReservationsServices;
private readonly ISQReservationParticipantsServices _SQReservationParticipantsServices;
private readonly ICoreCmsUserServices _userServices;
private readonly IMapper _mapper;
/// <summary>
/// 构造函数
///</summary>
public SQRoomPricingController(IWebHostEnvironment webHostEnvironment
, ISQRoomPricingServices SQRoomPricingServices
, ISQRoomsServices SQRoomsServices
, ISQReservationsServices SQReservationsServices
, ISQReservationParticipantsServices SQReservationParticipantsServices
, ICoreCmsUserServices userServices
, IMapper mapper
)
{
_webHostEnvironment = webHostEnvironment;
_SQRoomPricingServices = SQRoomPricingServices;
_SQRoomsServices = SQRoomsServices;
_SQReservationsServices = SQReservationsServices;
_SQReservationParticipantsServices = SQReservationParticipantsServices;
_userServices = userServices;
_mapper = mapper;
}
#region ============================================================
@ -820,6 +839,265 @@ namespace CoreCms.Net.Web.Admin.Controllers
}
#endregion
#region ============================================================
// GET: Api/SQRoomPricing/GetRoomListWithSlots
/// <summary>
/// 获取房间列表及时段状态(用于日历视图)
/// </summary>
/// <param name="date">日期</param>
/// <param name="showOnlyAvailable">是否只显示可用房间</param>
/// <param name="currentTimeSlot">当前时段</param>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
[Description("获取房间列表及时段状态")]
public async Task<AdminUiCallBack> GetRoomListWithSlots([FromQuery] string date, [FromQuery] bool showOnlyAvailable = false, [FromQuery] int? currentTimeSlot = null)
{
var jm = new AdminUiCallBack();
// 验证日期参数
if (string.IsNullOrEmpty(date))
{
jm.msg = "请提供日期参数";
return jm;
}
if (!DateTime.TryParse(date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
// 调用服务获取数据
var result = await _SQRoomsServices.GetRoomListWithSlotsAsync(dateValue, showOnlyAvailable, currentTimeSlot);
jm.code = 0;
jm.msg = "获取成功";
jm.data = result;
return jm;
}
#endregion
#region ============================================================
// GET: Api/SQRoomPricing/GetDateDetails
/// <summary>
/// 获取指定日期和房间的详细信息(用于日历视图点击日期)
/// </summary>
/// <param name="date">日期</param>
/// <param name="roomId">房间ID</param>
/// <returns></returns>
[HttpGet]
[AllowAnonymous]
[Description("获取日期详情")]
public async Task<AdminUiCallBack> GetDateDetails([FromQuery] string date, [FromQuery] int roomId)
{
var jm = new AdminUiCallBack();
try
{
// 验证参数
if (string.IsNullOrEmpty(date))
{
jm.msg = "请提供日期参数";
return jm;
}
if (roomId <= 0)
{
jm.msg = "请提供房间ID";
return jm;
}
if (!DateTime.TryParse(date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
// 获取房间信息
var room = await _SQRoomsServices.QueryByIdAsync(roomId);
if (room == null)
{
jm.msg = "房间不存在";
return jm;
}
// 获取该日期该房间的时段状态
var roomListWithSlots = await _SQRoomsServices.GetRoomListWithSlotsAsync(dateValue, false, null);
var roomData = roomListWithSlots?.FirstOrDefault(r => r.id == roomId);
// 获取该日期该房间的预约列表
var startTime = dateValue.Date;
var endTime = dateValue.Date.AddDays(1);
var reservations = await _SQReservationsServices.QueryListByClauseAsync(
p => p.room_id == roomId &&
p.start_time >= startTime &&
p.start_time < endTime &&
p.status != 4, // 排除已取消的预约
p => p.start_time,
OrderByType.Asc
);
// 查询所有预约的参与者
var reservationIds = reservations.Select(r => r.id).ToList();
List<SQReservationParticipants> allParticipants = new List<SQReservationParticipants>();
List<CoreCmsUser> userList = new List<CoreCmsUser>();
if (reservationIds.Any())
{
allParticipants = await _SQReservationParticipantsServices.QueryListByClauseAsync(
p => reservationIds.Contains(p.reservation_id),
p => p.role,
OrderByType.Desc,
true
);
// 查询所有参与者的用户信息
var userIds = allParticipants.Select(p => p.user_id).Distinct().ToList();
if (userIds.Any())
{
userList = await _userServices.QueryListByClauseAsync(
u => userIds.Contains(u.id),
u => u.id,
OrderByType.Asc,
true
);
}
}
// 处理时段数据,添加参与者头像和数量
var enhancedTimeSlots = new List<object>();
if (roomData?.time_slots != null)
{
foreach (var slot in roomData.time_slots)
{
// 获取该时段的所有预约
var slotReservations = reservations.Where(r =>
r.time_slot_type.HasValue && r.time_slot_type.Value == slot.slot_type
).ToList();
// 获取该时段所有预约的参与者(正常状态)
var slotReservationIds = slotReservations.Select(r => r.id).ToList();
var slotParticipants = allParticipants.Where(p =>
slotReservationIds.Contains(p.reservation_id) && p.status == 0
).ToList();
// 提取头像列表
var avatars = slotParticipants
.Select(p => userList.FirstOrDefault(u => u.id == p.user_id)?.avatarImage)
.Where(avatar => !string.IsNullOrEmpty(avatar))
.Distinct()
.ToList();
enhancedTimeSlots.Add(new
{
slot_type = slot.slot_type,
slot_name = slot.slot_name,
status = slot.status,
price_desc_standard = slot.price_desc_standard,
price_desc_member = slot.price_desc_member,
reservation_count = slotParticipants.Count,
participant_avatars = avatars
});
}
}
// 按时段分组预约
var reservationsBySlot = new Dictionary<int, List<object>>();
for (int i = 0; i <= 3; i++)
{
reservationsBySlot[i] = new List<object>();
}
foreach (var reservation in reservations)
{
// 确定预约所属时段
int slotType = reservation.time_slot_type ?? GetTimeSlotTypeFromTime(reservation.start_time);
// 获取该预约的参与者
var participants = allParticipants.Where(p => p.reservation_id == reservation.id)
.OrderBy(p => p.role == 1 ? 0 : 1) // 发起者优先
.ThenBy(p => p.status) // 正常状态优先
.ToList();
var participantsDto = _mapper.Map<List<SQReservationParticipantsDto>>(participants);
// 填充用户信息
foreach (var p in participantsDto)
{
var user = userList.FirstOrDefault(u => u.id == p.user_id);
if (user != null)
{
p.UserName = user.nickName;
p.AvatarImage = user.avatarImage;
}
}
reservationsBySlot[slotType].Add(new
{
id = reservation.id,
title = reservation.title,
player_count = reservation.player_count,
deposit_fee = reservation.deposit_fee,
latest_arrival_time = reservation.latest_arrival_time?.ToString("yyyy-MM-dd HH:mm:ss"),
game_type = reservation.game_type,
game_rule = reservation.game_rule,
start_time = reservation.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
end_time = reservation.end_time.ToString("yyyy-MM-dd HH:mm:ss"),
status = reservation.status,
participants = participantsDto.Select(p => new
{
id = p.id,
user_id = p.user_id,
user_name = p.UserName,
avatar_image = p.AvatarImage,
join_time = p.join_time.ToString("yyyy-MM-dd HH:mm:ss"),
role = p.role,
quit_time = p.quit_time?.ToString("yyyy-MM-dd HH:mm:ss"),
status = p.status,
is_refund = p.is_refund,
remarks = p.remarks
}).ToList()
});
}
// 构建返回数据
var result = new
{
date = date,
room_id = roomId,
room_name = room.name,
time_slots = enhancedTimeSlots,
reservations_by_slot = reservationsBySlot
};
jm.code = 0;
jm.msg = "获取成功";
jm.data = result;
}
catch (Exception ex)
{
jm.msg = "获取数据时发生错误:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "获取日期详情", "GetDateDetails", ex);
}
return jm;
}
/// <summary>
/// 根据时间判断时段类型
/// </summary>
private int GetTimeSlotTypeFromTime(DateTime time)
{
var hour = time.Hour;
if (hour >= 0 && hour < 6) return 0; // 凌晨 00:00-06:00
if (hour >= 6 && hour < 12) return 1; // 上午 06:00-12:00
if (hour >= 12 && hour < 18) return 2; // 下午 12:00-18:00
return 3; // 晚上 18:00-24:00
}
#endregion
}
}

View File

@ -4013,7 +4013,7 @@
</summary>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.#ctor(Microsoft.AspNetCore.Hosting.IWebHostEnvironment,CoreCms.Net.IServices.ISQRoomPricingServices)">
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.#ctor(Microsoft.AspNetCore.Hosting.IWebHostEnvironment,CoreCms.Net.IServices.ISQRoomPricingServices,CoreCms.Net.IServices.ISQRoomsServices,CoreCms.Net.IServices.ISQReservationsServices,CoreCms.Net.IServices.ISQReservationParticipantsServices,CoreCms.Net.IServices.ICoreCmsUserServices,AutoMapper.IMapper)">
<summary>
构造函数
</summary>
@ -4098,6 +4098,28 @@
<param name="entity"></param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.GetRoomListWithSlots(System.String,System.Boolean,System.Nullable{System.Int32})">
<summary>
获取房间列表及时段状态(用于日历视图)
</summary>
<param name="date">日期</param>
<param name="showOnlyAvailable">是否只显示可用房间</param>
<param name="currentTimeSlot">当前时段</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.GetDateDetails(System.String,System.Int32)">
<summary>
获取指定日期和房间的详细信息(用于日历视图点击日期)
</summary>
<param name="date">日期</param>
<param name="roomId">房间ID</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.GetTimeSlotTypeFromTime(System.DateTime)">
<summary>
根据时间判断时段类型
</summary>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.SQRoomsController">
<summary>
房间表

View File

@ -749,6 +749,8 @@
}
});
}
//执行单个删除
function doDelete(obj) {
coreHelper.Post("Api/SQReservations/DoDelete", { id: obj.data.id }, function (e) {

View File

@ -9,30 +9,183 @@
<!--当前位置结束-->
<style>
/* 重写样式 */
.calendar-view {
display: none;
padding: 20px;
background: #fff;
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 15px;
background: #f8f8f8;
border-radius: 4px;
}
.calendar-header h3 {
margin: 0;
font-size: 18px;
font-weight: bold;
}
.calendar-nav button {
margin: 0 5px;
}
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 10px;
margin-top: 20px;
}
.calendar-weekday {
text-align: center;
font-weight: bold;
padding: 10px;
background: #f0f0f0;
border-radius: 4px;
}
.calendar-day {
border: 1px solid #e6e6e6;
border-radius: 4px;
padding: 10px;
min-height: 140px;
background: #fff;
transition: all 0.3s;
}
.calendar-day:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transform: translateY(-2px);
}
.calendar-day.empty {
background: #fafafa;
border-color: #f0f0f0;
}
.calendar-day.today {
border-color: #009688;
background: #f0fffe;
}
.calendar-day-header {
font-weight: bold;
margin-bottom: 8px;
font-size: 16px;
color: #333;
}
.calendar-day-price {
font-size: 12px;
color: #666;
margin-bottom: 4px;
}
.calendar-day-member {
display: inline-block;
background: #ff5722;
color: #fff;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
margin-bottom: 6px;
}
.calendar-day-slots {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 4px;
margin-top: 8px;
}
.calendar-slot {
font-size: 11px;
padding: 3px 5px;
border-radius: 3px;
text-align: center;
}
.calendar-slot.available {
background: #e8f5e9;
color: #4caf50;
}
.calendar-slot.unavailable {
background: #ffebee;
color: #f44336;
}
.calendar-slot.reserved {
background: #fff3e0;
color: #ff9800;
}
.calendar-slot.using {
background: #a3a9ac1e;
color: #ff9800;
}
</style>
<script type="text/html" template lay-type="Post" lay-url="Api/SQRoomPricing/GetIndex" lay-done="layui.data.done(d);">
</script>
<div class="table-body">
<table id="LAY-app-SQRoomPricing-tableBox" lay-filter="LAY-app-SQRoomPricing-tableBox"></table>
</div>
<script type="text/html" id="LAY-app-SQRoomPricing-toolbar">
<!-- 独立的搜索工具栏 -->
<div class="layui-card" style="margin-bottom: 10px;">
<div class="layui-card-body">
<div class="layui-form coreshop-toolbar-search-form">
<div class="layui-form-item">
<div class="layui-form-item" style="margin-bottom: 0;">
<div class="layui-inline">
<label class="layui-form-label" for="room_id">房间号</label>
<div class="layui-input-inline">
<select name="room_id" id="search_room_id">
<select name="room_id" id="search_room_id" lay-filter="search_room_id">
<option value="">请选择房间号</option>
</select>
</div>
</div>
<div class="layui-inline">
<div class="layui-inline" id="table-view-search-btn">
<button class="layui-btn layui-btn-sm" lay-submit lay-filter="LAY-app-SQRoomPricing-search"><i class="layui-icon layui-icon-search"></i>筛选</button>
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm layui-btn-normal" id="toggleViewBtn" type="button">
<i class="layui-icon layui-icon-date"></i>切换日历视图
</button>
</div>
</div>
</div>
</div>
</div>
<div class="table-body" id="table-view">
<table id="LAY-app-SQRoomPricing-tableBox" lay-filter="LAY-app-SQRoomPricing-tableBox"></table>
</div>
<div class="calendar-view" id="calendar-view">
<div class="calendar-header">
<div class="calendar-nav">
<button class="layui-btn layui-btn-sm" id="prevMonthBtn">
<i class="layui-icon layui-icon-left"></i> 上一月
</button>
</div>
<h3 id="currentMonthTitle"></h3>
<div class="calendar-nav">
<button class="layui-btn layui-btn-sm" id="nextMonthBtn">
下一月 <i class="layui-icon layui-icon-right"></i>
</button>
</div>
</div>
<div class="calendar-grid" id="calendarGrid">
<!-- 日历将通过JavaScript动态生成 -->
</div>
</div>
<script type="text/html" id="LAY-app-SQRoomPricing-toolbar">
</script>
<script type="text/html" id="LAY-app-SQRoomPricing-pagebar">
@ -66,6 +219,9 @@
var indexData;
var debug= layui.setter.debug;
var roomOptions = []; // 定义在外部作用域供表格templet使用
var currentView = 'table'; // 当前视图table 或 calendar
var currentMonth = new Date(); // 当前显示的月份
var selectedRoomId = null; // 选中的房间ID
layui.data.done = function (d) {
//开启调试情况下获取接口赋值数据
@ -117,7 +273,7 @@
pagebar: '#LAY-app-SQRoomPricing-pagebar',
className: 'pagebarbox',
defaultToolbar: ['filter', 'print', 'exports'],
height: 'full-127',//面包屑142px,搜索框4行172,3行137,2行102,1行67
height: 'full-210',//面包屑142px + 独立搜索栏68px = 210px
page: true,
limit: 30,
limits: [10, 15, 20, 25, 30, 50, 100, 200],
@ -385,10 +541,547 @@
});
// 视图切换功能
$('#toggleViewBtn').on('click', function() {
if (currentView === 'table') {
// 切换到日历视图
currentView = 'calendar';
$('#table-view').hide();
$('#calendar-view').show();
$('#table-view-search-btn').hide();
$(this).html('<i class="layui-icon layui-icon-template"></i>切换表格视图');
// 获取当前选中的房间ID
var currentRoomId = $('#search_room_id').val();
// 如果没有选择房间,默认选择第一个
if (!currentRoomId && roomOptions.length > 0) {
selectedRoomId = roomOptions[0].id;
$('#search_room_id').val(selectedRoomId);
form.render('select');
} else {
selectedRoomId = currentRoomId ? parseInt(currentRoomId) : null;
}
if (debug) {
console.log('切换到日历视图选中房间ID:', selectedRoomId);
}
renderCalendar();
} else {
// 切换到表格视图
currentView = 'table';
$('#table-view').show();
$('#calendar-view').hide();
$('#table-view-search-btn').show();
$(this).html('<i class="layui-icon layui-icon-date"></i>切换日历视图');
}
});
// 监听房间选择变化(日历视图)
form.on('select(search_room_id)', function(data) {
if (currentView === 'calendar') {
selectedRoomId = data.value ? parseInt(data.value) : null;
if (debug) {
console.log('房间选择变化新房间ID:', selectedRoomId);
}
if (selectedRoomId) {
renderCalendar();
}
}
});
// 上一月按钮
$('#prevMonthBtn').on('click', function() {
currentMonth.setMonth(currentMonth.getMonth() - 1);
renderCalendar();
});
// 下一月按钮
$('#nextMonthBtn').on('click', function() {
currentMonth.setMonth(currentMonth.getMonth() + 1);
renderCalendar();
});
// 渲染日历
function renderCalendar() {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
var year = currentMonth.getFullYear();
var month = currentMonth.getMonth();
// 更新标题
$('#currentMonthTitle').text(year + '年 ' + (month + 1) + '月');
// 获取当月第一天和最后一天
var firstDay = new Date(year, month, 1);
var lastDay = new Date(year, month + 1, 0);
var firstDayOfWeek = firstDay.getDay() || 7; // 周日为0转换为7
var daysInMonth = lastDay.getDate();
// 清空日历
var calendarGrid = $('#calendarGrid');
calendarGrid.empty();
// 添加星期标题
var weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
weekdays.forEach(function(day) {
calendarGrid.append('<div class="calendar-weekday">' + day + '</div>');
});
// 添加空白日期(第一天之前)
for (var i = 1; i < firstDayOfWeek; i++) {
calendarGrid.append('<div class="calendar-day empty"></div>');
}
// 先渲染所有日期框架(显示日期号和加载提示)
for (var day = 1; day <= daysInMonth; day++) {
var currentDate = new Date(year, month, day);
var dateStr = formatDate(currentDate);
var isToday = dateStr === formatDate(new Date());
var dayHtml = '<div class="calendar-day' + (isToday ? ' today' : '') + '" data-date="' + dateStr + '" style="cursor:pointer;">';
dayHtml += '<div class="calendar-day-header">' + day + '号</div>';
dayHtml += '<div style="text-align:center;color:#999;padding:20px 0;">加载中...</div>';
dayHtml += '</div>';
calendarGrid.append(dayHtml);
}
// 绑定日期点击事件
$('#calendarGrid').off('click', '.calendar-day').on('click', '.calendar-day', function() {
var clickedDate = $(this).attr('data-date');
if (clickedDate && !$(this).hasClass('empty')) {
showDateDetails(clickedDate);
}
});
// 异步加载数据并更新
var startDate = new Date(year, month, 1);
var endDate = new Date(year, month + 1, 0);
loadMonthData(selectedRoomId, startDate, endDate);
}
// 加载月度数据
function loadMonthData(roomId, startDate, endDate) {
var daysToLoad = [];
// 生成日期列表
var currentDate = new Date(startDate);
while (currentDate <= endDate) {
daysToLoad.push(new Date(currentDate));
currentDate.setDate(currentDate.getDate() + 1);
}
if (debug) {
console.log('开始加载数据房间ID:', roomId, '日期数量:', daysToLoad.length);
}
// 批量加载数据,每个日期加载完成后立即更新
daysToLoad.forEach(function(date) {
var dateStr = formatDate(date);
var url = layui.setter.apiUrl + "Api/SQRoomPricing/GetRoomListWithSlots?date=" + encodeURIComponent(dateStr) + "&showOnlyAvailable=false";
if (debug) {
console.log('请求URL:', url);
}
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(e) {
if (debug) {
console.log('日期:', dateStr, '返回数据:', e);
}
var dayElement = $('#calendarGrid').find('.calendar-day[data-date="' + dateStr + '"]');
if (debug) {
console.log('查找元素:', dateStr, '找到:', dayElement.length);
}
if (dayElement.length === 0) {
console.warn('未找到日期元素:', dateStr);
return;
}
// 清空加载提示(保留日期标题)
dayElement.find('div:not(.calendar-day-header)').remove();
if (e.code === 0 && e.data && Array.isArray(e.data)) {
// 注意roomId 可能是字符串,需要类型转换比较
var roomData = e.data.find(function(r) {
return r.id == roomId || r.id == parseInt(roomId);
});
if (debug) {
console.log('查找房间:', roomId, '找到:', roomData ? '是' : '否');
}
if (roomData && roomData.time_slots && Array.isArray(roomData.time_slots)) {
var dayContentHtml = '';
// 显示价格信息
var firstSlot = roomData.time_slots[0];
if (firstSlot && firstSlot.standard_price) {
dayContentHtml += '<div class="calendar-day-price">' + firstSlot.standard_price + '元/时段</div>';
}
if (firstSlot && firstSlot.member_price > 0) {
dayContentHtml += '<div class="calendar-day-member">会员价</div>';
}
// 显示时段状态
dayContentHtml += '<div class="calendar-day-slots">';
roomData.time_slots.forEach(function(slot) {
var statusClass = 'unavailable';
var statusIcon = '✗';
if (slot.status === 'available') {
statusClass = 'available';
statusIcon = '◯';
} else if (slot.status === 'reserved') {
statusClass = 'reserved';
statusIcon = '✓ ';
}else if( slot.status === 'using'){
statusClass = 'using';
statusIcon = '✗';
}
dayContentHtml += '<div class="calendar-slot ' + statusClass + '">' +
slot.slot_name + statusIcon + '</div>';
});
dayContentHtml += '</div>';
dayElement.append(dayContentHtml);
} else {
dayElement.append('<div style="text-align:center;color:#999;padding:10px 0;">无房间数据</div>');
}
} else {
var errorMsg = e.msg || '加载失败';
dayElement.append('<div style="text-align:center;color:#f44336;padding:10px 0;">' + errorMsg + '</div>');
}
},
error: function(xhr, status, error) {
console.error('请求失败:', dateStr, status, error);
var dayElement = $('#calendarGrid').find('.calendar-day[data-date="' + dateStr + '"]');
if (dayElement.length > 0) {
dayElement.find('div:not(.calendar-day-header)').remove();
dayElement.append('<div style="text-align:center;color:#f44336;padding:10px 0;">网络错误</div>');
}
}
});
});
}
// 格式化日期为 YYYY-MM-DD
function formatDate(date) {
var year = date.getFullYear();
var month = (date.getMonth() + 1).toString().padStart(2, '0');
var day = date.getDate().toString().padStart(2, '0');
return year + '-' + month + '-' + day;
}
// 展示日期详情弹窗
function showDateDetails(dateStr) {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
// 查找对应的房间名称
var selectedRoom = roomOptions.find(function(r) {
return r.id == selectedRoomId;
});
var roomName = selectedRoom ? selectedRoom.name : '未知房间';
// 显示加载提示
var loadingIndex = layer.load(1, { shade: [0.1, '#fff'] });
// 请求详细数据
var url = layui.setter.apiUrl + "Api/SQRoomPricing/GetDateDetails?date=" + encodeURIComponent(dateStr) + "&roomId=" + selectedRoomId;
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(e) {
layer.close(loadingIndex);
if (e.code === 0 && e.data) {
var data = e.data;
// 构建弹窗内容
var content = '<div style="padding: 20px;">';
// 日期和房间信息
content += '<div class="layui-row">';
content += ' <div class="layui-col-md12">';
content += ' <div class="layui-card">';
content += ' <div class="layui-card-header"><h3>日期信息</h3></div>';
content += ' <div class="layui-card-body">';
content += ' <div class="layui-row">';
content += ' <div class="layui-col-md6">';
content += ' <p><strong>日期:</strong>' + dateStr + '</p>';
content += ' <p><strong>房间:</strong>' + roomName + '</p>';
content += ' </div>';
content += ' <div class="layui-col-md6">';
content += ' <p><strong>星期:</strong>' + getWeekDay(dateStr) + '</p>';
content += ' </div>';
content += ' </div>';
content += ' </div>';
content += ' </div>';
content += ' </div>';
content += '</div>';
// 时段详情
if (data.time_slots && data.time_slots.length > 0) {
content += '<div class="layui-row" style="margin-top: 20px;">';
content += ' <div class="layui-col-md12">';
content += ' <div class="layui-card">';
content += ' <div class="layui-card-header"><h3>时段详情</h3></div>';
content += ' <div class="layui-card-body">';
content += ' <table id="dateDetailsTable" lay-filter="dateDetailsTable"></table>';
content += ' </div>';
content += ' </div>';
content += ' </div>';
content += '</div>';
}
// 预约详情列表(按时段分组)
content += '<div id="reservationsBySlot"></div>';
content += '</div>';
// 弹出窗口
layer.open({
type: 1,
title: roomName + ' - ' + dateStr + ' 详情',
area: ['1200px', '90%'],
content: content,
success: function(layero, index) {
// 渲染时段详情表格
if (data.time_slots && data.time_slots.length > 0) {
var tableData = data.time_slots.map(function(slot) {
return {
slot_name: slot.slot_name || '',
status: slot.status || '',
price_desc_standard: slot.price_desc_standard || '',
price_desc_member: slot.price_desc_member || '',
participant_avatars: slot.participant_avatars || [],
reservation_count: slot.reservation_count || 0
};
});
table.render({
elem: '#dateDetailsTable',
data: tableData,
page: false,
cols: [[
{ field: 'slot_name', title: '时段', width: 100 },
{
field: 'status',
title: '状态',
width: 100,
templet: function(d) {
var statusText = '';
var statusColor = '';
if (d.status === 'available') {
statusText = '可用';
statusColor = '#5FB878';
} else if (d.status === 'reserved') {
statusText = '已预约';
statusColor = '#FFB800';
} else if (d.status === 'using') {
statusText = '使用中';
statusColor = '#999';
} else if (d.status === 'unavailable') {
statusText = '不可用';
statusColor = '#FF5722';
} else {
statusText = d.status;
statusColor = '#999';
}
return '<span style="background: ' + statusColor + '; color: white; padding: 2px 8px; border-radius: 3px; font-size: 12px;">' + statusText + '</span>';
}
},
{ field: 'price_desc_standard', title: '普通价格描述', width: 150 },
{ field: 'price_desc_member', title: '会员价格描述', width: 150 },
{
field: 'participant_avatars',
title: '预约人头像',
width: 200,
templet: function(d) {
if (!d.participant_avatars || d.participant_avatars.length === 0) {
return '<span style="color: #999;"></span>';
}
var html = '<div style="display: flex; gap: 4px; flex-wrap: wrap;">';
d.participant_avatars.forEach(function(avatar) {
html += '<img src="' + avatar + '" style="width:28px;height:28px;border-radius:50%;object-fit:cover;" onerror="this.src=\'/images/default-avatar.png\'" />';
});
html += '</div>';
return html;
}
},
{ field: 'reservation_count', title: '预约人数', width: 100 }
]]
});
}
// 渲染按时段分组的预约详情
if (data.reservations_by_slot) {
var slotNames = ['凌晨', '上午', '下午', '晚上'];
var reservationsBySlotContainer = $('#reservationsBySlot');
for (var slotType = 0; slotType <= 3; slotType++) {
var slotReservations = data.reservations_by_slot[slotType];
if (slotReservations && slotReservations.length > 0) {
// 时段标题
var slotHtml = '<div class="layui-row" style="margin-top: 20px;">';
slotHtml += ' <div class="layui-col-md12">';
slotHtml += ' <h3 style="padding: 10px; background: #f8f8f8; border-left: 4px solid #009688;">预约详情列表(' + slotNames[slotType] + '</h3>';
// 遍历该时段的每个预约
slotReservations.forEach(function(reservation, idx) {
slotHtml += ' <div class="layui-card" style="margin-top: 10px;">';
slotHtml += ' <div class="layui-card-header">';
slotHtml += ' <div class="layui-row">';
slotHtml += ' <div class="layui-col-md3"><strong>组局名称:</strong>' + (reservation.title || '无') + '</div>';
slotHtml += ' <div class="layui-col-md2"><strong>参与人数:</strong>' + (reservation.player_count || 0) + '人</div>';
slotHtml += ' <div class="layui-col-md2"><strong>鸽子费:</strong>' + (reservation.deposit_fee || 0) + '元</div>';
slotHtml += ' <div class="layui-col-md3"><strong>最晚到店:</strong>' + (reservation.latest_arrival_time || '无') + '</div>';
slotHtml += ' </div>';
slotHtml += ' <div class="layui-row" style="margin-top: 5px;">';
slotHtml += ' <div class="layui-col-md3"><strong>玩法类型:</strong>' + (reservation.game_type || '无') + '</div>';
slotHtml += ' <div class="layui-col-md3"><strong>具体规则:</strong>' + (reservation.game_rule || '无') + '</div>';
slotHtml += ' <div class="layui-col-md4"><strong>开始时间:</strong>' + (reservation.start_time || '无') + '</div>';
slotHtml += ' </div>';
slotHtml += ' </div>';
slotHtml += ' <div class="layui-card-body">';
slotHtml += ' <table id="participantsTable_' + slotType + '_' + reservation.id + '" lay-filter="participantsTable_' + slotType + '_' + reservation.id + '"></table>';
slotHtml += ' </div>';
slotHtml += ' </div>';
});
slotHtml += ' </div>';
slotHtml += '</div>';
reservationsBySlotContainer.append(slotHtml);
// 渲染每个预约的参与者表格
slotReservations.forEach(function(reservation, idx) {
var participants = reservation.participants || [];
table.render({
elem: '#participantsTable_' + slotType + '_' + reservation.id,
data: participants,
page: false,
cols: [[
{ field: 'id', title: 'ID', width: 60 },
{ field: 'user_id', title: '用户ID', width: 80 },
{ field: 'user_name', title: '用户昵称', width: 120 },
{
field: 'avatar_image',
title: '用户头像',
width: 80,
templet: function(d) {
if (d.avatar_image) {
return '<img src="' + d.avatar_image + '" style="width:40px;height:40px;border-radius:50%;object-fit:cover;" onerror="this.src=\'/images/default-avatar.png\'" />';
}
return '<span style="color: #999;"></span>';
}
},
{ field: 'join_time', title: '参与时间', width: 150 },
{
field: 'role',
title: '角色',
width: 80,
templet: function(d) {
return d.role === 1 ? '<span style="color: #ff5722;">发起者</span>' : '参与者';
}
},
{ field: 'quit_time', title: '退出时间', width: 150 },
{
field: 'is_refund',
title: '鸽子费状态',
width: 100,
templet: function(d) {
var refundText = '';
var refundColor = '';
switch(d.is_refund) {
case 0:
refundText = '无需退款';
refundColor = '#999';
break;
case 1:
refundText = '未付鸽子费';
refundColor = '#1E9FFF';
break;
case 2:
refundText = '已付鸽子费';
refundColor = '#FFB800';
break;
case 3:
refundText = '退款中';
refundColor = '#5FB878';
break;
case 4:
refundText = '退款成功';
refundColor = '#5FB878';
break;
case 9:
refundText = '退款失败';
refundColor = '#FF5722';
break;
default:
refundText = '未知状态';
refundColor = '#999';
}
return '<span style="background: ' + refundColor + '; color: white; padding: 2px 6px; border-radius: 3px; font-size: 12px;">' + refundText + '</span>';
}
},
{ field: 'remarks', title: '备注', minWidth: 150 }
]]
});
});
}
}
}
}
});
} else {
layer.msg(e.msg || '获取数据失败');
}
},
error: function(xhr, status, error) {
layer.close(loadingIndex);
console.error('请求失败:', status, error);
layer.msg('获取数据失败,请稍后重试');
}
});
}
// 获取星期几
function getWeekDay(dateStr) {
var date = new Date(dateStr);
var weekDays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
return weekDays[date.getDay()];
}
//重载form
form.render();
});
};
// 查看预约详情(全局函数,供表格调用)
function viewReservationDetail(reservationId) {
// 跳转到预约管理页面或打开预约详情弹窗
layer.msg('预约ID: ' + reservationId + ',可跳转到预约详情页面');
// 实际使用时可以调用预约详情接口
}
</script>
<!--设置是否启用-->