468 lines
16 KiB
C#
468 lines
16 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.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();
|
||
|
||
return new
|
||
{
|
||
a.Uuid,
|
||
a.Name,
|
||
a.Gender,
|
||
a.IsActive,
|
||
a.StatusCode,
|
||
a.RoomUuid,
|
||
canUsed,
|
||
schedule = bedSchedules
|
||
};
|
||
});
|
||
|
||
|
||
return Ok(data);
|
||
}
|
||
|
||
[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("床為性別和房間性別必須一致");
|
||
}
|
||
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("未找到床位");
|
||
}
|
||
_db.RegionRoomBed.Remove(bed);
|
||
_db.SaveChanges();
|
||
return Ok(new { message = "刪除成功" });
|
||
}
|
||
|
||
[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 => !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; }
|
||
}
|
||
} |