This commit is contained in:
zpc 2025-12-07 15:15:37 +08:00
parent 7468f0df26
commit 2fe3facdce
8 changed files with 1886 additions and 552 deletions

View File

@ -2796,5 +2796,33 @@ namespace CoreCms.Net.Configuration
} }
#endregion #endregion
#region ===============================================================
/// <summary>
/// 房间不可用类型
/// </summary>
public enum RoomUnavailableType
{
/// <summary>
/// 禁用/维护
/// </summary>
[Description("禁用/维护")]
Disabled = 1,
/// <summary>
/// 后台预约
/// </summary>
[Description("后台预约")]
BackendReservation = 2,
/// <summary>
/// 线下预约
/// </summary>
[Description("线下预约")]
OfflineReservation = 3
}
#endregion
} }
} }

View File

@ -93,6 +93,12 @@ namespace CoreCms.Net.Model.Entities
[Display(Name = "时段类型")] [Display(Name = "时段类型")]
public System.Int32? time_slot_type { get; set; } public System.Int32? time_slot_type { get; set; }
/// <summary>
/// 不可用类型1-禁用/维护, 2-后台预约, 3-线下预约
/// </summary>
[Display(Name = "不可用类型")]
public System.Int32 type { get; set; } = 1;
/// <summary> /// <summary>
/// 创建人ID管理员 /// 创建人ID管理员
/// </summary> /// </summary>

View File

@ -380,6 +380,11 @@ namespace CoreCms.Net.Model.ViewModels.SQ
/// </summary> /// </summary>
public string price_desc_member { get; set; } public string price_desc_member { get; set; }
/// <summary>
/// 不可用类型当status为unavailable时有效1=禁用/维护2=后台预约3=线下预约
/// </summary>
public int? unavailable_type { get; set; }
/// <summary> /// <summary>
/// 该时段内的预约列表(仅详情接口返回) /// 该时段内的预约列表(仅详情接口返回)
/// </summary> /// </summary>

View File

@ -243,14 +243,15 @@ namespace CoreCms.Net.Services
} }
else else
{ {
// 检查不可用时段 // 检查不可用时段,并获取禁用类型
bool isUnavailable = unavailableTimes?.Any(u => var unavailableRecord = unavailableTimes?.FirstOrDefault(u =>
(u.time_slot_type.HasValue && u.time_slot_type.Value == slotType) || (u.time_slot_type.HasValue && u.time_slot_type.Value == slotType) ||
(u.start_time < slotEnd && u.end_time > slotStart)) ?? false; (u.start_time < slotEnd && u.end_time > slotStart));
if (isUnavailable) if (unavailableRecord != null)
{ {
slotDto.status = GlobalConstVars.RoomStatusUnavailable; slotDto.status = GlobalConstVars.RoomStatusUnavailable;
slotDto.unavailable_type = unavailableRecord.type; // 设置禁用类型
} }
else else
{ {

View File

@ -57,6 +57,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
private readonly ISQRoomsServices _SQRoomsServices; private readonly ISQRoomsServices _SQRoomsServices;
private readonly ISQReservationsServices _SQReservationsServices; private readonly ISQReservationsServices _SQReservationsServices;
private readonly ISQReservationParticipantsServices _SQReservationParticipantsServices; private readonly ISQReservationParticipantsServices _SQReservationParticipantsServices;
private readonly ISQRoomUnavailableTimesServices _SQRoomUnavailableTimesServices;
private readonly ICoreCmsUserServices _userServices; private readonly ICoreCmsUserServices _userServices;
private readonly IMapper _mapper; private readonly IMapper _mapper;
@ -68,6 +69,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
, ISQRoomsServices SQRoomsServices , ISQRoomsServices SQRoomsServices
, ISQReservationsServices SQReservationsServices , ISQReservationsServices SQReservationsServices
, ISQReservationParticipantsServices SQReservationParticipantsServices , ISQReservationParticipantsServices SQReservationParticipantsServices
, ISQRoomUnavailableTimesServices SQRoomUnavailableTimesServices
, ICoreCmsUserServices userServices , ICoreCmsUserServices userServices
, IMapper mapper , IMapper mapper
) )
@ -77,6 +79,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
_SQRoomsServices = SQRoomsServices; _SQRoomsServices = SQRoomsServices;
_SQReservationsServices = SQReservationsServices; _SQReservationsServices = SQReservationsServices;
_SQReservationParticipantsServices = SQReservationParticipantsServices; _SQReservationParticipantsServices = SQReservationParticipantsServices;
_SQRoomUnavailableTimesServices = SQRoomUnavailableTimesServices;
_userServices = userServices; _userServices = userServices;
_mapper = mapper; _mapper = mapper;
} }
@ -1098,6 +1101,545 @@ namespace CoreCms.Net.Web.Admin.Controllers
} }
#endregion #endregion
#region ============================================================
// POST: Api/SQRoomPricing/SetRoomUnavailable
/// <summary>
/// 设置房间时段不可用
/// </summary>
/// <param name="roomId">房间ID</param>
/// <param name="date">日期</param>
/// <param name="timeSlotType">时段类型0=凌晨1=上午2=下午3=晚上)</param>
/// <param name="type">不可用类型1=禁用/维护2=后台预约3=线下预约)</param>
/// <param name="reason">原因/备注</param>
/// <returns></returns>
[HttpPost]
[Description("设置房间时段不可用")]
public async Task<AdminUiCallBack> SetRoomUnavailable([FromBody] SetRoomUnavailableRequest request)
{
var jm = new AdminUiCallBack();
try
{
// 参数验证
if (request.roomId <= 0)
{
jm.msg = "请选择房间";
return jm;
}
if (string.IsNullOrEmpty(request.date))
{
jm.msg = "请选择日期";
return jm;
}
if (!DateTime.TryParse(request.date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
if (request.timeSlotType < 0 || request.timeSlotType > 3)
{
jm.msg = "时段类型不正确";
return jm;
}
if (request.type < 1 || request.type > 3)
{
jm.msg = "不可用类型不正确";
return jm;
}
// 检查房间是否存在
var room = await _SQRoomsServices.QueryByIdAsync(request.roomId);
if (room == null)
{
jm.msg = "房间不存在";
return jm;
}
// 根据时段类型计算开始和结束时间
var (startTime, endTime) = GetTimeSlotRange(dateValue, request.timeSlotType);
// 检查该时段是否已有用户预约
var hasReservation = await _SQReservationsServices.ExistsAsync(
r => r.room_id == request.roomId &&
r.status < 4 && // 排除已取消的预约
r.start_time < endTime &&
r.end_time > startTime
);
if (hasReservation)
{
jm.msg = "该时段已有用户预约,请先处理预约后再设置禁用";
return jm;
}
// 检查是否已存在禁用记录
var existingRecord = await _SQRoomUnavailableTimesServices.QueryByClauseAsync(
u => u.room_id == request.roomId &&
u.time_slot_type == request.timeSlotType &&
u.start_time == startTime &&
u.end_time == endTime,
u => u.id,
OrderByType.Asc
);
if (existingRecord != null)
{
// 更新现有记录
existingRecord.type = request.type;
existingRecord.reason = request.reason;
await _SQRoomUnavailableTimesServices.UpdateAsync(existingRecord);
jm.code = 0;
jm.msg = "更新成功";
}
else
{
// 新增记录
var newRecord = new SQRoomUnavailableTimes
{
room_id = request.roomId,
start_time = startTime,
end_time = endTime,
time_slot_type = request.timeSlotType,
type = request.type,
reason = request.reason,
created_at = DateTime.Now
};
await _SQRoomUnavailableTimesServices.InsertAsync(newRecord);
jm.code = 0;
jm.msg = "设置成功";
}
}
catch (Exception ex)
{
jm.msg = "设置失败:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "设置房间不可用", "SetRoomUnavailable", ex);
}
return jm;
}
/// <summary>
/// 根据时段类型获取时间范围
/// </summary>
private (DateTime startTime, DateTime endTime) GetTimeSlotRange(DateTime date, int timeSlotType)
{
var baseDate = date.Date;
return timeSlotType switch
{
0 => (baseDate, baseDate.AddHours(6)), // 凌晨 00:00-06:00
1 => (baseDate.AddHours(6), baseDate.AddHours(12)), // 上午 06:00-12:00
2 => (baseDate.AddHours(12), baseDate.AddHours(18)), // 下午 12:00-18:00
3 => (baseDate.AddHours(18), baseDate.AddDays(1)), // 晚上 18:00-24:00
_ => (baseDate, baseDate.AddDays(1))
};
}
#endregion
#region ============================================================
// POST: Api/SQRoomPricing/CancelRoomUnavailable
/// <summary>
/// 取消房间时段不可用
/// </summary>
/// <param name="id">不可用记录ID</param>
/// <returns></returns>
[HttpPost]
[Description("取消房间时段不可用")]
public async Task<AdminUiCallBack> CancelRoomUnavailable([FromBody] CancelRoomUnavailableRequest request)
{
var jm = new AdminUiCallBack();
try
{
if (request.ids == null || request.ids.Length == 0)
{
jm.msg = "请选择要取消的记录";
return jm;
}
await _SQRoomUnavailableTimesServices.DeleteByIdsAsync(request.ids);
jm.code = 0;
jm.msg = "取消成功";
}
catch (Exception ex)
{
jm.msg = "取消失败:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "取消房间不可用", "CancelRoomUnavailable", ex);
}
return jm;
}
#endregion
#region ============================================================
// POST: Api/SQRoomPricing/CancelRoomUnavailableAllDay
/// <summary>
/// 取消房间整天不可用(删除该日期的所有禁用记录)
/// </summary>
/// <param name="roomId">房间ID</param>
/// <param name="date">日期</param>
/// <returns></returns>
[HttpPost]
[Description("取消房间整天不可用")]
public async Task<AdminUiCallBack> CancelRoomUnavailableAllDay([FromBody] CancelRoomUnavailableAllDayRequest request)
{
var jm = new AdminUiCallBack();
try
{
// 参数验证
if (request.roomId <= 0)
{
jm.msg = "请选择房间";
return jm;
}
if (string.IsNullOrEmpty(request.date))
{
jm.msg = "请选择日期";
return jm;
}
if (!DateTime.TryParse(request.date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
// 检查房间是否存在
var room = await _SQRoomsServices.QueryByIdAsync(request.roomId);
if (room == null)
{
jm.msg = "房间不存在";
return jm;
}
// 获取该日期的开始和结束时间
var startOfDay = dateValue.Date;
var endOfDay = dateValue.Date.AddDays(1);
// 查询该房间该日期的所有禁用记录
var unavailableRecords = await _SQRoomUnavailableTimesServices.QueryListByClauseAsync(
u => u.room_id == request.roomId &&
u.start_time >= startOfDay &&
u.start_time < endOfDay
);
if (unavailableRecords == null || unavailableRecords.Count == 0)
{
jm.msg = "该日期没有禁用记录";
return jm;
}
// 获取所有记录的ID
var ids = unavailableRecords.Select(r => r.id).ToArray();
// 批量删除
await _SQRoomUnavailableTimesServices.DeleteByIdsAsync(ids);
jm.code = 0;
jm.msg = $"取消成功,共删除 {ids.Length} 条禁用记录";
}
catch (Exception ex)
{
jm.msg = "取消失败:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "取消房间整天不可用", "CancelRoomUnavailableAllDay", ex);
}
return jm;
}
#endregion
#region ============================================================
// POST: Api/SQRoomPricing/SetRoomUnavailableAllDay
/// <summary>
/// 设置房间整天不可用(禁用所有时段,类型为维护)
/// </summary>
/// <param name="roomId">房间ID</param>
/// <param name="date">日期</param>
/// <returns></returns>
[HttpPost]
[Description("设置房间整天不可用")]
public async Task<AdminUiCallBack> SetRoomUnavailableAllDay([FromBody] SetRoomUnavailableAllDayRequest request)
{
var jm = new AdminUiCallBack();
try
{
// 参数验证
if (request.roomId <= 0)
{
jm.msg = "请选择房间";
return jm;
}
if (string.IsNullOrEmpty(request.date))
{
jm.msg = "请选择日期";
return jm;
}
if (!DateTime.TryParse(request.date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
// 检查房间是否存在
var room = await _SQRoomsServices.QueryByIdAsync(request.roomId);
if (room == null)
{
jm.msg = "房间不存在";
return jm;
}
// 检查该日期是否已有用户预约
var startOfDay = dateValue.Date;
var endOfDay = dateValue.Date.AddDays(1);
var hasReservation = await _SQReservationsServices.ExistsAsync(
r => r.room_id == request.roomId &&
r.status < 4 && // 排除已取消的预约
r.start_time < endOfDay &&
r.end_time > startOfDay
);
if (hasReservation)
{
jm.msg = "该日期已有用户预约,请先处理预约后再设置禁用";
return jm;
}
// 禁用类型为维护type=1原因默认为"整天维护"
var maintenanceType = 1;
var defaultReason = "整天维护";
// 遍历所有4个时段设置禁用
var successCount = 0;
var updateCount = 0;
var insertCount = 0;
for (int timeSlotType = 0; timeSlotType <= 3; timeSlotType++)
{
var (startTime, endTime) = GetTimeSlotRange(dateValue, timeSlotType);
// 检查是否已存在禁用记录
var existingRecord = await _SQRoomUnavailableTimesServices.QueryByClauseAsync(
u => u.room_id == request.roomId &&
u.time_slot_type == timeSlotType &&
u.start_time == startTime &&
u.end_time == endTime,
u => u.id,
OrderByType.Asc
);
if (existingRecord != null)
{
// 更新现有记录为维护类型
existingRecord.type = maintenanceType;
existingRecord.reason = defaultReason;
await _SQRoomUnavailableTimesServices.UpdateAsync(existingRecord);
updateCount++;
}
else
{
// 新增记录
var newRecord = new SQRoomUnavailableTimes
{
room_id = request.roomId,
start_time = startTime,
end_time = endTime,
time_slot_type = timeSlotType,
type = maintenanceType,
reason = defaultReason,
created_at = DateTime.Now
};
await _SQRoomUnavailableTimesServices.InsertAsync(newRecord);
insertCount++;
}
successCount++;
}
jm.code = 0;
jm.msg = $"禁用成功,共设置 {successCount} 个时段(新增 {insertCount} 条,更新 {updateCount} 条)";
}
catch (Exception ex)
{
jm.msg = "禁用失败:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "设置房间整天不可用", "SetRoomUnavailableAllDay", ex);
}
return jm;
}
#endregion
#region ============================================================
// GET: Api/SQRoomPricing/GetRoomUnavailableList
/// <summary>
/// 获取房间某日期的禁用列表
/// </summary>
/// <param name="roomId">房间ID</param>
/// <param name="date">日期</param>
/// <returns></returns>
[HttpGet]
[Description("获取房间禁用列表")]
public async Task<AdminUiCallBack> GetRoomUnavailableList([FromQuery] int roomId, [FromQuery] string date)
{
var jm = new AdminUiCallBack();
try
{
if (roomId <= 0)
{
jm.msg = "请选择房间";
return jm;
}
if (string.IsNullOrEmpty(date))
{
jm.msg = "请选择日期";
return jm;
}
if (!DateTime.TryParse(date, out DateTime dateValue))
{
jm.msg = "日期格式不正确";
return jm;
}
// 获取该日期的开始和结束时间
var startOfDay = dateValue.Date;
var endOfDay = dateValue.Date.AddDays(1);
// 查询该房间该日期的所有禁用记录
var list = await _SQRoomUnavailableTimesServices.QueryListByClauseAsync(
u => u.room_id == roomId &&
u.start_time >= startOfDay &&
u.start_time < endOfDay,
u => u.time_slot_type,
OrderByType.Asc
);
// 时段名称映射
var slotNames = new[] { "凌晨", "上午", "下午", "晚上" };
var typeNames = new Dictionary<int, string>
{
{ 1, "禁用/维护" },
{ 2, "后台预约" },
{ 3, "线下预约" }
};
var result = list.Select(item => new
{
item.id,
item.room_id,
item.time_slot_type,
slot_name = item.time_slot_type.HasValue && item.time_slot_type.Value >= 0 && item.time_slot_type.Value <= 3
? slotNames[item.time_slot_type.Value]
: "未知",
item.type,
type_name = typeNames.ContainsKey(item.type) ? typeNames[item.type] : "未知",
item.reason,
start_time = item.start_time.ToString("yyyy-MM-dd HH:mm:ss"),
end_time = item.end_time.ToString("yyyy-MM-dd HH:mm:ss"),
created_at = item.created_at.ToString("yyyy-MM-dd HH:mm:ss")
}).ToList();
jm.code = 0;
jm.msg = "获取成功";
jm.data = result;
}
catch (Exception ex)
{
jm.msg = "获取失败:" + ex.Message;
NLogUtil.WriteAll(LogLevel.Error, LogType.Web, "获取房间禁用列表", "GetRoomUnavailableList", ex);
}
return jm;
}
#endregion
} }
#region
/// <summary>
/// 设置房间不可用请求参数
/// </summary>
public class SetRoomUnavailableRequest
{
/// <summary>
/// 房间ID
/// </summary>
public int roomId { get; set; }
/// <summary>
/// 日期 (YYYY-MM-DD)
/// </summary>
public string date { get; set; }
/// <summary>
/// 时段类型0=凌晨1=上午2=下午3=晚上)
/// </summary>
public int timeSlotType { get; set; }
/// <summary>
/// 不可用类型1=禁用/维护2=后台预约3=线下预约)
/// </summary>
public int type { get; set; }
/// <summary>
/// 原因/备注
/// </summary>
public string reason { get; set; }
}
/// <summary>
/// 取消房间不可用请求参数
/// </summary>
public class CancelRoomUnavailableRequest
{
/// <summary>
/// 不可用记录ID数组
/// </summary>
public int[] ids { get; set; }
}
/// <summary>
/// 设置房间整天不可用请求参数
/// </summary>
public class SetRoomUnavailableAllDayRequest
{
/// <summary>
/// 房间ID
/// </summary>
public int roomId { get; set; }
/// <summary>
/// 日期 (YYYY-MM-DD)
/// </summary>
public string date { get; set; }
}
/// <summary>
/// 取消房间整天不可用请求参数
/// </summary>
public class CancelRoomUnavailableAllDayRequest
{
/// <summary>
/// 房间ID
/// </summary>
public int roomId { get; set; }
/// <summary>
/// 日期 (YYYY-MM-DD)
/// </summary>
public string date { get; set; }
}
#endregion
} }

View File

@ -4013,7 +4013,7 @@
</summary> </summary>
</member> </member>
<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)"> <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.ISQRoomUnavailableTimesServices,CoreCms.Net.IServices.ICoreCmsUserServices,AutoMapper.IMapper)">
<summary> <summary>
构造函数 构造函数
</summary> </summary>
@ -4120,6 +4120,123 @@
根据时间判断时段类型 根据时间判断时段类型
</summary> </summary>
</member> </member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.SetRoomUnavailable(CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest)">
<summary>
设置房间时段不可用
</summary>
<param name="roomId">房间ID</param>
<param name="date">日期</param>
<param name="timeSlotType">时段类型0=凌晨1=上午2=下午3=晚上)</param>
<param name="type">不可用类型1=禁用/维护2=后台预约3=线下预约)</param>
<param name="reason">原因/备注</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.GetTimeSlotRange(System.DateTime,System.Int32)">
<summary>
根据时段类型获取时间范围
</summary>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.CancelRoomUnavailable(CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableRequest)">
<summary>
取消房间时段不可用
</summary>
<param name="id">不可用记录ID</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.CancelRoomUnavailableAllDay(CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableAllDayRequest)">
<summary>
取消房间整天不可用(删除该日期的所有禁用记录)
</summary>
<param name="roomId">房间ID</param>
<param name="date">日期</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.SetRoomUnavailableAllDay(CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableAllDayRequest)">
<summary>
设置房间整天不可用(禁用所有时段,类型为维护)
</summary>
<param name="roomId">房间ID</param>
<param name="date">日期</param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.SQRoomPricingController.GetRoomUnavailableList(System.Int32,System.String)">
<summary>
获取房间某日期的禁用列表
</summary>
<param name="roomId">房间ID</param>
<param name="date">日期</param>
<returns></returns>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest">
<summary>
设置房间不可用请求参数
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest.roomId">
<summary>
房间ID
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest.date">
<summary>
日期 (YYYY-MM-DD)
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest.timeSlotType">
<summary>
时段类型0=凌晨1=上午2=下午3=晚上)
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest.type">
<summary>
不可用类型1=禁用/维护2=后台预约3=线下预约)
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableRequest.reason">
<summary>
原因/备注
</summary>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableRequest">
<summary>
取消房间不可用请求参数
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableRequest.ids">
<summary>
不可用记录ID数组
</summary>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableAllDayRequest">
<summary>
设置房间整天不可用请求参数
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableAllDayRequest.roomId">
<summary>
房间ID
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.SetRoomUnavailableAllDayRequest.date">
<summary>
日期 (YYYY-MM-DD)
</summary>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableAllDayRequest">
<summary>
取消房间整天不可用请求参数
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableAllDayRequest.roomId">
<summary>
房间ID
</summary>
</member>
<member name="P:CoreCms.Net.Web.Admin.Controllers.CancelRoomUnavailableAllDayRequest.date">
<summary>
日期 (YYYY-MM-DD)
</summary>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.SQRoomsController"> <member name="T:CoreCms.Net.Web.Admin.Controllers.SQRoomsController">
<summary> <summary>
房间表 房间表

View File

@ -68,7 +68,7 @@
} }
.calendar-day:hover { .calendar-day:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
transform: translateY(-2px); transform: translateY(-2px);
} }
@ -139,12 +139,17 @@
color: #ff9800; color: #ff9800;
} }
.calendar-slot.backend-reservation {
background: #e65100;
color: #fff;
}
/* 右键菜单样式调整 */ /* 右键菜单样式调整 */
.context-menu-list { .context-menu-list {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 14px; font-size: 14px;
border-radius: 4px; border-radius: 4px;
box-shadow: 0 2px 12px rgba(0,0,0,0.15); box-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);
border: 1px solid #e6e6e6; border: 1px solid #e6e6e6;
} }
@ -179,7 +184,8 @@
</div> </div>
</div> </div>
<div class="layui-inline" id="table-view-search-btn" style="display: none;"> <div class="layui-inline" id="table-view-search-btn" style="display: none;">
<button class="layui-btn layui-btn-sm" lay-submit lay-filter="LAY-app-SQRoomPricing-search"><i class="layui-icon layui-icon-search"></i>筛选</button> <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>
<div class="layui-inline"> <div class="layui-inline">
<button class="layui-btn layui-btn-sm layui-btn-normal" id="toggleViewBtn" type="button"> <button class="layui-btn layui-btn-sm layui-btn-normal" id="toggleViewBtn" type="button">
@ -247,7 +253,7 @@
<script> <script>
var indexData; var indexData;
var debug= layui.setter.debug; var debug = layui.setter.debug;
var roomOptions = []; // 定义在外部作用域供表格templet使用 var roomOptions = []; // 定义在外部作用域供表格templet使用
var currentView = 'calendar'; // 当前视图table 或 calendar var currentView = 'calendar'; // 当前视图table 或 calendar
var currentMonth = new Date(); // 当前显示的月份 var currentMonth = new Date(); // 当前显示的月份
@ -258,7 +264,7 @@
if (debug) { console.log(d); } if (debug) { console.log(d); }
indexData = d.data; indexData = d.data;
layui.use(['index', 'table', 'laydate', 'util', 'coredropdown', 'coreHelper'], layui.use(['index', 'table', 'laydate', 'util', 'coredropdown', 'coreHelper', 'element'],
function () { function () {
var $ = layui.$ var $ = layui.$
, admin = layui.admin , admin = layui.admin
@ -268,7 +274,8 @@
, setter = layui.setter , setter = layui.setter
, coreHelper = layui.coreHelper , coreHelper = layui.coreHelper
, util = layui.util , util = layui.util
, view = layui.view; , view = layui.view
, element = layui.element;
var searchwhere; var searchwhere;
@ -279,7 +286,7 @@
var roomSelect = $('#search_room_id'); var roomSelect = $('#search_room_id');
roomSelect.empty(); roomSelect.empty();
roomSelect.append('<option value="">请选择房间号</option>'); roomSelect.append('<option value="">请选择房间号</option>');
layui.each(roomOptions, function(index, item) { layui.each(roomOptions, function (index, item) {
roomSelect.append('<option value="' + item.id + '">' + item.name + '</option>'); roomSelect.append('<option value="' + item.id + '">' + item.name + '</option>');
}); });
@ -300,11 +307,11 @@
//监听搜索 //监听搜索
form.on('submit(LAY-app-SQRoomPricing-search)', form.on('submit(LAY-app-SQRoomPricing-search)',
function(data) { function (data) {
var field = data.field; var field = data.field;
searchwhere = field; searchwhere = field;
//执行重载 //执行重载
table.reloadData('LAY-app-SQRoomPricing-tableBox',{ where: field }); table.reloadData('LAY-app-SQRoomPricing-tableBox', { where: field });
}); });
//数据绑定 //数据绑定
table.render({ table.render({
@ -319,36 +326,40 @@
page: true, page: true,
limit: 30, limit: 30,
limits: [10, 15, 20, 25, 30, 50, 100, 200], limits: [10, 15, 20, 25, 30, 50, 100, 200],
text: {none: '暂无相关数据'}, text: { none: '暂无相关数据' },
cols: [ cols: [
[ [
{ type: "checkbox", fixed: "left" }, { type: "checkbox", fixed: "left" },
{ field: 'id', title: 'id', width: 60, sort: false}, { field: 'id', title: 'id', width: 60, sort: false },
{ field: 'room_id', title: '房间号', sort: false, width: 150, templet: function(d) { {
var room = roomOptions.find(function(item) { return item.id == d.room_id; }); field: 'room_id', title: '房间号', sort: false, width: 150, templet: function (d) {
var room = roomOptions.find(function (item) { return item.id == d.room_id; });
return room ? room.name : (d.room_id || ''); return room ? room.name : (d.room_id || '');
}}, }
{ field: 'time_slot_type', title: '时间段', sort: false, width: 105, templet: function(d) { },
{
field: 'time_slot_type', title: '时间段', sort: false, width: 105, templet: function (d) {
if (d.time_slot_type === 0 || d.time_slot_type === '0') return '凌晨'; if (d.time_slot_type === 0 || d.time_slot_type === '0') return '凌晨';
if (d.time_slot_type === 1 || d.time_slot_type === '1') return '上午'; if (d.time_slot_type === 1 || d.time_slot_type === '1') return '上午';
if (d.time_slot_type === 2 || d.time_slot_type === '2') return '下午'; if (d.time_slot_type === 2 || d.time_slot_type === '2') return '下午';
if (d.time_slot_type === 3 || d.time_slot_type === '3') return '晚上'; if (d.time_slot_type === 3 || d.time_slot_type === '3') return '晚上';
return d.time_slot_type || ''; return d.time_slot_type || '';
}}, }
},
{ field: 'price_desc_standard', title: '普通价格描述', sort: false,width: 105 }, { field: 'price_desc_standard', title: '普通价格描述', sort: false, width: 105 },
{ field: 'price_desc_member', title: '会员价格描述', sort: false,width: 105 }, { field: 'price_desc_member', title: '会员价格描述', sort: false, width: 105 },
{ field: 'effective_date_start', title: '开始时间', sort: false,width: 105 }, { field: 'effective_date_start', title: '开始时间', sort: false, width: 105 },
{ field: 'effective_date_end', title: '结束时间', sort: false,width: 105 }, { field: 'effective_date_end', title: '结束时间', sort: false, width: 105 },
{ field: 'is_active', title: '是否启用', width: 95, templet: '#switch_is_active', sort: false , unresize: true}, { field: 'is_active', title: '是否启用', width: 95, templet: '#switch_is_active', sort: false, unresize: true },
{ field: 'created_at', title: '创建时间', width: 130, sort: false}, { field: 'created_at', title: '创建时间', width: 130, sort: false },
{ field: 'updated_at', title: '修改时间', width: 130, sort: false}, { field: 'updated_at', title: '修改时间', width: 130, sort: false },
{ width: 162, align: 'center', title:'操作', fixed: 'right', toolbar: '#LAY-app-SQRoomPricing-tableBox-bar' } { width: 162, align: 'center', title: '操作', fixed: 'right', toolbar: '#LAY-app-SQRoomPricing-tableBox-bar' }
] ]
] ]
}); });
//监听排序事件 //监听排序事件
table.on('sort(LAY-app-SQRoomPricing-tableBox)', function(obj){ table.on('sort(LAY-app-SQRoomPricing-tableBox)', function (obj) {
table.reloadData('LAY-app-SQRoomPricing-tableBox', { table.reloadData('LAY-app-SQRoomPricing-tableBox', {
initSort: obj, //记录初始排序,如果不设的话,将无法标记表头的排序状态。 initSort: obj, //记录初始排序,如果不设的话,将无法标记表头的排序状态。
where: { //请求参数(注意:这里面的参数可任意定义,并非下面固定的格式) where: { //请求参数(注意:这里面的参数可任意定义,并非下面固定的格式)
@ -382,7 +393,7 @@
}); });
//监听工具条 //监听工具条
table.on('tool(LAY-app-SQRoomPricing-tableBox)', table.on('tool(LAY-app-SQRoomPricing-tableBox)',
function(obj) { function (obj) {
if (obj.event === 'detail') { if (obj.event === 'detail') {
doDetails(obj); doDetails(obj);
} else if (obj.event === 'del') { } else if (obj.event === 'del') {
@ -392,7 +403,7 @@
} }
}); });
//执行创建操作 //执行创建操作
function doCreate(){ function doCreate() {
coreHelper.Post("Api/SQRoomPricing/GetCreate", null, function (e) { coreHelper.Post("Api/SQRoomPricing/GetCreate", null, function (e) {
if (e.code === 0) { if (e.code === 0) {
admin.popup({ admin.popup({
@ -404,7 +415,7 @@
view(this.id).render('sq/sqroompricing/create', { data: e.data }).done(function () { view(this.id).render('sq/sqroompricing/create', { data: e.data }).done(function () {
//监听提交 //监听提交
form.on('submit(LAY-app-SQRoomPricing-createForm-submit)', form.on('submit(LAY-app-SQRoomPricing-createForm-submit)',
function(data) { function (data) {
var field = data.field; //获取提交的字段 var field = data.field; //获取提交的字段
field.is_active = field.is_active == 'on'; field.is_active = field.is_active == 'on';
@ -437,8 +448,8 @@
}); });
} }
//执行编辑操作 //执行编辑操作
function doEdit(obj){ function doEdit(obj) {
coreHelper.Post("Api/SQRoomPricing/GetEdit", {id:obj.data.id}, function (e) { coreHelper.Post("Api/SQRoomPricing/GetEdit", { id: obj.data.id }, function (e) {
if (e.code === 0) { if (e.code === 0) {
admin.popup({ admin.popup({
shadeClose: false, shadeClose: false,
@ -449,7 +460,7 @@
view(this.id).render('sq/sqroompricing/edit', { data: e.data }).done(function () { view(this.id).render('sq/sqroompricing/edit', { data: e.data }).done(function () {
//监听提交 //监听提交
form.on('submit(LAY-app-SQRoomPricing-editForm-submit)', form.on('submit(LAY-app-SQRoomPricing-editForm-submit)',
function(data) { function (data) {
var field = data.field; //获取提交的字段 var field = data.field; //获取提交的字段
field.is_active = field.is_active == 'on'; field.is_active = field.is_active == 'on';
@ -504,7 +515,7 @@
}); });
} }
//执行单个删除 //执行单个删除
function doDelete(obj){ function doDelete(obj) {
coreHelper.Post("Api/SQRoomPricing/DoDelete", { id: obj.data.id }, function (e) { coreHelper.Post("Api/SQRoomPricing/DoDelete", { id: obj.data.id }, function (e) {
if (debug) { console.log(e); } //开启调试返回数据 if (debug) { console.log(e); } //开启调试返回数据
table.reloadData('LAY-app-SQRoomPricing-tableBox'); table.reloadData('LAY-app-SQRoomPricing-tableBox');
@ -512,16 +523,16 @@
}); });
} }
//执行批量删除 //执行批量删除
function doBatchDelete(checkStatus){ function doBatchDelete(checkStatus) {
var checkData = checkStatus.data; var checkData = checkStatus.data;
if (checkData.length === 0) { if (checkData.length === 0) {
return layer.msg('请选择要删除的数据'); return layer.msg('请选择要删除的数据');
} }
layer.confirm('确定删除吗?删除后将无法恢复。', layer.confirm('确定删除吗?删除后将无法恢复。',
function(index) { function (index) {
var delidsStr = []; var delidsStr = [];
layui.each(checkData, layui.each(checkData,
function(index, item) { function (index, item) {
delidsStr.push(item.id); delidsStr.push(item.id);
}); });
coreHelper.Post("Api/SQRoomPricing/DoBatchDelete", { id: delidsStr }, function (e) { coreHelper.Post("Api/SQRoomPricing/DoBatchDelete", { id: delidsStr }, function (e) {
@ -532,9 +543,9 @@
}); });
} }
//执行查询条件导出excel //执行查询条件导出excel
function doQueryExportexcel(){ function doQueryExportexcel() {
layer.confirm('确定根据当前的查询条件导出数据吗?', layer.confirm('确定根据当前的查询条件导出数据吗?',
function(index) { function (index) {
var field = searchwhere; var field = searchwhere;
coreHelper.PostForm("Api/SQRoomPricing/QueryExportExcel", field, function (e) { coreHelper.PostForm("Api/SQRoomPricing/QueryExportExcel", field, function (e) {
if (debug) { console.log(e); } //开启调试返回数据 if (debug) { console.log(e); } //开启调试返回数据
@ -547,16 +558,16 @@
}); });
} }
//执行选择目录导出数据 //执行选择目录导出数据
function doSelectExportExcel(checkStatus){ function doSelectExportExcel(checkStatus) {
var checkData = checkStatus.data; var checkData = checkStatus.data;
if (checkData.length === 0) { if (checkData.length === 0) {
return layer.msg('请选择您要导出的数据'); return layer.msg('请选择您要导出的数据');
} }
layer.confirm('确定导出选择的内容吗?', layer.confirm('确定导出选择的内容吗?',
function(index) { function (index) {
var delidsStr = []; var delidsStr = [];
layui.each(checkData, layui.each(checkData,
function(index, item) { function (index, item) {
delidsStr.push(item.id); delidsStr.push(item.id);
}); });
layer.close(index); layer.close(index);
@ -584,7 +595,7 @@
// 视图切换功能 // 视图切换功能
$('#toggleViewBtn').on('click', function() { $('#toggleViewBtn').on('click', function () {
if (currentView === 'table') { if (currentView === 'table') {
// 切换到日历视图 // 切换到日历视图
currentView = 'calendar'; currentView = 'calendar';
@ -621,7 +632,7 @@
}); });
// 监听房间选择变化(日历视图) // 监听房间选择变化(日历视图)
form.on('select(search_room_id)', function(data) { form.on('select(search_room_id)', function (data) {
if (currentView === 'calendar') { if (currentView === 'calendar') {
selectedRoomId = data.value ? parseInt(data.value) : null; selectedRoomId = data.value ? parseInt(data.value) : null;
if (debug) { if (debug) {
@ -634,13 +645,13 @@
}); });
// 上一月按钮 // 上一月按钮
$('#prevMonthBtn').on('click', function() { $('#prevMonthBtn').on('click', function () {
currentMonth.setMonth(currentMonth.getMonth() - 1); currentMonth.setMonth(currentMonth.getMonth() - 1);
renderCalendar(); renderCalendar();
}); });
// 下一月按钮 // 下一月按钮
$('#nextMonthBtn').on('click', function() { $('#nextMonthBtn').on('click', function () {
currentMonth.setMonth(currentMonth.getMonth() + 1); currentMonth.setMonth(currentMonth.getMonth() + 1);
renderCalendar(); renderCalendar();
}); });
@ -670,7 +681,7 @@
// 添加星期标题 // 添加星期标题
var weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日']; var weekdays = ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
weekdays.forEach(function(day) { weekdays.forEach(function (day) {
calendarGrid.append('<div class="calendar-weekday">' + day + '</div>'); calendarGrid.append('<div class="calendar-weekday">' + day + '</div>');
}); });
@ -693,7 +704,7 @@
} }
// 绑定日期双击事件(查看详情) // 绑定日期双击事件(查看详情)
$('#calendarGrid').off('dblclick', '.calendar-day').on('dblclick', '.calendar-day', function() { $('#calendarGrid').off('dblclick', '.calendar-day').on('dblclick', '.calendar-day', function () {
var clickedDate = $(this).attr('data-date'); var clickedDate = $(this).attr('data-date');
if (clickedDate && !$(this).hasClass('empty')) { if (clickedDate && !$(this).hasClass('empty')) {
showDateDetails(clickedDate); showDateDetails(clickedDate);
@ -717,25 +728,323 @@
// 创建右键菜单 // 创建右键菜单
$.contextMenu({ $.contextMenu({
selector: '.calendar-day:not(.empty)', selector: '.calendar-day:not(.empty)',
callback: function(key, options) { callback: function (key, options) {
var dateStr = $(this).attr('data-date'); var dateStr = $(this).attr('data-date');
if (!dateStr) return; if (!dateStr) return;
switch(key) { switch (key) {
case 'view': case 'view':
showDateDetails(dateStr); showDateDetails(dateStr);
break; break;
case 'setUnavailable':
showSetUnavailableDialog(dateStr);
break;
case 'cancelUnavailable':
showCancelUnavailableDialog(dateStr);
break;
case 'disableAllDay':
showDisableAllDayConfirm(dateStr);
break;
case 'cancelAllUnavailable':
showCancelAllUnavailableConfirm(dateStr);
break;
} }
}, },
items: { items: {
"view": { "view": {
name: "查看", name: "查看",
icon: "fa-eye" icon: "fa-eye"
},
"sep1": "---------",
"setUnavailable": {
name: "设置预约状态",
icon: "fa-ban"
},
"cancelUnavailable": {
name: "取消预约状态",
icon: "fa-check-circle"
},
"sep2": "---------",
"disableAllDay": {
name: "禁用整天",
icon: "fa-calendar-times"
},
"cancelAllUnavailable": {
name: "取消全部禁用",
icon: "fa-undo"
} }
} }
}); });
} }
// 取消全部禁用确认
function showCancelAllUnavailableConfirm(dateStr) {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
var selectedRoom = roomOptions.find(function (r) {
return r.id == selectedRoomId;
});
var roomName = selectedRoom ? selectedRoom.name : '未知房间';
layer.confirm('确定要取消 ' + roomName + ' 在 ' + dateStr + ' 的所有禁用吗?<br>这将取消该日期的所有时段禁用记录。', {
icon: 3,
title: '取消全部禁用确认'
}, function (confirmIndex) {
// 调用取消全部禁用接口
coreHelper.Post("Api/SQRoomPricing/CancelRoomUnavailableAllDay", {
roomId: selectedRoomId,
date: dateStr
}, function (e) {
layer.close(confirmIndex);
if (e.code === 0) {
layer.msg(e.msg);
refreshSingleDay(dateStr); // 只刷新当前日期
} else {
layer.msg(e.msg);
}
});
});
}
// 禁用整天确认
function showDisableAllDayConfirm(dateStr) {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
var selectedRoom = roomOptions.find(function (r) {
return r.id == selectedRoomId;
});
var roomName = selectedRoom ? selectedRoom.name : '未知房间';
layer.confirm('确定要禁用 ' + roomName + ' 在 ' + dateStr + ' 的整天吗?<br>这将禁用该日期的所有时段(凌晨、上午、下午、晚上),类型为维护。', {
icon: 3,
title: '禁用整天确认'
}, function (confirmIndex) {
// 调用禁用整天接口
coreHelper.Post("Api/SQRoomPricing/SetRoomUnavailableAllDay", {
roomId: selectedRoomId,
date: dateStr
}, function (e) {
layer.close(confirmIndex);
if (e.code === 0) {
layer.msg(e.msg);
refreshSingleDay(dateStr); // 只刷新当前日期
} else {
layer.msg(e.msg);
}
});
});
}
// 设置禁用弹窗
function showSetUnavailableDialog(dateStr) {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
var selectedRoom = roomOptions.find(function (r) {
return r.id == selectedRoomId;
});
var roomName = selectedRoom ? selectedRoom.name : '未知房间';
admin.popup({
shadeClose: false,
title: '设置禁用 - ' + roomName + ' - ' + dateStr,
area: ['1200px', '800px'],
id: 'LAY-popup-SQRoomPricing-unavailable',
btn: ['确定', '取消'],
success: function (layero, index) {
view(this.id).render('sq/sqroompricing/unavailable', {
data: {
dateStr: dateStr,
roomName: roomName,
selectedRoomId: selectedRoomId,
renderCalendar: renderCalendar,
refreshSingleDay: refreshSingleDay
}
}).done(function () {
form.render('radio', 'setUnavailableForm');
});
},
yes: function (index, layero) {
// 调用模板中保存的提交处理函数
if (typeof window._setUnavailableSubmitHandler === 'function') {
window._setUnavailableSubmitHandler(layero, index);
} else {
layer.msg('提交处理函数未初始化');
}
}
});
}
// 取消禁用弹窗
function showCancelUnavailableDialog(dateStr) {
if (!selectedRoomId) {
layer.msg('请先选择房间');
return;
}
var selectedRoom = roomOptions.find(function (r) {
return r.id == selectedRoomId;
});
var roomName = selectedRoom ? selectedRoom.name : '未知房间';
// 获取禁用列表
coreHelper.Get("Api/SQRoomPricing/GetRoomUnavailableList?roomId=" + selectedRoomId + "&date=" + encodeURIComponent(dateStr), function (e) {
if (e.code === 0) {
var list = e.data || [];
if (list.length === 0) {
layer.msg('该日期没有禁用记录');
return;
}
// 构建弹窗内容
var content = '<div style="padding: 20px;">';
content += '<table id="unavailableListTable" lay-filter="unavailableListTable"></table>';
content += '</div>';
layer.open({
type: 1,
title: '取消禁用 - ' + roomName + ' - ' + dateStr,
area: ['700px', '400px'],
content: content,
btn: ['删除选中', '取消'],
success: function (layero, index) {
// 渲染表格
table.render({
elem: '#unavailableListTable',
data: list,
page: false,
cols: [[
{ type: 'checkbox', fixed: 'left' },
{ field: 'slot_name', title: '时段', width: 100 },
{ field: 'type_name', title: '类型', width: 100 },
{ field: 'reason', title: '原因', minWidth: 150 },
{ field: 'created_at', title: '创建时间', width: 160 }
]]
});
},
yes: function (index, layero) {
var checkStatus = table.checkStatus('unavailableListTable');
var checkData = checkStatus.data;
if (checkData.length === 0) {
layer.msg('请选择要删除的记录');
return;
}
var ids = checkData.map(function (item) { return item.id; });
layer.confirm('确定要删除选中的禁用记录吗?', function (confirmIndex) {
coreHelper.Post("Api/SQRoomPricing/CancelRoomUnavailable", {
ids: ids
}, function (e) {
if (e.code === 0) {
layer.close(confirmIndex);
layer.close(index);
layer.msg(e.msg);
refreshSingleDay(dateStr); // 只刷新当前日期
} else {
layer.msg(e.msg);
}
});
});
}
});
} else {
layer.msg(e.msg || '获取数据失败');
}
});
}
// 刷新单个日期
function refreshSingleDay(dateStr) {
if (!selectedRoomId || !dateStr) {
return;
}
var dayElement = $('#calendarGrid').find('.calendar-day[data-date="' + dateStr + '"]');
if (dayElement.length === 0) {
if (debug) {
console.warn('未找到日期元素:', dateStr);
}
return;
}
// 清空加载提示(保留日期标题)
dayElement.find('div:not(.calendar-day-header)').remove();
// 显示加载中
dayElement.append('<div style="text-align:center;color:#999;padding:10px 0;">加载中...</div>');
coreHelper.Get("Api/SQRoomPricing/GetRoomListWithSlots?date=" + encodeURIComponent(dateStr) + "&showOnlyAvailable=false", function (e) {
// 再次清空内容(包括加载提示)
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 == selectedRoomId || r.id == parseInt(selectedRoomId);
});
if (roomData && roomData.time_slots && Array.isArray(roomData.time_slots)) {
var dayContentHtml = '';
// 显示价格信息
var firstSlot = roomData.time_slots[0];
if (firstSlot && firstSlot.price_desc_standard != '') {
dayContentHtml += '<div class="calendar-day-price">' + firstSlot.price_desc_standard + '</div>';
}
if (firstSlot && firstSlot.price_desc_member != '') {
dayContentHtml += '<div class="calendar-day-price">' + firstSlot.price_desc_member + '</div>';
}
// 显示时段状态
dayContentHtml += '<div class="calendar-day-slots">';
roomData.time_slots.forEach(function (slot) {
var statusClass = 'unavailable';
var statusIcon = '✗';
// 检查该时段是否被后台预约禁用unavailable_type=2
if (slot.status === 'unavailable' && slot.unavailable_type === 2) {
// 后台预约:深橙色 + ✓
statusClass = 'backend-reservation';
statusIcon = '✓';
} else 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>');
}
});
}
// 加载月度数据 // 加载月度数据
function loadMonthData(roomId, startDate, endDate) { function loadMonthData(roomId, startDate, endDate) {
var daysToLoad = []; var daysToLoad = [];
@ -752,19 +1061,14 @@
} }
// 批量加载数据,每个日期加载完成后立即更新 // 批量加载数据,每个日期加载完成后立即更新
daysToLoad.forEach(function(date) { daysToLoad.forEach(function (date) {
var dateStr = formatDate(date); var dateStr = formatDate(date);
var url = layui.setter.apiUrl + "Api/SQRoomPricing/GetRoomListWithSlots?date=" + encodeURIComponent(dateStr) + "&showOnlyAvailable=false";
if (debug) { if (debug) {
console.log('请求URL:', url); console.log('请求日期:', dateStr);
} }
$.ajax({ coreHelper.Get("Api/SQRoomPricing/GetRoomListWithSlots?date=" + encodeURIComponent(dateStr) + "&showOnlyAvailable=false", function (e) {
url: url,
type: 'GET',
dataType: 'json',
success: function(e) {
if (debug) { if (debug) {
console.log('日期:', dateStr, '返回数据:', e); console.log('日期:', dateStr, '返回数据:', e);
} }
@ -785,7 +1089,7 @@
if (e.code === 0 && e.data && Array.isArray(e.data)) { if (e.code === 0 && e.data && Array.isArray(e.data)) {
// 注意roomId 可能是字符串,需要类型转换比较 // 注意roomId 可能是字符串,需要类型转换比较
var roomData = e.data.find(function(r) { var roomData = e.data.find(function (r) {
return r.id == roomId || r.id == parseInt(roomId); return r.id == roomId || r.id == parseInt(roomId);
}); });
@ -798,26 +1102,32 @@
// 显示价格信息 // 显示价格信息
var firstSlot = roomData.time_slots[0]; var firstSlot = roomData.time_slots[0];
if (firstSlot && firstSlot.standard_price) { if (firstSlot && firstSlot.price_desc_standard != '') {
dayContentHtml += '<div class="calendar-day-price">' + firstSlot.standard_price + '元/时段</div>'; dayContentHtml += '<div class="calendar-day-price">' + firstSlot.price_desc_standard + '</div>';
} }
if (firstSlot && firstSlot.member_price > 0) { if (firstSlot && firstSlot.price_desc_member != '') {
dayContentHtml += '<div class="calendar-day-member">会员价</div>'; dayContentHtml += '<div class="calendar-day-price">' + firstSlot.price_desc_member + '</div>';
} }
// 显示时段状态 // 显示时段状态
dayContentHtml += '<div class="calendar-day-slots">'; dayContentHtml += '<div class="calendar-day-slots">';
roomData.time_slots.forEach(function(slot) { roomData.time_slots.forEach(function (slot) {
var statusClass = 'unavailable'; var statusClass = 'unavailable';
var statusIcon = '✗'; var statusIcon = '✗';
if (slot.status === 'available') { // 检查该时段是否被后台预约禁用unavailable_type=2
if (slot.status === 'unavailable' && slot.unavailable_type === 2) {
// 后台预约:深橙色 + ✓
statusClass = 'backend-reservation';
statusIcon = '✓';
} else if (slot.status === 'available') {
statusClass = 'available'; statusClass = 'available';
statusIcon = '◯'; statusIcon = '◯';
} else if (slot.status === 'reserved') { } else if (slot.status === 'reserved') {
statusClass = 'reserved'; statusClass = 'reserved';
statusIcon = '✓ '; statusIcon = '✓ ';
}else if( slot.status === 'using'){ } else if (slot.status === 'using') {
statusClass = 'using'; statusClass = 'using';
statusIcon = '✗'; statusIcon = '✗';
} }
@ -835,16 +1145,8 @@
var errorMsg = e.msg || '加载失败'; var errorMsg = e.msg || '加载失败';
dayElement.append('<div style="text-align:center;color:#f44336;padding:10px 0;">' + errorMsg + '</div>'); 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>');
}
}
}); });
}); });
} }
@ -864,24 +1166,13 @@
} }
// 查找对应的房间名称 // 查找对应的房间名称
var selectedRoom = roomOptions.find(function(r) { var selectedRoom = roomOptions.find(function (r) {
return r.id == selectedRoomId; return r.id == selectedRoomId;
}); });
var roomName = selectedRoom ? selectedRoom.name : '未知房间'; 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; coreHelper.Get("Api/SQRoomPricing/GetDateDetails?date=" + encodeURIComponent(dateStr) + "&roomId=" + selectedRoomId, function (e) {
$.ajax({
url: url,
type: 'GET',
dataType: 'json',
success: function(e) {
layer.close(loadingIndex);
if (e.code === 0 && e.data) { if (e.code === 0 && e.data) {
var data = e.data; var data = e.data;
@ -933,10 +1224,10 @@
title: roomName + ' - ' + dateStr + ' 详情', title: roomName + ' - ' + dateStr + ' 详情',
area: ['1200px', '90%'], area: ['1200px', '90%'],
content: content, content: content,
success: function(layero, index) { success: function (layero, index) {
// 渲染时段详情表格 // 渲染时段详情表格
if (data.time_slots && data.time_slots.length > 0) { if (data.time_slots && data.time_slots.length > 0) {
var tableData = data.time_slots.map(function(slot) { var tableData = data.time_slots.map(function (slot) {
return { return {
slot_name: slot.slot_name || '', slot_name: slot.slot_name || '',
status: slot.status || '', status: slot.status || '',
@ -957,7 +1248,7 @@
field: 'status', field: 'status',
title: '状态', title: '状态',
width: 100, width: 100,
templet: function(d) { templet: function (d) {
var statusText = ''; var statusText = '';
var statusColor = ''; var statusColor = '';
if (d.status === 'available') { if (d.status === 'available') {
@ -985,12 +1276,12 @@
field: 'participant_avatars', field: 'participant_avatars',
title: '预约人头像', title: '预约人头像',
width: 200, width: 200,
templet: function(d) { templet: function (d) {
if (!d.participant_avatars || d.participant_avatars.length === 0) { if (!d.participant_avatars || d.participant_avatars.length === 0) {
return '<span style="color: #999;"></span>'; return '<span style="color: #999;"></span>';
} }
var html = '<div style="display: flex; gap: 4px; flex-wrap: wrap;">'; var html = '<div style="display: flex; gap: 4px; flex-wrap: wrap;">';
d.participant_avatars.forEach(function(avatar) { 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 += '<img src="' + avatar + '" style="width:28px;height:28px;border-radius:50%;object-fit:cover;" onerror="this.src=\'/images/default-avatar.png\'" />';
}); });
html += '</div>'; html += '</div>';
@ -1017,7 +1308,7 @@
slotHtml += ' <h3 style="padding: 10px; background: #f8f8f8; border-left: 4px solid #009688;">预约详情列表(' + slotNames[slotType] + '</h3>'; slotHtml += ' <h3 style="padding: 10px; background: #f8f8f8; border-left: 4px solid #009688;">预约详情列表(' + slotNames[slotType] + '</h3>';
// 遍历该时段的每个预约 // 遍历该时段的每个预约
slotReservations.forEach(function(reservation, idx) { slotReservations.forEach(function (reservation, idx) {
slotHtml += ' <div class="layui-card" style="margin-top: 10px;">'; slotHtml += ' <div class="layui-card" style="margin-top: 10px;">';
slotHtml += ' <div class="layui-card-header">'; slotHtml += ' <div class="layui-card-header">';
slotHtml += ' <div class="layui-row">'; slotHtml += ' <div class="layui-row">';
@ -1044,7 +1335,7 @@
reservationsBySlotContainer.append(slotHtml); reservationsBySlotContainer.append(slotHtml);
// 渲染每个预约的参与者表格 // 渲染每个预约的参与者表格
slotReservations.forEach(function(reservation, idx) { slotReservations.forEach(function (reservation, idx) {
var participants = reservation.participants || []; var participants = reservation.participants || [];
table.render({ table.render({
@ -1059,7 +1350,7 @@
field: 'avatar_image', field: 'avatar_image',
title: '用户头像', title: '用户头像',
width: 80, width: 80,
templet: function(d) { templet: function (d) {
if (d.avatar_image) { 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 '<img src="' + d.avatar_image + '" style="width:40px;height:40px;border-radius:50%;object-fit:cover;" onerror="this.src=\'/images/default-avatar.png\'" />';
} }
@ -1071,7 +1362,7 @@
field: 'role', field: 'role',
title: '角色', title: '角色',
width: 80, width: 80,
templet: function(d) { templet: function (d) {
return d.role === 1 ? '<span style="color: #ff5722;">发起者</span>' : '参与者'; return d.role === 1 ? '<span style="color: #ff5722;">发起者</span>' : '参与者';
} }
}, },
@ -1080,10 +1371,10 @@
field: 'is_refund', field: 'is_refund',
title: '鸽子费状态', title: '鸽子费状态',
width: 100, width: 100,
templet: function(d) { templet: function (d) {
var refundText = ''; var refundText = '';
var refundColor = ''; var refundColor = '';
switch(d.is_refund) { switch (d.is_refund) {
case 0: case 0:
refundText = '无需退款'; refundText = '无需退款';
refundColor = '#999'; refundColor = '#999';
@ -1127,12 +1418,6 @@
} else { } else {
layer.msg(e.msg || '获取数据失败'); layer.msg(e.msg || '获取数据失败');
} }
},
error: function(xhr, status, error) {
layer.close(loadingIndex);
console.error('请求失败:', status, error);
layer.msg('获取数据失败,请稍后重试');
}
}); });
} }
@ -1160,4 +1445,3 @@
<script type="text/html" id="switch_is_active"> <script type="text/html" id="switch_is_active">
<input type="checkbox" name="switch_is_active" value="{{d.id}}" lay-skin="switch" lay-text="开启|关闭" lay-filter="switch_is_active" {{ d.is_active ? 'checked' : '' }}> <input type="checkbox" name="switch_is_active" value="{{d.id}}" lay-skin="switch" lay-text="开启|关闭" lay-filter="switch_is_active" {{ d.is_active ? 'checked' : '' }}>
</script> </script>

View File

@ -0,0 +1,351 @@
<script type="text/html" template lay-done="layui.data.sendParams(d);">
<div class="layui-form" lay-filter="setUnavailableForm" style="padding: 20px;">
<!-- 日期和房间合并一行 -->
<div class="layui-form-item">
<label class="layui-form-label">日期</label>
<div class="layui-input-inline" style="width: 200px;">
<input type="text" class="layui-input" value="{{d.params.data.dateStr || ''}}" readonly>
</div>
<label class="layui-form-label" style="margin-left: 20px;">房间</label>
<div class="layui-input-inline" style="width: 200px;">
<input type="text" class="layui-input" value="{{d.params.data.roomName || ''}}" readonly>
</div>
</div>
<!-- 时段列表 -->
<div class="time-slot-list" style="margin-top: 20px;">
<!-- 凌晨时段 -->
<div class="time-slot-item" data-slot="0" style="border: 1px solid #e6e6e6; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #fff;">
<div class="layui-form-item" style="margin-bottom: 10px;">
<label class="layui-form-label" style="width: 80px;">凌晨:</label>
<div class="layui-input-block" style="margin-left: 90px; display: flex; align-items: center; flex-wrap: wrap;">
<input type="checkbox" name="switch_0" lay-skin="switch" lay-text="开启|关闭" lay-filter="slot-switch">
<input type="hidden" name="slot_id_0" value="">
<div style="margin-left: 20px; flex: 1; min-width: 200px;">
<div style="display: inline-block; margin-right: 20px;">
<input type="radio" name="type_0" value="1" title="禁用/维护" checked disabled>
<input type="radio" name="type_0" value="2" title="后台预约" disabled>
<input type="radio" name="type_0" value="3" title="线下预约" disabled>
</div>
<div style="display: inline-block; width: 300px;">
<input type="text" name="reason_0" placeholder="请输入原因/备注" class="layui-input" disabled>
</div>
</div>
</div>
</div>
</div>
<!-- 上午时段 -->
<div class="time-slot-item" data-slot="1" style="border: 1px solid #e6e6e6; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #fff;">
<div class="layui-form-item" style="margin-bottom: 10px;">
<label class="layui-form-label" style="width: 80px;">上午:</label>
<div class="layui-input-block" style="margin-left: 90px; display: flex; align-items: center; flex-wrap: wrap;">
<input type="checkbox" name="switch_1" lay-skin="switch" lay-text="开启|关闭" lay-filter="slot-switch">
<input type="hidden" name="slot_id_1" value="">
<div style="margin-left: 20px; flex: 1; min-width: 200px;">
<div style="display: inline-block; margin-right: 20px;">
<input type="radio" name="type_1" value="1" title="禁用/维护" checked disabled>
<input type="radio" name="type_1" value="2" title="后台预约" disabled>
<input type="radio" name="type_1" value="3" title="线下预约" disabled>
</div>
<div style="display: inline-block; width: 300px;">
<input type="text" name="reason_1" placeholder="请输入原因/备注" class="layui-input" disabled>
</div>
</div>
</div>
</div>
</div>
<!-- 下午时段 -->
<div class="time-slot-item" data-slot="2" style="border: 1px solid #e6e6e6; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #fff;">
<div class="layui-form-item" style="margin-bottom: 10px;">
<label class="layui-form-label" style="width: 80px;">下午:</label>
<div class="layui-input-block" style="margin-left: 90px; display: flex; align-items: center; flex-wrap: wrap;">
<input type="checkbox" name="switch_2" lay-skin="switch" lay-text="开启|关闭" lay-filter="slot-switch">
<input type="hidden" name="slot_id_2" value="">
<div style="margin-left: 20px; flex: 1; min-width: 200px;">
<div style="display: inline-block; margin-right: 20px;">
<input type="radio" name="type_2" value="1" title="禁用/维护" checked disabled>
<input type="radio" name="type_2" value="2" title="后台预约" disabled>
<input type="radio" name="type_2" value="3" title="线下预约" disabled>
</div>
<div style="display: inline-block; width: 300px;">
<input type="text" name="reason_2" placeholder="请输入原因/备注" class="layui-input" disabled>
</div>
</div>
</div>
</div>
</div>
<!-- 晚上时段 -->
<div class="time-slot-item" data-slot="3" style="border: 1px solid #e6e6e6; border-radius: 4px; padding: 15px; margin-bottom: 15px; background: #fff;">
<div class="layui-form-item" style="margin-bottom: 10px;">
<label class="layui-form-label" style="width: 80px;">晚上:</label>
<div class="layui-input-block" style="margin-left: 90px; display: flex; align-items: center; flex-wrap: wrap;">
<input type="checkbox" name="switch_3" lay-skin="switch" lay-text="开启|关闭" lay-filter="slot-switch">
<input type="hidden" name="slot_id_3" value="">
<div style="margin-left: 20px; flex: 1; min-width: 200px;">
<div style="display: inline-block; margin-right: 20px;">
<input type="radio" name="type_3" value="1" title="禁用/维护" checked disabled>
<input type="radio" name="type_3" value="2" title="后台预约" disabled>
<input type="radio" name="type_3" value="3" title="线下预约" disabled>
</div>
<div style="display: inline-block; width: 300px;">
<input type="text" name="reason_3" placeholder="请输入原因/备注" class="layui-input" disabled>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</script>
<script>
var debug = layui.setter.debug;
layui.data.sendParams = function (d) {
//开启调试情况下获取接口赋值数据
if (debug) { console.log(d.params.data); }
layui.use(['admin', 'form', 'element', 'coreHelper', 'layer'],
function () {
var $ = layui.$
, form = layui.form
, element = layui.element
, admin = layui.admin
, coreHelper = layui.coreHelper
, layer = layui.layer;
var params = d.params.data;
var dateStr = params.dateStr;
var selectedRoomId = params.selectedRoomId;
var renderCalendar = params.renderCalendar;
var refreshSingleDay = params.refreshSingleDay; // 刷新单个日期的函数
// 存储已禁用的记录ID用于取消禁用
var unavailableRecords = {};
// 存储原始数据,用于对比是否有变化
var originalData = {};
// 切换时段表单元素的启用/禁用状态
function toggleSlotForm(slotType, enabled) {
var slotItem = $('.time-slot-item[data-slot="' + slotType + '"]');
var typeRadios = slotItem.find('input[name="type_' + slotType + '"]');
var reasonInput = slotItem.find('input[name="reason_' + slotType + '"]');
if (enabled) {
typeRadios.prop('disabled', false);
reasonInput.prop('disabled', false);
} else {
typeRadios.prop('disabled', true);
reasonInput.prop('disabled', true);
}
form.render('radio', 'setUnavailableForm');
}
// 更新时段状态显示
function updateSlotStatus(slotType, item) {
var slotItem = $('.time-slot-item[data-slot="' + slotType + '"]');
var switchInput = slotItem.find('input[name="switch_' + slotType + '"]');
if (item) {
// 已禁用,打开开关
switchInput.prop('checked', true);
// 保存记录ID
slotItem.find('input[name="slot_id_' + slotType + '"]').val(item.id);
unavailableRecords[slotType] = item.id;
// 保存原始数据用于对比
originalData[slotType] = {
type: item.type,
reason: item.reason || '',
enabled: true
};
// 启用表单元素
toggleSlotForm(slotType, true);
} else {
// 未禁用,关闭开关
switchInput.prop('checked', false);
slotItem.find('input[name="slot_id_' + slotType + '"]').val('');
delete unavailableRecords[slotType];
originalData[slotType] = {
type: null,
reason: '',
enabled: false
};
// 禁用表单元素
toggleSlotForm(slotType, false);
}
form.render('checkbox', 'setUnavailableForm');
}
// 开关切换事件
form.on('switch(slot-switch)', function(data) {
var slotType = parseInt(data.elem.name.replace('switch_', ''));
var isChecked = data.elem.checked;
var slotItem = $('.time-slot-item[data-slot="' + slotType + '"]');
toggleSlotForm(slotType, isChecked);
// 如果关闭开关,清空类型和原因
if (!isChecked) {
slotItem.find('input[name="type_' + slotType + '"][value="1"]').prop('checked', true);
slotItem.find('input[name="reason_' + slotType + '"]').val('');
form.render('radio', 'setUnavailableForm');
}
});
// 加载该日期的禁用记录
coreHelper.Get("Api/SQRoomPricing/GetRoomUnavailableList?roomId=" + selectedRoomId + "&date=" + encodeURIComponent(dateStr), function(e) {
if (e.code === 0 && e.data) {
// 初始化所有时段为未禁用状态
for (var i = 0; i <= 3; i++) {
updateSlotStatus(i, null);
}
// 遍历禁用记录,填充到对应的时段
if (e.data && e.data.length > 0) {
layui.each(e.data, function(index, item) {
var slotType = item.time_slot_type;
if (slotType !== null && slotType !== undefined && slotType >= 0 && slotType <= 3) {
// 设置类型单选框
var typeRadio = $('input[name="type_' + slotType + '"][value="' + item.type + '"]');
if (typeRadio.length > 0) {
typeRadio.prop('checked', true);
}
// 设置原因
var reasonInput = $('input[name="reason_' + slotType + '"]');
if (reasonInput.length > 0) {
reasonInput.val(item.reason || '');
}
// 更新状态显示
updateSlotStatus(slotType, item);
}
});
}
}
//重载form
form.render('radio', 'setUnavailableForm');
form.render('checkbox', 'setUnavailableForm');
});
// 保存提交处理函数到全局,供弹窗的确定按钮调用
window._setUnavailableSubmitHandler = function(layero, index) {
var saveTasks = [];
var cancelTasks = [];
var hasChanges = false;
// 遍历所有4个时段收集需要保存或取消的数据
for (var slotType = 0; slotType <= 3; slotType++) {
var switchChecked = layero.find('input[name="switch_' + slotType + '"]').prop('checked');
var slotId = layero.find('input[name="slot_id_' + slotType + '"]').val();
var original = originalData[slotType] || { type: null, reason: '', enabled: false };
if (switchChecked) {
// 开关开启,需要设置禁用
var type = parseInt(layero.find('input[name="type_' + slotType + '"]:checked').val());
var reason = (layero.find('input[name="reason_' + slotType + '"]').val() || '').trim();
// 判断是否需要保存(新增或修改)
var needSave = false;
if (slotId) {
// 已禁用状态,检查是否有修改
if (original.type !== type || original.reason !== reason) {
needSave = true;
}
} else {
// 未禁用状态,需要新增
needSave = true;
}
if (needSave) {
hasChanges = true;
saveTasks.push({
slotType: slotType,
type: type,
reason: reason
});
}
} else {
// 开关关闭,需要取消禁用
if (slotId) {
hasChanges = true;
cancelTasks.push({
slotType: slotType,
slotId: parseInt(slotId)
});
}
}
}
if (!hasChanges) {
layer.msg('没有需要保存的更改');
return;
}
// 显示加载提示
var loadIndex = layer.load(1, {shade: [0.1,'#fff']});
var completedCount = 0;
var totalTasks = saveTasks.length + cancelTasks.length;
var hasError = false;
var errorMsg = '';
// 依次执行保存和取消任务
function executeNext() {
if (completedCount >= totalTasks) {
layer.close(loadIndex);
if (hasError) {
layer.msg(errorMsg || '部分操作失败');
} else {
layer.close(index);
layer.msg('保存成功');
// 优先使用刷新单个日期,如果没有则刷新整个日历
if (refreshSingleDay && typeof refreshSingleDay === 'function') {
refreshSingleDay(dateStr); // 只刷新当前日期
} else if (renderCalendar && typeof renderCalendar === 'function') {
renderCalendar(); // 刷新整个日历(兼容旧逻辑)
}
}
return;
}
// 先执行取消任务,再执行保存任务
if (completedCount < cancelTasks.length) {
var cancelTask = cancelTasks[completedCount];
coreHelper.Post("Api/SQRoomPricing/CancelRoomUnavailable", {
ids: [cancelTask.slotId]
}, function(e) {
completedCount++;
if (e.code !== 0) {
hasError = true;
errorMsg = e.msg || '取消失败';
}
executeNext();
});
} else {
var saveTask = saveTasks[completedCount - cancelTasks.length];
coreHelper.Post("Api/SQRoomPricing/SetRoomUnavailable", {
roomId: selectedRoomId,
date: dateStr,
timeSlotType: saveTask.slotType,
type: saveTask.type,
reason: saveTask.reason
}, function(e) {
completedCount++;
if (e.code !== 0) {
hasError = true;
errorMsg = e.msg || '保存失败';
}
executeNext();
});
}
}
// 开始执行
executeNext();
};
})
};
</script>