532 lines
18 KiB
C#
532 lines
18 KiB
C#
using DocumentFormat.OpenXml.EMMA;
|
|
using DocumentFormat.OpenXml.Office.CustomUI;
|
|
using DocumentFormat.OpenXml.Wordprocessing;
|
|
using Microsoft.AspNet.SignalR;
|
|
using Model;
|
|
using Org.BouncyCastle.Asn1.Ocsp;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data.Entity;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using System.Web.Http;
|
|
|
|
/// <summary>
|
|
/// regionRoomBedController 的摘要描述
|
|
/// </summary>
|
|
[ezAuthorize]
|
|
public class regionRoomBedController : ApiController
|
|
{
|
|
private Model.ezEntities _db = new Model.ezEntities();
|
|
public regionRoomBedController()
|
|
{
|
|
//
|
|
// TODO: 在這裡新增建構函式邏輯
|
|
//
|
|
}
|
|
[HttpGet]
|
|
[Route("api/region/room/bed/list")]
|
|
public IHttpActionResult GetRegionRoomBedListByRoomId(Guid? roomUuid, DateTime StartTime, DateTime? EndTime)
|
|
{
|
|
if (StartTime == null || EndTime == null)
|
|
return BadRequest("时间不能为空");
|
|
|
|
if (roomUuid == null)
|
|
return BadRequest("roomId不能为空");
|
|
|
|
// 先取出床位
|
|
var beds = _db.RegionRoomBed
|
|
.Where(a => a.RoomUuid == roomUuid)
|
|
.ToList();
|
|
|
|
StartTime = StartTime.Date;
|
|
EndTime = EndTime?.Date;
|
|
|
|
var data = beds.Select(a =>
|
|
{
|
|
var bedSchedules = _db.RegionAndRoomAndBedSchedule
|
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403")
|
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "404")
|
|
.Where(b => b.TargetUuid == a.Uuid
|
|
&& (b.ScheduleDate == null
|
|
|| (b.ScheduleDate >= StartTime && b.ScheduleDate < EndTime)))
|
|
.ToList()
|
|
.Select(c => new
|
|
{
|
|
c.Uuid,
|
|
c.Description,
|
|
c.IsDeleted,
|
|
c.GuaDanOrderNo,
|
|
c.UseType,
|
|
c.Title,
|
|
c.TargetUuid,
|
|
scheduledate = c.ScheduleDate,
|
|
})
|
|
.ToList();
|
|
|
|
bool canUsed = !bedSchedules.Any();
|
|
bool bedIsStop = IsBedStopped(a);
|
|
return new
|
|
{
|
|
a.Uuid,
|
|
a.Name,
|
|
a.Gender,
|
|
a.IsActive,
|
|
a.StatusCode,
|
|
a.RoomUuid,
|
|
canUsed,
|
|
bedIsStop,
|
|
schedule = bedSchedules
|
|
};
|
|
});
|
|
|
|
|
|
return Ok(data);
|
|
}
|
|
public bool IsBedStopped(RegionRoomBed bed)
|
|
{
|
|
// 1️⃣ 床位本身不可用
|
|
if (!bed.IsActive || bed.IsDeleted)
|
|
return true;
|
|
|
|
// 2️⃣ 所属房间不可用
|
|
var room = bed.Room;
|
|
if (room == null || !room.IsActive.Value || room.IsDeleted)
|
|
return true;
|
|
|
|
// 3️⃣ 所属区域不可用
|
|
var region = room.Region;
|
|
while (region != null)
|
|
{
|
|
if (!region.IsActive || region.IsDeleted)
|
|
return true; // 有任意一级区域不可用就返回 true
|
|
|
|
if (!region.ParentUuid.HasValue)
|
|
break; // 到顶层了
|
|
|
|
region = _db.Region.FirstOrDefault(r => r.Uuid == region.ParentUuid.Value);
|
|
}
|
|
|
|
// 4️⃣ 全部检查通过 → 床位可用
|
|
return false;
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("api/region/bed/create")]
|
|
public IHttpActionResult CreateBed([FromBody] RegionRoomBed bed)
|
|
{
|
|
var room = _db.Room.Find(bed.RoomUuid);
|
|
if (room == null)
|
|
{
|
|
return BadRequest("當前客房不存在");
|
|
}
|
|
if (room.Gender != bed.Gender)
|
|
{
|
|
return BadRequest("床為性別和房間性別必須一致");
|
|
}
|
|
if (room.BedCount != null && room.BedCount < room.RegionRoomBed.Count() + 1)
|
|
{
|
|
return BadRequest("該客房床位已滿");
|
|
}
|
|
var regionBed = new RegionRoomBed
|
|
{
|
|
Name = bed.Name,
|
|
RoomUuid = bed.RoomUuid,
|
|
StatusCode = bed.StatusCode,
|
|
IsActive = bed.IsActive,
|
|
Gender = bed.Gender,
|
|
Uuid = Guid.NewGuid(),
|
|
};
|
|
_db.RegionRoomBed.Add(regionBed);
|
|
_db.SaveChanges();
|
|
|
|
//創建床位
|
|
return Ok(new
|
|
{
|
|
uuid = regionBed.Uuid,
|
|
roomUuid = regionBed.RoomUuid,
|
|
statuscode = regionBed.StatusCode,
|
|
isactive = regionBed.IsActive,
|
|
gender = regionBed.Gender,
|
|
name = regionBed.Name,
|
|
});
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("api/region/bed/update")]
|
|
public IHttpActionResult UpdateBed([FromBody] RegionRoomBed bed)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(bed.Name))
|
|
{
|
|
return BadRequest("床位名稱不可為空");
|
|
}
|
|
var oldBed = _db.RegionRoomBed.Find(bed.Uuid);
|
|
if (oldBed == null)
|
|
{
|
|
return BadRequest("更新失敗,床位不存在");
|
|
}
|
|
var room = _db.Room.Find(bed.RoomUuid);
|
|
if (room == null)
|
|
{
|
|
return BadRequest("當前客房不存在");
|
|
}
|
|
if (room.Gender != bed.Gender)
|
|
{
|
|
return BadRequest("床為性別和房間性別必須一致");
|
|
}
|
|
if (bed.IsActive == false)
|
|
{
|
|
var hasPendingBeds = oldBed.GuaDanOrderGuest.Any(g => !g.IsDeleted &&
|
|
(g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_BOOKED || // 预约中
|
|
g.RegionRoomBedStatus.Code == GuaDanOrderGuest.STATUS_CHECKED_IN));
|
|
if (hasPendingBeds)
|
|
{
|
|
return Content(HttpStatusCode.BadRequest, new
|
|
{
|
|
code = "BED_IS_USED",
|
|
message = "該床位正在掛單中,請先處理"
|
|
});
|
|
}
|
|
}
|
|
oldBed.StatusCode = bed.StatusCode;
|
|
oldBed.IsActive = bed.IsActive;
|
|
oldBed.Name = bed.Name;
|
|
oldBed.Gender = bed.Gender;
|
|
_db.SaveChanges();
|
|
|
|
//創建床位
|
|
return Ok(new { message = "床位更新成功" });
|
|
}
|
|
[HttpPost]
|
|
[Route("api/region/bed/delete")]
|
|
public IHttpActionResult Delete([FromUri] Guid uuid)
|
|
{
|
|
var bed = _db.RegionRoomBed.Find(uuid);
|
|
if (bed == null)
|
|
{
|
|
return BadRequest("未找到床位");
|
|
}
|
|
|
|
try
|
|
{
|
|
_db.RegionRoomBed.Remove(bed);
|
|
_db.SaveChanges();
|
|
return Ok(new { message = "刪除成功" });
|
|
}
|
|
catch (System.Data.Entity.Infrastructure.DbUpdateException ex)
|
|
{
|
|
// 判斷是否為外鍵關聯錯誤
|
|
if (ex.InnerException?.InnerException is System.Data.SqlClient.SqlException sqlEx &&
|
|
(sqlEx.Number == 547)) // 547 = SQL Server 外鍵違反錯誤碼
|
|
{
|
|
return BadRequest("刪除失敗:該床位已被使用或存在關聯資料,無法刪除。");
|
|
}
|
|
|
|
return InternalServerError(ex); // 其他資料庫錯誤
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return InternalServerError(ex); // 其他未預期錯誤
|
|
}
|
|
}
|
|
|
|
|
|
[HttpGet]
|
|
[Route("api/region/bed/getavailablebedcountbytime")]
|
|
public async Task<IHttpActionResult> GetCanUseBedCountByTime(DateTime startTime, DateTime endTime)
|
|
{
|
|
//获取某个时间段内可用床位数量
|
|
var start = startTime.Date;
|
|
var end = endTime.Date;
|
|
|
|
// 找出所有在日期範圍內被占用的床位
|
|
var busyBedUuids = await _db.RegionAndRoomAndBedSchedule
|
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "403")
|
|
.Where(s => s.GuaDanOrderGuest.StatusCode != "404")
|
|
.Where(a => a.IsCancel == false)
|
|
.Where(s => s.IsDeleted == false
|
|
&& (s.ScheduleDate == null // 長期占用
|
|
|| (s.ScheduleDate >= start && s.ScheduleDate < end)))
|
|
.Select(s => s.TargetUuid)
|
|
.Distinct()
|
|
.ToListAsync();
|
|
|
|
// 可用床位 = 所有床位 - 忙碌床位
|
|
var availableBeds = _db.RegionRoomBed
|
|
.Where(b => b.IsActive)
|
|
.Where(b => !busyBedUuids.Contains(b.Uuid));
|
|
|
|
var result = await availableBeds
|
|
.GroupBy(b => b.Gender)
|
|
.Select(g => new
|
|
{
|
|
Gender = g.Key,
|
|
Count = g.Count()
|
|
})
|
|
.ToListAsync();
|
|
|
|
var male = result.Where(r => r.Gender == true).Select(r => r.Count).FirstOrDefault();
|
|
var female = result.Where(r => r.Gender == false).Select(r => r.Count).FirstOrDefault();
|
|
return Ok(new {male, female});
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("api/region/bed/preallocation")]
|
|
public async Task<IHttpActionResult> PreAutoAllocationBed([FromBody] ConfirmAllocationRequest request)
|
|
{
|
|
DateTime allocationStart = request.CheckInAt;
|
|
DateTime? allocationEnd = request.CheckOutAt;
|
|
bool isAllallocation = true; //是否全部分配完毕
|
|
// 获取可用床位列表
|
|
var availableBeds = await RegionAndRoomAndBedSchedule.GetAvailableBedsAsync(_db, allocationStart, allocationEnd);
|
|
|
|
// 将床位按房间分组
|
|
var roomGroups = availableBeds
|
|
.GroupBy(b => b.RoomUuid)
|
|
.Select(g => new
|
|
{
|
|
RoomUuid = g.Key,
|
|
Beds = g.ToList(),
|
|
Gender = g.First().Room.Gender // bool,不可空
|
|
})
|
|
.ToList();
|
|
|
|
var data = new List<FollowerBedResponse>();
|
|
|
|
// 按性别分组请求
|
|
var maleFollowers = request.PreBeds.Where(f => f.sex == "M").ToList();
|
|
var femaleFollowers = request.PreBeds.Where(f => f.sex == "F").ToList();
|
|
|
|
void AllocateByGender(List<FollowerBedResponse> followers, bool isMale)
|
|
{
|
|
var rooms = roomGroups.Where(r => r.Gender == isMale).ToList();
|
|
int remaining = followers.Count;
|
|
int index = 0;
|
|
|
|
while (remaining > 0 && rooms.Any(r => r.Beds.Count > 0))
|
|
{
|
|
// 找能容纳所有人的房间
|
|
var fullRoom = rooms
|
|
.Where(r => r.Beds.Count >= remaining)
|
|
.OrderBy(r => r.Beds.Count - remaining) // 分配后剩余床位最少优先
|
|
.FirstOrDefault();
|
|
|
|
if (fullRoom != null)
|
|
{
|
|
// 分配所有剩余人员
|
|
for (int i = index; i < followers.Count; i++)
|
|
{
|
|
var follower = followers[i];
|
|
var bed = fullRoom.Beds.First();
|
|
data.Add(new FollowerBedResponse
|
|
{
|
|
num = follower.num,
|
|
sex = follower.sex,
|
|
bedUuid = bed.Uuid
|
|
});
|
|
fullRoom.Beds.Remove(bed);
|
|
remaining--;
|
|
index++;
|
|
}
|
|
break; // 全部分配完
|
|
}
|
|
else
|
|
{
|
|
// 找剩余床位最多的房间
|
|
var room = rooms.OrderByDescending(r => r.Beds.Count).First();
|
|
int toAssign = Math.Min(remaining, room.Beds.Count);
|
|
|
|
for (int i = 0; i < toAssign; i++)
|
|
{
|
|
var follower = followers[index++];
|
|
var bed = room.Beds.First();
|
|
data.Add(new FollowerBedResponse
|
|
{
|
|
num = follower.num,
|
|
sex = follower.sex,
|
|
bedUuid = bed.Uuid
|
|
});
|
|
room.Beds.Remove(bed);
|
|
remaining--;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (index < followers.Count)
|
|
{
|
|
isAllallocation = false;
|
|
return;
|
|
}
|
|
// 剩余无法分配的人员
|
|
for (int i = index; i < followers.Count; i++)
|
|
{
|
|
|
|
data.Add(new FollowerBedResponse
|
|
{
|
|
num = followers[i].num,
|
|
sex = followers[i].sex,
|
|
bedUuid = null
|
|
});
|
|
}
|
|
}
|
|
|
|
// 先分配男生,再分配女生
|
|
AllocateByGender(maleFollowers, true);
|
|
if (!isAllallocation)
|
|
{
|
|
return BadRequest("分配失敗,床位不足");
|
|
}
|
|
AllocateByGender(femaleFollowers, false);
|
|
if (!isAllallocation)
|
|
{
|
|
return BadRequest("分配失敗,床位不足");
|
|
}
|
|
|
|
return Ok(new { message = "預分配成功", data });
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("api/region/bed/confirmallocation")]
|
|
public async Task<IHttpActionResult> ConfirmAutoAllocationBed([FromBody] ConfirmAllocationRequest request)
|
|
{
|
|
if (request?.PreBeds == null || !request.PreBeds.Any())
|
|
return BadRequest("请求床位不能为空");
|
|
|
|
using (var transaction = _db.Database.BeginTransaction())
|
|
{
|
|
try
|
|
{
|
|
DateTime allocationStart = request.CheckInAt.Date; // 保證時間清零
|
|
DateTime? allocationEnd = request.CheckOutAt?.Date;
|
|
|
|
foreach (var req in request.PreBeds)
|
|
{
|
|
if (req.bedUuid != null)
|
|
{
|
|
// 先拉出床位相關排程到內存,避免 EF 不支援 .Date
|
|
var schedules = _db.RegionAndRoomAndBedSchedule
|
|
.Where(s => s.IsDeleted == false && !s.IsCancel && s.TargetUuid == req.bedUuid)
|
|
.ToList();
|
|
|
|
bool conflictExists = schedules.Any(s =>
|
|
s.ScheduleDate == null // 長期占用
|
|
|| (allocationEnd.HasValue
|
|
? (s.ScheduleDate >= allocationStart && s.ScheduleDate <= allocationEnd.Value)
|
|
: s.ScheduleDate >= allocationStart)
|
|
);
|
|
|
|
if (conflictExists)
|
|
{
|
|
transaction.Rollback();
|
|
return BadRequest($"床位 {req.bedUuid} 在时间段内已被占用,分配失败");
|
|
}
|
|
}
|
|
|
|
// 找到房間 UUID
|
|
Guid? roomUuid = null;
|
|
if (req.bedUuid != null)
|
|
{
|
|
var bed = _db.RegionRoomBed.Find(req.bedUuid);
|
|
if (bed != null)
|
|
roomUuid = bed.RoomUuid;
|
|
}
|
|
|
|
// 新增挂单入住客人记录
|
|
var guest = new GuaDanOrderGuest
|
|
{
|
|
GuaDanOrderNo = request.OrderNo,
|
|
FollowerNum = req.num,
|
|
BedUuid = req.bedUuid,
|
|
Uuid = Guid.NewGuid(),
|
|
RoomUuid = roomUuid,
|
|
CheckInAt = allocationStart,
|
|
CheckOutAt = allocationEnd,
|
|
StatusCode = "401",
|
|
};
|
|
_db.GuaDanOrderGuest.Add(guest);
|
|
|
|
// 新增每日排程
|
|
if (allocationEnd.HasValue)
|
|
{
|
|
for (var date = allocationStart; date < allocationEnd.Value; date = date.AddDays(1))
|
|
{
|
|
var newSchedule = new RegionAndRoomAndBedSchedule
|
|
{
|
|
Uuid = Guid.NewGuid(),
|
|
TargetUuid = req.bedUuid,
|
|
ScheduleDate = date,
|
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
|
IsDeleted = false,
|
|
CreatedBy = "系统自动分配",
|
|
CreatedAt = DateTime.Now,
|
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
|
Title = "掛單",
|
|
GuaDanOrderGuestUuid = guest.Uuid,
|
|
};
|
|
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 長期占用
|
|
var newSchedule = new RegionAndRoomAndBedSchedule
|
|
{
|
|
Uuid = Guid.NewGuid(),
|
|
TargetUuid = req.bedUuid,
|
|
ScheduleDate = null,
|
|
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
|
|
IsDeleted = false,
|
|
CreatedBy = "系统自动分配",
|
|
CreatedAt = DateTime.Now,
|
|
GuaDanOrderNo = guest.GuaDanOrderNo,
|
|
Title = "掛單",
|
|
GuaDanOrderGuestUuid = guest.Uuid,
|
|
};
|
|
_db.RegionAndRoomAndBedSchedule.Add(newSchedule);
|
|
}
|
|
}
|
|
|
|
await _db.SaveChangesAsync();
|
|
transaction.Commit();
|
|
|
|
return Ok(new { message = "分配成功" });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
transaction.Rollback();
|
|
return InternalServerError(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
private bool BedIsCanUsed(RegionRoomBed bed, DateTime? StartTime, DateTime? EndTime)
|
|
{
|
|
if (!bed.IsActive)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
public class FollowerBedRequest
|
|
{
|
|
public int num { get; set; }
|
|
public string sex { get; set; }
|
|
}
|
|
|
|
public class FollowerBedResponse
|
|
{
|
|
public int num { get; set; }
|
|
public string sex { get; set; }
|
|
public Guid? bedUuid { get; set; } = null;
|
|
public string bedName { get; set; }
|
|
}
|
|
public class ConfirmAllocationRequest
|
|
{
|
|
public List<FollowerBedResponse> PreBeds { get; set; }
|
|
public string OrderNo { get; set; }
|
|
public DateTime CheckInAt { get; set; }
|
|
public DateTime? CheckOutAt { get; set; }
|
|
}
|
|
} |