掛單管理
This commit is contained in:
1 parent
8db6019ba3
commit
9e251fc7d4
12 files changed
+2179
-98
No files matched your search
@@ -0,0 +1,16 @@
|
|||||||
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddCors(p => p.AddDefaultPolicy(b => b.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
|
||||||
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
|
var app = builder.Build();
|
||||||
|
if (app.Environment.IsDevelopment()) app.UseDeveloperExceptionPage();
|
||||||
|
app.UseCors();
|
||||||
|
app.UseSwagger();
|
||||||
|
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json","MyApi v1"));
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
app.UseAuthorization();
|
||||||
|
app.MapControllers();
|
||||||
|
app.Run();
|
||||||
@@ -2047,6 +2047,7 @@ namespace Model
|
|||||||
public System.Guid Uuid { get; set; }
|
public System.Guid Uuid { get; set; }
|
||||||
public System.Guid RoomUuid { get; set; }
|
public System.Guid RoomUuid { get; set; }
|
||||||
public string StatusCode { get; set; }
|
public string StatusCode { get; set; }
|
||||||
|
public string Limits { get; set; }
|
||||||
|
|
||||||
public virtual Room Room { get; set; }
|
public virtual Room Room { get; set; }
|
||||||
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
public virtual RegionRoomBedStatus RegionRoomBedStatus { get; set; }
|
||||||
|
|||||||
@@ -1202,6 +1202,7 @@
|
|||||||
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
<Property Name="Uuid" Type="uniqueidentifier" Nullable="false" />
|
||||||
<Property Name="RoomUuid" Type="uniqueidentifier" Nullable="false" />
|
<Property Name="RoomUuid" Type="uniqueidentifier" Nullable="false" />
|
||||||
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
<Property Name="StatusCode" Type="nvarchar" MaxLength="20" Nullable="false" />
|
||||||
|
<Property Name="Limits" Type="varchar(max)" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBedStatus">
|
<EntityType Name="RegionRoomBedStatus">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -5507,6 +5508,7 @@
|
|||||||
<NavigationProperty Name="Room" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="RegionRoomBed" ToRole="Room" />
|
<NavigationProperty Name="Room" Relationship="Model.FK_RegionRoomBed_RoomUuid" FromRole="RegionRoomBed" ToRole="Room" />
|
||||||
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_RegionRoomBed_StatusCode" FromRole="RegionRoomBed" ToRole="RegionRoomBedStatus" />
|
<NavigationProperty Name="RegionRoomBedStatus" Relationship="Model.FK_RegionRoomBed_StatusCode" FromRole="RegionRoomBed" ToRole="RegionRoomBedStatus" />
|
||||||
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="RegionRoomBed" ToRole="GuaDanOrderGuest" />
|
<NavigationProperty Name="GuaDanOrderGuest" Relationship="Model.FK_GuaDanOrderGuest_BedUuid" FromRole="RegionRoomBed" ToRole="GuaDanOrderGuest" />
|
||||||
|
<Property Name="Limits" Type="String" MaxLength="Max" FixedLength="false" Unicode="false" />
|
||||||
</EntityType>
|
</EntityType>
|
||||||
<EntityType Name="RegionRoomBedStatus">
|
<EntityType Name="RegionRoomBedStatus">
|
||||||
<Key>
|
<Key>
|
||||||
@@ -7277,6 +7279,7 @@
|
|||||||
<EntitySetMapping Name="RegionRoomBed">
|
<EntitySetMapping Name="RegionRoomBed">
|
||||||
<EntityTypeMapping TypeName="Model.RegionRoomBed">
|
<EntityTypeMapping TypeName="Model.RegionRoomBed">
|
||||||
<MappingFragment StoreEntitySet="RegionRoomBed">
|
<MappingFragment StoreEntitySet="RegionRoomBed">
|
||||||
|
<ScalarProperty Name="Limits" ColumnName="Limits" />
|
||||||
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
<ScalarProperty Name="StatusCode" ColumnName="StatusCode" />
|
||||||
<ScalarProperty Name="RoomUuid" ColumnName="RoomUuid" />
|
<ScalarProperty Name="RoomUuid" ColumnName="RoomUuid" />
|
||||||
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
<ScalarProperty Name="Uuid" ColumnName="Uuid" />
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
|||||||
using System.Data.Entity;
|
using System.Data.Entity;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.util.collections;
|
||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Web.Http;
|
using System.Web.Http;
|
||||||
using static Model.admin_log;
|
using static Model.admin_log;
|
||||||
@@ -110,6 +111,114 @@ public class guadanOrderController : ApiController
|
|||||||
data
|
data
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadan/getorderbyuuid")]
|
||||||
|
public async Task<IHttpActionResult> getGuadanOrderByUuid([FromBody] dynamic req)
|
||||||
|
{
|
||||||
|
if (!Guid.TryParse((string)req.uuid, out Guid targetGuid))
|
||||||
|
{
|
||||||
|
return BadRequest("無效的 GUID 格式");
|
||||||
|
}
|
||||||
|
var order = await _db.GuaDanOrder
|
||||||
|
.Where(a => a.Uuid == targetGuid)
|
||||||
|
.Where(a => a.IsCancel == false && a.IsDeleted == false)
|
||||||
|
.FirstOrDefaultAsync();
|
||||||
|
if (order == null)
|
||||||
|
{
|
||||||
|
return BadRequest("未找到對應掛單資料");
|
||||||
|
}
|
||||||
|
// 1. 先把全台/全區的 Region 載入記憶體做成字典,方便 GetParentPath 快速查找
|
||||||
|
var regionDict = _db.Region.ToDictionary(r => r.Uuid);
|
||||||
|
|
||||||
|
// 2. 修改你的 GetParentPath 邏輯(改用高效的 while 迴圈)
|
||||||
|
List<string> GetRegionPathNames(Guid? startRegionUuid)
|
||||||
|
{
|
||||||
|
var pathNames = new List<string>();
|
||||||
|
Guid? nextId = startRegionUuid;
|
||||||
|
|
||||||
|
while (nextId.HasValue && regionDict.TryGetValue(nextId.Value, out var reg))
|
||||||
|
{
|
||||||
|
pathNames.Add(reg.Name); // 收集區域名稱
|
||||||
|
nextId = reg.ParentUuid; // 假設你的欄位叫 ParentUuid,請依實際欄位修改
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反轉順序讓它變成:[大區域, 中區域, 小區域]
|
||||||
|
pathNames.Reverse();
|
||||||
|
return pathNames;
|
||||||
|
}
|
||||||
|
var result = new
|
||||||
|
{
|
||||||
|
order_form = new
|
||||||
|
{
|
||||||
|
order.admin,
|
||||||
|
order.followers,
|
||||||
|
startdate = order.StartDate?.ToString("yyyy-MM-dd"),
|
||||||
|
enddate = order.EndDate?.ToString("yyyy-MM-dd"),
|
||||||
|
order.CreateUser,
|
||||||
|
order.CreatedAt,
|
||||||
|
order.UpdatedAt,
|
||||||
|
note = order.Notes,
|
||||||
|
orderNo = order.GuaDanOrderNo,
|
||||||
|
order.BookerFollowerNum,
|
||||||
|
bookerName = order.BookerName,
|
||||||
|
bookerPhone = order.BookerPhone,
|
||||||
|
order.IsDeleted,
|
||||||
|
uuid = order.Uuid,
|
||||||
|
activityNum = order.ActivityNum,
|
||||||
|
},
|
||||||
|
details = _db.GuaDanOrderGuest
|
||||||
|
.Where(g => g.GuaDanOrderNo == order.GuaDanOrderNo && g.IsDeleted == false)
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
g.Uuid,
|
||||||
|
g.GuaDanOrderNo,
|
||||||
|
g.RoomUuid,
|
||||||
|
g.BedUuid,
|
||||||
|
checkinat = g.CheckInAt,
|
||||||
|
checkoutat = g.CheckOutAt,
|
||||||
|
gender = g.Sex,
|
||||||
|
specialNeeds = g.Handi,
|
||||||
|
name = g.Name,
|
||||||
|
statuscode = g.StatusCode,
|
||||||
|
g.FollowerNum,
|
||||||
|
bedName = _db.RegionRoomBed.Where(b => b.Uuid == g.BedUuid).Select(b => b.Name).FirstOrDefault(),
|
||||||
|
// 先把資料庫能查的查出來
|
||||||
|
roomRaw = _db.Room.Where(r => r.Uuid == g.RoomUuid).Select(r => new
|
||||||
|
{
|
||||||
|
r.Name,
|
||||||
|
r.RegionUuid
|
||||||
|
}).FirstOrDefault()
|
||||||
|
}).AsEnumerable() // 🔥 關鍵:從這裡切斷,後面的 Select 會在 C# 記憶體內執行
|
||||||
|
.Select(g => new
|
||||||
|
{
|
||||||
|
g.Uuid,
|
||||||
|
g.GuaDanOrderNo,
|
||||||
|
g.RoomUuid,
|
||||||
|
g.BedUuid,
|
||||||
|
g.checkinat,
|
||||||
|
g.checkoutat,
|
||||||
|
g.gender,
|
||||||
|
g.specialNeeds,
|
||||||
|
g.name,
|
||||||
|
g.statuscode,
|
||||||
|
g.FollowerNum,
|
||||||
|
g.bedName,
|
||||||
|
room = g.roomRaw == null ? null : new
|
||||||
|
{
|
||||||
|
g.roomRaw.Name,
|
||||||
|
g.roomRaw.RegionUuid,
|
||||||
|
// 在記憶體中,這時候可以直接查字典拿到當前區域名稱
|
||||||
|
regionName = regionDict.TryGetValue(g.roomRaw.RegionUuid, out var r) ? r.Name : null,
|
||||||
|
// 🔥 這時候呼叫區域函式就不會報錯了!
|
||||||
|
resion = GetRegionPathNames(g.roomRaw.RegionUuid)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.ToList()
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(result);
|
||||||
|
}
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
[Route("api/guadan/getorderbyid")]
|
[Route("api/guadan/getorderbyid")]
|
||||||
public async Task<IHttpActionResult> getGuadanOrderById(string orderId)
|
public async Task<IHttpActionResult> getGuadanOrderById(string orderId)
|
||||||
@@ -187,12 +296,53 @@ public class guadanOrderController : ApiController
|
|||||||
return Ok(guadanorder);
|
return Ok(guadanorder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadan/changeGuadanGuest")]
|
||||||
|
public async Task<IHttpActionResult> ChangeGuadanGuest([FromBody] dynamic req)
|
||||||
|
{
|
||||||
|
var json = req;
|
||||||
|
if (json != null && json.guest != null)
|
||||||
|
{
|
||||||
|
var guest = json.guest;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpPost]
|
||||||
|
[Route("api/guadan/updateGandan")]
|
||||||
|
public async Task<IHttpActionResult> UpdateGandan([FromBody] dynamic req)
|
||||||
|
{
|
||||||
|
var json = req;
|
||||||
|
if (json != null && json.order != null)
|
||||||
|
{
|
||||||
|
var order = json.order;
|
||||||
|
string guadanOrderNo = order.GuaDanOrderNo;
|
||||||
|
var oldOrder = _db.GuaDanOrder.Where(a => a.GuaDanOrderNo == guadanOrderNo).FirstOrDefault();
|
||||||
|
if (oldOrder == null)
|
||||||
|
{
|
||||||
|
return BadRequest("未找到對應掛單資料");
|
||||||
|
}
|
||||||
|
|
||||||
|
oldOrder.StartDate = order.startdate;
|
||||||
|
oldOrder.EndDate = order.enddate;
|
||||||
|
oldOrder.UpdatedAt = DateTime.Now;
|
||||||
|
oldOrder.Notes = order.note;
|
||||||
|
oldOrder.BookerName = order.bookerName;
|
||||||
|
oldOrder.BookerPhone = order.bookerPhone;
|
||||||
|
await _db.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
return Ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[HttpPost]
|
[HttpPost]
|
||||||
[Route("api/guadan/saveGandan")]
|
[Route("api/guadan/saveGandan")]
|
||||||
public async Task<IHttpActionResult> SaveGandan([FromBody] dynamic req)
|
public async Task<IHttpActionResult> SaveGandan([FromBody] dynamic req)
|
||||||
{
|
{
|
||||||
var json = req;
|
var json = req;
|
||||||
if (json != null&&json.order!=null) {
|
if (json != null && json.order != null)
|
||||||
|
{
|
||||||
var order = json.order;
|
var order = json.order;
|
||||||
if (string.IsNullOrEmpty(order.GuaDanOrderNo))
|
if (string.IsNullOrEmpty(order.GuaDanOrderNo))
|
||||||
{//表示新增掛單
|
{//表示新增掛單
|
||||||
@@ -255,7 +405,8 @@ public class guadanOrderController : ApiController
|
|||||||
if (!bedIsCanUse)
|
if (!bedIsCanUse)
|
||||||
return BadRequest("床位在該時間段內已被占用");
|
return BadRequest("床位在該時間段內已被占用");
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
return BadRequest("未設定床位");
|
return BadRequest("未設定床位");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,48 +441,6 @@ public class guadanOrderController : ApiController
|
|||||||
_db.RegionAndRoomAndBedSchedule.AddRange(bedList);
|
_db.RegionAndRoomAndBedSchedule.AddRange(bedList);
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{//表示更新掛單
|
|
||||||
var model =await _db.GuaDanOrder.FindAsync((string)order.Uuid);
|
|
||||||
if (model == null)
|
|
||||||
{
|
|
||||||
return BadRequest("未找到對應掛單資料");
|
|
||||||
}
|
|
||||||
model.StartDate = order.startdate;
|
|
||||||
model.EndDate = order.enddate;
|
|
||||||
model.Notes = order.note;
|
|
||||||
model.BookerName = order.bookerName;
|
|
||||||
model.BookerPhone = order.bookerPhone;
|
|
||||||
model.ActivityNum = order.activityNum;
|
|
||||||
|
|
||||||
//更新掛單明細...還要處理RegionAndRoomAndBedSchedule
|
|
||||||
}
|
|
||||||
//if (json.detail != null)
|
|
||||||
//{
|
|
||||||
// var details = json.detail;
|
|
||||||
// foreach (var detail in details)
|
|
||||||
// {
|
|
||||||
// var guadanDetail = new GuaDanOrderGuest
|
|
||||||
// {
|
|
||||||
// GuaDanOrderNo = order.GuaDanOrderNo,
|
|
||||||
// //FollowerNum = detail.guestName,
|
|
||||||
// Uuid = detail.uuid,
|
|
||||||
// StatusCode = "401", // 預約狀態
|
|
||||||
// RoomUuid = detail.roomUuid,
|
|
||||||
// BedUuid = detail.bedUuid,
|
|
||||||
// CheckInAt = detail.checkInAt,
|
|
||||||
// CheckOutAt = detail.checkOutAt,
|
|
||||||
// Sex = detail.gender,
|
|
||||||
// Handi = detail.handi,
|
|
||||||
// IsDeleted = false,
|
|
||||||
// Name = detail.name,
|
|
||||||
// };
|
|
||||||
// _db.GuaDanOrderGuest.Add(guadanDetail);
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// //return BadRequest("掛單資料不可為空");
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
return Ok();
|
return Ok();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -236,7 +236,7 @@ public class regionController : ApiController
|
|||||||
isactive = c.IsActive,
|
isactive = c.IsActive,
|
||||||
statuscode = c.StatusCode,
|
statuscode = c.StatusCode,
|
||||||
Gender = c.Gender,
|
Gender = c.Gender,
|
||||||
|
Limits=c.Limits,
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
|
|
||||||
}).ToList(),
|
}).ToList(),
|
||||||
@@ -349,6 +349,7 @@ public class regionController : ApiController
|
|||||||
public string statuscode { get; set; }
|
public string statuscode { get; set; }
|
||||||
public bool isactive { get; set; }
|
public bool isactive { get; set; }
|
||||||
public bool Gender { get; set; }
|
public bool Gender { get; set; }
|
||||||
|
public string Limits { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RegionDto
|
public class RegionDto
|
||||||
|
|||||||
@@ -195,6 +195,7 @@ public class regionRoomBedController : ApiController
|
|||||||
oldBed.IsActive = bed.IsActive;
|
oldBed.IsActive = bed.IsActive;
|
||||||
oldBed.Name = bed.Name;
|
oldBed.Name = bed.Name;
|
||||||
oldBed.Gender = bed.Gender;
|
oldBed.Gender = bed.Gender;
|
||||||
|
oldBed.Limits = bed.Limits;
|
||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
|
|
||||||
//創建床位
|
//創建床位
|
||||||
@@ -294,16 +295,84 @@ public class regionRoomBedController : ApiController
|
|||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// 空閒床位 = 所有床位 - 忙碌床位
|
// 1. 先把全台/全區的 Region 載入記憶體做成字典,方便 GetParentPath 快速查找
|
||||||
var availableBeds = _db.RegionRoomBed.Select(b=>new {
|
var regionDict = _db.Region.ToDictionary(r => r.Uuid);
|
||||||
b.Name ,b.Uuid,b.StatusCode,b.IsActive,
|
|
||||||
|
// 2. 修改你的 GetParentPath 邏輯(改用高效的 while 迴圈)
|
||||||
|
List<string> GetRegionPathNames(Guid? startRegionUuid)
|
||||||
|
{
|
||||||
|
var pathNames = new List<string>();
|
||||||
|
Guid? nextId = startRegionUuid;
|
||||||
|
|
||||||
|
while (nextId.HasValue && regionDict.TryGetValue(nextId.Value, out var reg))
|
||||||
|
{
|
||||||
|
pathNames.Add(reg.Name); // 收集區域名稱
|
||||||
|
nextId = reg.ParentUuid; // 假設你的欄位叫 ParentUuid,請依實際欄位修改
|
||||||
|
}
|
||||||
|
|
||||||
|
// 反轉順序讓它變成:[大區域, 中區域, 小區域]
|
||||||
|
pathNames.Reverse();
|
||||||
|
return pathNames;
|
||||||
|
}
|
||||||
|
// 3. 步驟 A:純資料庫查詢 (只撈取需要的資料,不呼叫 C# 函式)
|
||||||
|
var dbBeds = _db.RegionRoomBed
|
||||||
|
.Where(b => !busyBedUuids.Contains(b.Uuid)) // 建議過濾條件放在 ToList 之前,減少傳輸資料量
|
||||||
|
.Select(b => new
|
||||||
|
{
|
||||||
|
b.Name,
|
||||||
|
b.Uuid,
|
||||||
|
b.StatusCode,
|
||||||
|
b.IsActive,
|
||||||
b.RoomUuid,
|
b.RoomUuid,
|
||||||
Room=_db.Room.Where(r=>r.Uuid==b.RoomUuid).
|
b.Limits,
|
||||||
Select(r=>new { r.Name,r.RegionUuid,
|
// 直接在 SQL 層級把 Room 撈出來
|
||||||
RegionName=_db.Region.Where(g=>g.Uuid==r.RegionUuid).Select(g=>g.Name).FirstOrDefault()}).FirstOrDefault(),
|
Room = _db.Room
|
||||||
|
.Where(r => r.Uuid == b.RoomUuid)
|
||||||
|
.Select(r => new
|
||||||
|
{
|
||||||
|
r.Name,
|
||||||
|
r.RegionUuid
|
||||||
})
|
})
|
||||||
.Where(b => !busyBedUuids.Contains(b.Uuid))
|
.FirstOrDefault()
|
||||||
.ToList();
|
})
|
||||||
|
.AsEnumerable(); // 💡 關鍵:從這裡開始切換到記憶體(LINQ to Objects)
|
||||||
|
|
||||||
|
// 4. 步驟 B:在記憶體中加工,呼叫 GetRegionPathNames
|
||||||
|
var availableBeds = dbBeds.Select(b => new
|
||||||
|
{
|
||||||
|
b.Name,
|
||||||
|
b.Uuid,
|
||||||
|
b.StatusCode,
|
||||||
|
b.IsActive,
|
||||||
|
b.RoomUuid,
|
||||||
|
b.Limits,
|
||||||
|
// 💡 此時已經在記憶體中,可以安全地呼叫 C# 函式
|
||||||
|
RegionPath = GetRegionPathNames(b.Room?.RegionUuid),
|
||||||
|
Room = b.Room == null ? null : new
|
||||||
|
{
|
||||||
|
b.Room.Name,
|
||||||
|
b.Room.RegionUuid,
|
||||||
|
// 從你已經載入的字典中直接抓 RegionName,省去在 SQL 裡面重複 Join Region 表
|
||||||
|
|
||||||
|
// 💡 修正關鍵:用 is 語法自動拆箱並安全檢查,完美避開 ?? 的型態限制
|
||||||
|
RegionName = b.Room.RegionUuid is Guid rId && regionDict.TryGetValue(rId, out var reg)
|
||||||
|
? reg.Name
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
}).ToList();
|
||||||
|
// 空閒床位 = 所有床位 - 忙碌床位
|
||||||
|
//var availableBeds = _db.RegionRoomBed.Select(b=>new {
|
||||||
|
// b.Name ,b.Uuid,b.StatusCode,b.IsActive,
|
||||||
|
// b.RoomUuid,b.Limits,
|
||||||
|
// resion = GetRegionPathNames(b.RoomUuid),
|
||||||
|
// Room =_db.Room.Where(r=>r.Uuid==b.RoomUuid).
|
||||||
|
// Select(r=>new { r.Name,r.RegionUuid,
|
||||||
|
// RegionName=_db.Region.Where(g=>g.Uuid==r.RegionUuid).
|
||||||
|
// Select(g=>g.Name).FirstOrDefault()}).FirstOrDefault(),
|
||||||
|
|
||||||
|
//})
|
||||||
|
// .Where(b => !busyBedUuids.Contains(b.Uuid))
|
||||||
|
// .ToList();
|
||||||
|
|
||||||
|
|
||||||
return Ok(new { availableBeds });
|
return Ok(new { availableBeds });
|
||||||
|
|||||||
+241
-25
@@ -118,7 +118,7 @@
|
|||||||
<template v-slot:activator="{ on, attrs }">
|
<template v-slot:activator="{ on, attrs }">
|
||||||
<v-icon color="error" v-bind="attrs" v-on="on" size="20">mdi-alert-circle</v-icon>
|
<v-icon color="error" v-bind="attrs" v-on="on" size="20">mdi-alert-circle</v-icon>
|
||||||
</template>
|
</template>
|
||||||
<span>特殊需求: {{ item.specialNeeds }}</span>
|
<span>特殊需求: {{ getSpecialNeedsText(item.specialNeeds) }}</span>
|
||||||
</v-tooltip>
|
</v-tooltip>
|
||||||
<v-icon v-else color="grey lighten-3" size="20">mdi-alert-circle-outline</v-icon>
|
<v-icon v-else color="grey lighten-3" size="20">mdi-alert-circle-outline</v-icon>
|
||||||
</div>
|
</div>
|
||||||
@@ -138,6 +138,10 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<v-list dense>
|
<v-list dense>
|
||||||
|
<v-list-item :disabled="item.statuscode !== '401'" @click="confirmRemoveGuadanOrderGuest(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-trash</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="error--text">刪除</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
<v-list-item :disabled="item.statuscode !== '401'" @click="confirmDeleteGuadanOrderGuest(item)">
|
<v-list-item :disabled="item.statuscode !== '401'" @click="confirmDeleteGuadanOrderGuest(item)">
|
||||||
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-cancel</v-icon></v-list-item-icon>
|
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-cancel</v-icon></v-list-item-icon>
|
||||||
<v-list-item-title class="error--text">取消預訂</v-list-item-title>
|
<v-list-item-title class="error--text">取消預訂</v-list-item-title>
|
||||||
@@ -197,18 +201,36 @@
|
|||||||
{{ room.name }} (剩餘: {{ roomAvailableBedsCount(room) }})
|
{{ room.name }} (剩餘: {{ roomAvailableBedsCount(room) }})
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 床位列表 -->
|
<!-- 床位列表 (加入 Tooltip 提示特殊條件) -->
|
||||||
<v-chip-group column>
|
<v-chip-group column>
|
||||||
<v-chip v-for="bed in room.beds"
|
<template v-for="bed in room.beds">
|
||||||
:key="bed.id"
|
<!-- 封裝 Tooltip:有條件時提示內容,沒條件時提示無特殊限制 -->
|
||||||
:color="bed.id === selectedGuestForBed.bedUuid ? 'success' : (bed.isAvailableNow ? 'primary' : 'grey')"
|
<v-tooltip bottom :key="bed.id">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-chip :color="bed.id === selectedGuestForBed.bedUuid ? 'success' : (bed.isAvailableNow ? 'primary' : 'grey')"
|
||||||
:text-color="bed.id === selectedGuestForBed.bedUuid || bed.isAvailableNow ? 'white' : 'black'"
|
:text-color="bed.id === selectedGuestForBed.bedUuid || bed.isAvailableNow ? 'white' : 'black'"
|
||||||
:disabled="!bed.isAvailableNow && bed.id !== selectedGuestForBed.bedUuid"
|
:disabled="!bed.isAvailableNow && bed.id !== selectedGuestForBed.bedUuid"
|
||||||
@click="assignBedToGuest(building, room, bed)"
|
@click="assignBedToGuest(building, room, bed)"
|
||||||
|
v-bind="attrs"
|
||||||
|
v-on="on"
|
||||||
small>
|
small>
|
||||||
{{ bed.name }}
|
{{ bed.name }}
|
||||||
<v-icon v-if="bed.id === selectedGuestForBed.bedUuid" right size="14">mdi-check-circle</v-icon>
|
<v-icon v-if="bed.id === selectedGuestForBed.bedUuid" right size="14">mdi-check-circle</v-icon>
|
||||||
|
<!-- 若床位有特殊條件,加上小圖示標示 -->
|
||||||
|
<v-icon v-if="bed.limits && bed.limits.length > 0" right size="12" color="amber lighten-3">mdi-star</v-icon>
|
||||||
</v-chip>
|
</v-chip>
|
||||||
|
</template>
|
||||||
|
<span>
|
||||||
|
{{ bed.name }}
|
||||||
|
<template v-if="bed.limits && bed.limits.length > 0">
|
||||||
|
<br>【具備條件】:{{ getSpecialNeedsText(Array.isArray(bed.limits) ? bed.limits.join(',') : String(bed.limits)) }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<br>(無特殊限制床位)
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
</v-chip-group>
|
</v-chip-group>
|
||||||
|
|
||||||
<v-divider v-if="index < building.rooms.length - 1" class="mt-2"></v-divider>
|
<v-divider v-if="index < building.rooms.length - 1" class="mt-2"></v-divider>
|
||||||
@@ -277,7 +299,7 @@
|
|||||||
<v-select :items="e2" v-model="e5" label="性別"></v-select>
|
<v-select :items="e2" v-model="e5" label="性別"></v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12">
|
<v-col cols="12">
|
||||||
<v-select v-model="e6" :items="states" label="特殊需求" multiple hint="選擇條件" persistent-hint></v-select>
|
<v-select v-model="e6" :items="states" item-text="text" item-value="value" label="特殊需求" multiple hint="選擇條件" persistent-hint></v-select>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-container>
|
</v-container>
|
||||||
@@ -391,20 +413,28 @@
|
|||||||
|
|
||||||
const guestGender = this.selectedGuestForBed.gender;
|
const guestGender = this.selectedGuestForBed.gender;
|
||||||
const currentGuestBedUuid = this.selectedGuestForBed.bedUuid;
|
const currentGuestBedUuid = this.selectedGuestForBed.bedUuid;
|
||||||
|
const guestNeeds = (this.selectedGuestForBed.specialNeeds || '').split(',').filter(c => c);
|
||||||
return this.mockBuildings.map(building => {
|
return this.mockBuildings.map(building => {
|
||||||
|
console.log('filteredMockBuildings:', building);
|
||||||
// 過濾房間並處理床位動態狀態
|
// 過濾房間並處理床位動態狀態
|
||||||
const filteredRooms = building.rooms.map(room => {
|
const filteredRooms = building.rooms.map(room => {
|
||||||
return {
|
return {
|
||||||
...room,
|
...room,
|
||||||
beds: room.beds.map(bed => {
|
beds: room.beds.map(bed => {
|
||||||
const isTakenByOthers = this.assignedBedUuids.includes(bed.id) && bed.id !== currentGuestBedUuid;
|
const isTakenByOthers = this.assignedBedUuids.includes(bed.id) && bed.id !== currentGuestBedUuid;
|
||||||
|
// 檢查條件是否完全滿足
|
||||||
|
const bedConditions = bed.limits || [];
|
||||||
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
|
room["regionPath"] = bed.regionPath;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...bed,
|
...bed,
|
||||||
isAvailableNow: bed.isAvailable && !isTakenByOthers
|
isAvailableNow: bed.isAvailable && !isTakenByOthers && isMatchConditions,
|
||||||
|
isMatchConditions: isMatchConditions
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
console.log("filteredMockBuildings: room:", room);
|
||||||
}).filter(room =>
|
}).filter(room =>
|
||||||
!guestGender || guestGender === '請選擇' || room.genderLimit === guestGender
|
!guestGender || guestGender === '請選擇' || room.genderLimit === guestGender
|
||||||
);
|
);
|
||||||
@@ -438,6 +468,16 @@
|
|||||||
roomAvailableBedsCount(room) {
|
roomAvailableBedsCount(room) {
|
||||||
return room.beds.filter(b => b.isAvailableNow).length;
|
return room.beds.filter(b => b.isAvailableNow).length;
|
||||||
},
|
},
|
||||||
|
getSpecialNeedsText(specialNeedsCodes) {
|
||||||
|
if (!specialNeedsCodes) return '';
|
||||||
|
const codes = specialNeedsCodes.split(',');
|
||||||
|
let self = this;
|
||||||
|
const names = codes.map(code => {
|
||||||
|
const target = self.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
});
|
||||||
|
return names.join('、');
|
||||||
|
},
|
||||||
getGuadanLimits() {//抓掛單條件
|
getGuadanLimits() {//抓掛單條件
|
||||||
this.states.length = 0; // 清空陣列
|
this.states.length = 0; // 清空陣列
|
||||||
let self = this;
|
let self = this;
|
||||||
@@ -445,8 +485,11 @@
|
|||||||
axios.post(HTTP_HOST + 'api/guadan/getGuadanLimit').then((res) => {
|
axios.post(HTTP_HOST + 'api/guadan/getGuadanLimit').then((res) => {
|
||||||
if (res.status == 200) {
|
if (res.status == 200) {
|
||||||
res.data.forEach(item => {
|
res.data.forEach(item => {
|
||||||
console.log('掛單條件', item);
|
|
||||||
self.states.push(item.paramName);
|
self.states.push({
|
||||||
|
text: item.paramName,
|
||||||
|
value: item.paramNo
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -457,7 +500,18 @@
|
|||||||
if (!this.e5 || this.e5 == 0) { console.log("請選擇男眾或女眾"); return; }
|
if (!this.e5 || this.e5 == 0) { console.log("請選擇男眾或女眾"); return; }
|
||||||
if (!this.s_date) { console.log('請選擇開始日期'); return; }
|
if (!this.s_date) { console.log('請選擇開始日期'); return; }
|
||||||
if (!this.e_date) { console.log('請選擇結束日期'); return; }
|
if (!this.e_date) { console.log('請選擇結束日期'); return; }
|
||||||
|
const today = moment().format('YYYY-MM-DD');
|
||||||
|
if (this.s_date < today) {
|
||||||
|
this.message = '開始日期不可小於今天';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 檢查 2:結束日期不可小於開始日期
|
||||||
|
if (this.e_date < this.s_date) {
|
||||||
|
this.message = '結束日期不可小於開始日期';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
for (let i = 0; i < this.e4; i++) {
|
for (let i = 0; i < this.e4; i++) {
|
||||||
const tempUuid = 'temp-' + Date.now() + '-' + i;
|
const tempUuid = 'temp-' + Date.now() + '-' + i;
|
||||||
this.guadanguest.items.push({
|
this.guadanguest.items.push({
|
||||||
@@ -495,8 +549,40 @@
|
|||||||
validateOrderForm() {
|
validateOrderForm() {
|
||||||
if (!this.guadanorder.order_form.startdate) { this.message = '請輸入開始日期'; this.message_dialog = true; return false; }
|
if (!this.guadanorder.order_form.startdate) { this.message = '請輸入開始日期'; this.message_dialog = true; return false; }
|
||||||
if (!this.guadanorder.order_form.enddate) { this.message = '請輸入結束日期'; this.message_dialog = true; return false; }
|
if (!this.guadanorder.order_form.enddate) { this.message = '請輸入結束日期'; this.message_dialog = true; return false; }
|
||||||
|
const startDate = this.guadanorder.order_form.startdate;
|
||||||
|
const endDate = this.guadanorder.order_form.enddate;
|
||||||
|
// 取得今天日期字串 (YYYY-MM-DD)
|
||||||
|
const today = moment().format('YYYY-MM-DD');
|
||||||
|
|
||||||
|
// 檢查 1:預約開始日期不可小於今天
|
||||||
|
if (startDate < today) {
|
||||||
|
this.message = '預約開始日期不可小於今天';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 檢查 2:預約結束日期不可小於預約開始日期
|
||||||
|
if (endDate < startDate) {
|
||||||
|
this.message = '預約結束日期不可小於預約開始日期';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (!this.guadanorder.order_form.bookerName) { this.message = '請輸入姓名'; this.message_dialog = true; return false; }
|
if (!this.guadanorder.order_form.bookerName) { this.message = '請輸入姓名'; this.message_dialog = true; return false; }
|
||||||
if (!this.guadanorder.order_form.bookerPhone) { this.message = '請輸入電話'; this.message_dialog = true; return false; }
|
if (!this.guadanorder.order_form.bookerPhone) { this.message = '請輸入電話'; this.message_dialog = true; return false; }
|
||||||
|
// 檢查 3:若有掛單明細,檢查是否有「未分配床位」的人員
|
||||||
|
if (this.guadanguest.items && this.guadanguest.items.length > 0) {
|
||||||
|
// 找出沒有 bedUuid 的人員
|
||||||
|
const unassignedGuests = this.guadanguest.items.filter(item => !item.bedUuid);
|
||||||
|
|
||||||
|
if (unassignedGuests.length > 0) {
|
||||||
|
// 找出第一個未分配人員的顯示名稱或順位號碼
|
||||||
|
const firstUnassignedIdx = this.guadanguest.items.indexOf(unassignedGuests[0]) + 1;
|
||||||
|
const guestIdentifier = unassignedGuests[0].fullName || `第 ${firstUnassignedIdx} 位預訂人`;
|
||||||
|
|
||||||
|
this.message = `無法存檔!尚有 ${unassignedGuests.length} 位人員未分配床位(例如:${guestIdentifier})。請先完成床位分配再存檔!`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -522,7 +608,6 @@
|
|||||||
|
|
||||||
let detail = []
|
let detail = []
|
||||||
this.guadanguest.items.forEach(item => {
|
this.guadanguest.items.forEach(item => {
|
||||||
console.log('明細', item);
|
|
||||||
detail.push({
|
detail.push({
|
||||||
uuid: item.uuid,
|
uuid: item.uuid,
|
||||||
fullName: item.fullName,
|
fullName: item.fullName,
|
||||||
@@ -534,10 +619,12 @@
|
|||||||
note: item.note,
|
note: item.note,
|
||||||
handi: item.specialNeeds,
|
handi: item.specialNeeds,
|
||||||
bedUuid: item.bedUuid,
|
bedUuid: item.bedUuid,
|
||||||
|
roomUuid: item.roomUuid,
|
||||||
name: item.fullName
|
name: item.fullName
|
||||||
})
|
})
|
||||||
|
console.log('掛單明細', detail);
|
||||||
})
|
})
|
||||||
console.log('掛單主檔', this.guadanorder.order_form);
|
//console.log('掛單主檔', this.guadanorder.order_form);
|
||||||
if (!this.validateOrderForm()) return;
|
if (!this.validateOrderForm()) return;
|
||||||
axios.post(HTTP_HOST + 'api/guadan/saveGandan', { order: this.guadanorder.order_form, detail: detail })
|
axios.post(HTTP_HOST + 'api/guadan/saveGandan', { order: this.guadanorder.order_form, detail: detail })
|
||||||
.then((res => {
|
.then((res => {
|
||||||
@@ -564,14 +651,94 @@
|
|||||||
this.checkInGuest.showSelectGuadanOrderGuest = true;
|
this.checkInGuest.showSelectGuadanOrderGuest = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
showAutomaticBedAllocation() {
|
async showAutomaticBedAllocation() {
|
||||||
if (!this.guadanorder.order_form.uuid) {
|
console.log(this.guadanguest.items);
|
||||||
|
// 1. 篩選出尚未分配床位的人員
|
||||||
|
const unassignedGuests = this.guadanguest.items.filter(item => !item.bedUuid);
|
||||||
|
|
||||||
|
if (unassignedGuests.length === 0) {
|
||||||
|
this.message = '目前所有人員皆已完成床位分配!';
|
||||||
this.message_dialog = true;
|
this.message_dialog = true;
|
||||||
this.message = '請先儲存掛單資訊';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.automaticBedAllocation.showModal = true;
|
unassignedGuests.sort((a, b) => {
|
||||||
this.getavailablebedcountbytime(this.guadanorder.order_form.startdate, this.guadanorder.order_form.enddate);
|
const needsA = (a.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
|
const needsB = (b.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
|
return needsB - needsA; // 數量多的排在前面 (降冪)
|
||||||
|
});
|
||||||
|
let successCount = 0;
|
||||||
|
let failCount = 0;
|
||||||
|
|
||||||
|
// 2. 逐一處理未分配床位的人員
|
||||||
|
for (const guest of unassignedGuests) {
|
||||||
|
try {
|
||||||
|
// 取得該人員入住時間區間的可分配床位
|
||||||
|
const resp = await axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: guest.checkinat,
|
||||||
|
endTime: guest.checkoutat
|
||||||
|
});
|
||||||
|
|
||||||
|
const availableBeds = resp.data?.availableBeds || [];
|
||||||
|
// 過濾出真正的特殊需求 (排除「無特殊需求」與空字串)
|
||||||
|
const rawNeeds = (guest.specialNeeds || '').split(',');
|
||||||
|
const guestNeeds = rawNeeds.filter(need => need && need !== '無特殊需求');
|
||||||
|
|
||||||
|
// 3. 搜尋合適的床位
|
||||||
|
const matchedBed = availableBeds.find(bed => {
|
||||||
|
// A. 床位狀態需為可用 ('101')
|
||||||
|
if (bed.statusCode !== '101') return false;
|
||||||
|
|
||||||
|
// B. 不能已被目前列表中的其他人佔用
|
||||||
|
if (this.assignedBedUuids.includes(bed.uuid)) return false;
|
||||||
|
|
||||||
|
// C. 性別限制過濾
|
||||||
|
const regionName = bed.room?.regionName || '';
|
||||||
|
let roomGenderLimit = null;
|
||||||
|
if (regionName.includes('男眾')) roomGenderLimit = '男眾';
|
||||||
|
else if (regionName.includes('女眾')) roomGenderLimit = '女眾';
|
||||||
|
|
||||||
|
if (guest.gender && guest.gender !== '請選擇' && roomGenderLimit) {
|
||||||
|
if (guest.gender !== roomGenderLimit) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// D. 特殊需求條件檢查 (人員需要的,床位必須具備)
|
||||||
|
const bedConditions = bed.limits || [];
|
||||||
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
|
if (!isMatchConditions) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. 若找到合適床位,進行分配
|
||||||
|
if (matchedBed) {
|
||||||
|
const buildingName = matchedBed.room?.regionName || '';
|
||||||
|
const roomName = matchedBed.room?.name || '';
|
||||||
|
const bedName = matchedBed.name || '';
|
||||||
|
|
||||||
|
this.$set(guest, 'bedName', `${buildingName} - ${roomName} - ${bedName}`);
|
||||||
|
this.$set(guest, 'bedUuid', matchedBed.uuid);
|
||||||
|
this.$set(guest, 'roomUuid', matchedBed.roomUuid);
|
||||||
|
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('自動分配床位發生錯誤:', error);
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 分配完成提示
|
||||||
|
this.message = `自動分配完成!成功分配 ${successCount} 位,失敗/無合適床位 ${failCount} 位。`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
//if (!this.guadanorder.order_form.uuid) {
|
||||||
|
// this.message_dialog = true;
|
||||||
|
// this.message = '請先儲存掛單資訊';
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
//this.automaticBedAllocation.showModal = true;
|
||||||
|
//this.getavailablebedcountbytime(this.guadanorder.order_form.startdate, this.guadanorder.order_form.enddate);
|
||||||
},
|
},
|
||||||
|
|
||||||
getavailablebedcountbytime(startTime, endTime) {
|
getavailablebedcountbytime(startTime, endTime) {
|
||||||
@@ -591,9 +758,56 @@
|
|||||||
assignBedToGuest(building, room, bed) {
|
assignBedToGuest(building, room, bed) {
|
||||||
if (!bed.isAvailableNow && bed.id !== this.selectedGuestForBed.bedUuid) return;
|
if (!bed.isAvailableNow && bed.id !== this.selectedGuestForBed.bedUuid) return;
|
||||||
|
|
||||||
|
// 1. 安全轉換函數:強制將各種型別轉換為標準陣列
|
||||||
|
const ensureArray = (val) => {
|
||||||
|
if (!val) return [];
|
||||||
|
if (Array.isArray(val)) return val;
|
||||||
|
if (typeof val === 'string') return val.split(',').filter(c => c && c.trim() !== '');
|
||||||
|
if (typeof val === 'object') return Object.values(val).filter(c => c);
|
||||||
|
return [String(val)];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取出安全的床位條件陣列
|
||||||
|
const bedConditions = ensureArray(bed.limits);
|
||||||
|
// 2. 條件比對檢查 (檢核特殊需求)
|
||||||
|
const guestNeedsStr = this.selectedGuestForBed.specialNeeds || '';
|
||||||
|
// 將人員需求轉換為代碼陣列 (過濾空值)
|
||||||
|
const guestNeeds = guestNeedsStr ? guestNeedsStr.split(',').filter(c => c) : [];
|
||||||
|
// 床位條件 (若後端未傳回則預設為空陣列)
|
||||||
|
//const bedConditions = bed.limits || [];
|
||||||
|
|
||||||
|
// 檢查人員有的需求,床位是否未滿足 (找出不合適的條件代碼)
|
||||||
|
const unmatchedNeeds = guestNeeds.filter(need => !bedConditions.includes(need));
|
||||||
|
|
||||||
|
if (unmatchedNeeds.length > 0) {
|
||||||
|
// 將未滿足的需求代碼轉換為中文名稱
|
||||||
|
const unmatchedNames = unmatchedNeeds.map(code => {
|
||||||
|
const target = this.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
}).join('、');
|
||||||
|
|
||||||
|
// 跳出提示阻擋分配(或改為 confirm 提醒)
|
||||||
|
this.message = `不符合分配條件!該人員需要「${unmatchedNames}」,但此床位未具備對應條件。`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
return; // 中斷分配
|
||||||
|
}
|
||||||
// 將大樓名稱也組進去顯示
|
// 將大樓名稱也組進去顯示
|
||||||
|
// 2. 取得床位具備的特殊條件文字
|
||||||
|
let bedConditionNotice = '';
|
||||||
|
if (bedConditions.length > 0) {
|
||||||
|
const bedConditionNames = bedConditions.map(code => {
|
||||||
|
const target = this.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
}).join('、');
|
||||||
|
bedConditionNotice = `\n【床位具備條件】:${bedConditionNames}`;
|
||||||
|
} else {
|
||||||
|
bedConditionNotice = `\n【床位具備條件】:無特殊限制`;
|
||||||
|
}
|
||||||
|
console.log(room, bed);
|
||||||
|
// 3. 設定床位並跳出點擊後的二次提示
|
||||||
this.$set(this.selectedGuestForBed, 'bedName', `${building.name} - ${room.name} - ${bed.name}`);
|
this.$set(this.selectedGuestForBed, 'bedName', `${building.name} - ${room.name} - ${bed.name}`);
|
||||||
this.$set(this.selectedGuestForBed, 'bedUuid', bed.id);
|
this.$set(this.selectedGuestForBed, 'bedUuid', bed.id);
|
||||||
|
this.$set(this.selectedGuestForBed, 'roomUuid', room.id);
|
||||||
|
|
||||||
this.message = `已將「${building.name} ${room.name} ${bed.name}」分配給該明細!`;
|
this.message = `已將「${building.name} ${room.name} ${bed.name}」分配給該明細!`;
|
||||||
this.message_dialog = true;
|
this.message_dialog = true;
|
||||||
@@ -610,7 +824,6 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
async selectGuestForBed(item) {
|
async selectGuestForBed(item) {
|
||||||
console.log('選床', item);
|
|
||||||
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
startTime: item.checkinat, endTime: item.checkoutat
|
startTime: item.checkinat, endTime: item.checkoutat
|
||||||
}).then((resp) => {
|
}).then((resp) => {
|
||||||
@@ -623,7 +836,8 @@
|
|||||||
const regionName = bed.room.regionName;
|
const regionName = bed.room.regionName;
|
||||||
const roomId = bed.roomUuid;
|
const roomId = bed.roomUuid;
|
||||||
const roomName = bed.room.name;
|
const roomName = bed.room.name;
|
||||||
|
const regionPath = bed.regionPath;
|
||||||
|
console.log('床位資料', bed);
|
||||||
// 自動判斷性別限制 (若區域名稱包含"男眾"則為"男眾",反之女眾)
|
// 自動判斷性別限制 (若區域名稱包含"男眾"則為"男眾",反之女眾)
|
||||||
const genderLimit = regionName.includes('男眾') ? '男眾' : '女眾';
|
const genderLimit = regionName.includes('男眾') ? '男眾' : '女眾';
|
||||||
|
|
||||||
@@ -653,7 +867,9 @@
|
|||||||
acc[regionId].roomsMap[roomId].beds.push({
|
acc[regionId].roomsMap[roomId].beds.push({
|
||||||
id: bed.uuid,
|
id: bed.uuid,
|
||||||
name: bed.name,
|
name: bed.name,
|
||||||
isAvailable: isAvailable
|
isAvailable: isAvailable,
|
||||||
|
limits: bed.limits || [],
|
||||||
|
regionPath: regionPath
|
||||||
});
|
});
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
@@ -669,15 +885,15 @@
|
|||||||
|
|
||||||
// 執行轉換
|
// 執行轉換
|
||||||
const result = transformData(rawData);
|
const result = transformData(rawData);
|
||||||
//console.log(JSON.stringify(result, null, 4));
|
|
||||||
|
|
||||||
|
|
||||||
this.mockBuildings = result;
|
this.mockBuildings = result;
|
||||||
this.selectedGuestForBed = item;
|
this.selectedGuestForBed = item;
|
||||||
this.activeRoomPanel = null;
|
this.activeRoomPanel = null;
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
confirmRemoveGuadanOrderGuest(item) {
|
||||||
|
//let temp = this.guadanguest.items.find(x => x.uuid == item.uuid);
|
||||||
|
this.guadanguest.items = this.guadanguest.items.filter(x => x.uuid != item.uuid);
|
||||||
|
},
|
||||||
confirmDeleteGuadanOrderGuest(item) {
|
confirmDeleteGuadanOrderGuest(item) {
|
||||||
console.log('取消預訂', item);
|
console.log('取消預訂', item);
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,921 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container-fluid">
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<v-tabs>
|
||||||
|
<v-tab value="tab-1" @click="tab='tab-1'">
|
||||||
|
掛單資訊
|
||||||
|
</v-tab>
|
||||||
|
<v-tab value="tab-2" @click="tab='tab-2'">
|
||||||
|
掛單明細
|
||||||
|
</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
|
||||||
|
<v-tabs-items v-model="tab">
|
||||||
|
<!-- ================== Tab 1: 掛單資訊 ================== -->
|
||||||
|
<v-tab-item value="tab-1">
|
||||||
|
<div class="border rounded p-3 bg-white shadow-sm mt-3">
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">掛單單號(不可修改)</label>
|
||||||
|
<div class="col-sm-4 text-left">
|
||||||
|
<input class="form-control" v-model="guadanorder.order_form.orderNo" readonly />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">關聯活動</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select class="form-control" v-model="activityNum">
|
||||||
|
<option :value="null">未關聯</option>
|
||||||
|
<option v-for="activity in activityList" :key="activity.num" :value="activity.num">
|
||||||
|
{{activity.subject}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預約開始日期</label>
|
||||||
|
<div class="col-sm-4 text-left">
|
||||||
|
<input class="form-control" type="date" disabled v-model="guadanorder.order_form.startdate" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預約結束日期</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" type="date" disabled v-model="guadanorder.order_form.enddate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預定人姓名</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" v-model="guadanorder.order_form.bookerName" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預定人電話</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" v-model="guadanorder.order_form.bookerPhone" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">備註</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<textarea class="form-control" v-model="guadanorder.order_form.note"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex mb-3">
|
||||||
|
<!--v-if="guadanorder.order_form.uuid"-->
|
||||||
|
<button type="button" class="btn btn-primary mx-auto" style="width: 120px;" @click="updateGuadanOrder">
|
||||||
|
存檔
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</v-tab-item>
|
||||||
|
|
||||||
|
<!-- ================== Tab 2: 掛單明細 ================== -->
|
||||||
|
<v-tab-item value="tab-2">
|
||||||
|
<v-row class="mt-2">
|
||||||
|
|
||||||
|
<!-- 左側:掛單明細列表 -->
|
||||||
|
<v-col cols="12" md="8">
|
||||||
|
<div class="d-flex align-items-center mb-3">
|
||||||
|
<v-btn color="primary" @click="showCheckInModal" class="me-3">
|
||||||
|
<v-icon left>mdi-plus</v-icon>設定人數
|
||||||
|
</v-btn>
|
||||||
|
<v-btn @click="showAutomaticBedAllocation">
|
||||||
|
自動分配床位
|
||||||
|
</v-btn>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-data-table :headers="guadanguest.headers" :items="guadanguest.items" class="elevation-1 rounded" dense>
|
||||||
|
<template #item.checkinat="{item}">
|
||||||
|
{{item.checkinat |timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template #item.checkoutat="{item}">
|
||||||
|
{{item.checkoutat |timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<!--<template v-slot:item.name="{item}">-->
|
||||||
|
<!--</template>-->
|
||||||
|
<!-- 姓名欄位改為輸入框:未輸入時預設顯示當前順位編號 -->
|
||||||
|
<template v-slot:item.name="{item}">
|
||||||
|
<v-text-field v-model="item.fullName"
|
||||||
|
dense
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
class="my-1"
|
||||||
|
:placeholder="item.fullName==null?item.name:(String(guadanguest.items.indexOf(item) + 1))"
|
||||||
|
style="min-width: 50px; font-size: 14px;"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.sex="{item}">
|
||||||
|
{{item.gender}}
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.room="{item}">
|
||||||
|
<span v-if="item.bedName || item.room">
|
||||||
|
{{ item.room ? item.room.resion.join("/") : '' }}
|
||||||
|
{{ item.room ? item.room.name : '' }}
|
||||||
|
{{ item.bedName || '' }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-muted">
|
||||||
|
未分配床位
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.indicators="{item}">
|
||||||
|
<div class="d-flex justify-center align-center">
|
||||||
|
|
||||||
|
<v-chip small :color="getStatusColor(item.statuscode)" text-color="white" class="me-2" style="font-size: 12px; height: 20px;">
|
||||||
|
{{ item.statusName || '待入住' }}
|
||||||
|
</v-chip>
|
||||||
|
|
||||||
|
<v-tooltip bottom v-if="item.note">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-icon color="warning" v-bind="attrs" v-on="on" size="20" class="me-1">mdi-note-text</v-icon>
|
||||||
|
</template>
|
||||||
|
<span>備註: {{ item.note }}</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-icon v-else color="grey lighten-3" size="20" class="me-1">mdi-note-text-outline</v-icon>
|
||||||
|
|
||||||
|
<v-tooltip bottom v-if="item.specialNeeds && item.specialNeeds !== '無特殊需求'">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-icon color="error" v-bind="attrs" v-on="on" size="20">mdi-alert-circle</v-icon>
|
||||||
|
</template>
|
||||||
|
<span>特殊需求: {{ getSpecialNeedsText(item.specialNeeds) }}</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-icon v-else color="grey lighten-3" size="20">mdi-alert-circle-outline</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #item.actions="{ item }">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
|
||||||
|
<v-btn color="success" outlined small class="me-2" @click="selectGuestForBed(item)">
|
||||||
|
<v-icon left size="16">mdi-bed</v-icon>選床
|
||||||
|
</v-btn>
|
||||||
|
|
||||||
|
<v-menu offset-y transition="slide-y-transition">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-btn color="primary" text small v-bind="attrs" v-on="on">
|
||||||
|
更多 <v-icon right size="18">mdi-menu-down</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list dense>
|
||||||
|
<v-list-item :disabled="item.statuscode !== '401'" @click="changeGuadanGuest(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-cancel</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="error--text">變更</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
<v-list-item :disabled="item.statuscode !== '401'" @click="confirmDeleteGuadanOrderGuest(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-cancel</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="error--text">取消預訂</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item :disabled="item.statuscode !== '401'" @click="checkinGuadanGuest(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="error" size="20">mdi-login</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="error--text">入住</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item :disabled="item.statuscode !== '402'" @click="showXuzhuGuestModalMethod(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="warning" size="20">mdi-calendar-plus</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="warning--text">續住</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
|
||||||
|
<v-list-item :disabled="item.statuscode !== '402'" @click="checkoutGuadanOrderGuest(item)">
|
||||||
|
<v-list-item-icon class="me-2"><v-icon color="primary" size="20">mdi-exit-run</v-icon></v-list-item-icon>
|
||||||
|
<v-list-item-title class="primary--text">退房</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</v-data-table>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
<!-- 右側:可選的大樓與房間床位 -->
|
||||||
|
<v-col cols="12" md="4">
|
||||||
|
<v-card class="elevation-1 h-100" style="min-height: 400px;">
|
||||||
|
<v-card-title class="bg-light">
|
||||||
|
分配床位
|
||||||
|
</v-card-title>
|
||||||
|
<v-divider></v-divider>
|
||||||
|
|
||||||
|
<v-card-text v-if="selectedGuestForBed">
|
||||||
|
<div class="mb-3 text-primary font-weight-bold">
|
||||||
|
目前選擇:{{ selectedGuestForBed.fullName || (guadanguest.items.indexOf(selectedGuestForBed) + 1) }} ({{ selectedGuestForBed.gender }})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 最外層:大樓 -->
|
||||||
|
<v-expansion-panels v-model="activeBuildingPanel" accordion>
|
||||||
|
<v-expansion-panel v-for="building in filteredMockBuildings" :key="building.id">
|
||||||
|
<v-expansion-panel-header class="font-weight-bold">
|
||||||
|
<div class="d-flex align-center">
|
||||||
|
<v-icon color="indigo" class="me-2" size="20">mdi-office-building-marker</v-icon>
|
||||||
|
{{ building.name }} (剩餘: {{ buildingAvailableBedsCount(building) }})
|
||||||
|
</div>
|
||||||
|
</v-expansion-panel-header>
|
||||||
|
|
||||||
|
<v-expansion-panel-content>
|
||||||
|
<!-- 內層:房間與床位 (直接以列表呈現,避免雙層手風琴太雜亂) -->
|
||||||
|
<div v-for="(room, index) in building.rooms" :key="room.id" :class="{'mt-4': index > 0}">
|
||||||
|
|
||||||
|
<!-- 房間標題 -->
|
||||||
|
<div class="text-subtitle-2 mb-1 text-indigo">
|
||||||
|
<v-icon small color="indigo" class="me-1">mdi-door-closed</v-icon>
|
||||||
|
{{ room.name }} (剩餘: {{ roomAvailableBedsCount(room) }})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 床位列表 (加入 Tooltip 提示特殊條件) -->
|
||||||
|
<v-chip-group column>
|
||||||
|
<template v-for="bed in room.beds">
|
||||||
|
<!-- 封裝 Tooltip:有條件時提示內容,沒條件時提示無特殊限制 -->
|
||||||
|
<v-tooltip bottom :key="bed.id">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-chip :color="bed.id === selectedGuestForBed.bedUuid ? 'success' : (bed.isAvailableNow ? 'primary' : 'grey')"
|
||||||
|
:text-color="bed.id === selectedGuestForBed.bedUuid || bed.isAvailableNow ? 'white' : 'black'"
|
||||||
|
:disabled="!bed.isAvailableNow && bed.id !== selectedGuestForBed.bedUuid"
|
||||||
|
@click="assignBedToGuest(building, room, bed)"
|
||||||
|
v-bind="attrs"
|
||||||
|
v-on="on"
|
||||||
|
small>
|
||||||
|
{{ bed.name }}
|
||||||
|
<v-icon v-if="bed.id === selectedGuestForBed.bedUuid" right size="14">mdi-check-circle</v-icon>
|
||||||
|
<!-- 若床位有特殊條件,加上小圖示標示 -->
|
||||||
|
<v-icon v-if="bed.limits && bed.limits.length > 0" right size="12" color="amber lighten-3">mdi-star</v-icon>
|
||||||
|
</v-chip>
|
||||||
|
</template>
|
||||||
|
<span>
|
||||||
|
{{ bed.name }}
|
||||||
|
<template v-if="bed.limits && bed.limits.length > 0">
|
||||||
|
<br>【具備條件】:{{ getSpecialNeedsText(Array.isArray(bed.limits) ? bed.limits.join(',') : String(bed.limits)) }}
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<br>(無特殊限制床位)
|
||||||
|
</template>
|
||||||
|
</span>
|
||||||
|
</v-tooltip>
|
||||||
|
</template>
|
||||||
|
</v-chip-group>
|
||||||
|
|
||||||
|
<v-divider v-if="index < building.rooms.length - 1" class="mt-2"></v-divider>
|
||||||
|
</div>
|
||||||
|
</v-expansion-panel-content>
|
||||||
|
</v-expansion-panel>
|
||||||
|
</v-expansion-panels>
|
||||||
|
|
||||||
|
<div v-if="filteredMockBuildings.length === 0" class="text-danger mt-3">
|
||||||
|
沒有符合該性別條件的大樓與房間。
|
||||||
|
</div>
|
||||||
|
</v-card-text>
|
||||||
|
|
||||||
|
<v-card-text v-else class="text-center mt-10 text-muted">
|
||||||
|
<v-icon size="64" color="grey lighten-2">mdi-hand-pointing-left</v-icon>
|
||||||
|
<div class="mt-4">請點選左側名單的「選床」按鈕<br>開始分配床位</div>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-tab-item>
|
||||||
|
</v-tabs-items>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<v-dialog v-model="message_dialog" max-width="500">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="text-h6">系統提示</v-card-title>
|
||||||
|
<v-card-text class="pt-4">{{message}}</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="primary" text @click="message_dialog = false">確認</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog v-model="checkInGuest.showSelectGuadanOrderGuest" max-width="600">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>設定人數條件</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12"><v-text-field label="人數" type="number" v-model="e4"></v-text-field></v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-menu v-model="menu2" :close-on-content-click="false" transition="scale-transition" offset-y min-width="auto">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field v-model="s_date" label="開始日期" prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="s_date" @input="menu2 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-menu v-model="menu3" :close-on-content-click="false" transition="scale-transition" offset-y min-width="auto">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field v-model="e_date" label="結束日期" prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="e_date" @input="menu3 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-select :items="e2" v-model="e5" label="性別"></v-select>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-select v-model="e6" :items="states" item-text="text" item-value="value" label="特殊需求" multiple hint="選擇條件" persistent-hint></v-select>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="grey" text @click="checkInGuest.showSelectGuadanOrderGuest = false">關閉</v-btn>
|
||||||
|
<v-btn color="primary" @click.prevent="genGuestList">產生</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
module.exports = {
|
||||||
|
name: "edit-component",
|
||||||
|
props: {
|
||||||
|
formData: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tab: "tab-1",
|
||||||
|
e1: null,
|
||||||
|
e2: ['請選擇', '男眾', '女眾'],
|
||||||
|
e4: "",
|
||||||
|
e5: "",
|
||||||
|
e6: [],
|
||||||
|
s_date: null,
|
||||||
|
menu2: false,
|
||||||
|
menu3: false,
|
||||||
|
e_date: null,
|
||||||
|
states: [
|
||||||
|
//'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
|
||||||
|
],
|
||||||
|
message_dialog: false,
|
||||||
|
message: "",
|
||||||
|
activityList: [],
|
||||||
|
activityNum: null,
|
||||||
|
availableBedCount: { male: 0, female: 0 },
|
||||||
|
|
||||||
|
guadanorder: {
|
||||||
|
order_form: {
|
||||||
|
uuid: null,
|
||||||
|
startdate: null,
|
||||||
|
enddate: null,
|
||||||
|
note: null,
|
||||||
|
orderNo: null,
|
||||||
|
bookerName: null,
|
||||||
|
bookerPhone: null,
|
||||||
|
bookerFollowerNum: null,
|
||||||
|
activityNum: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
guadanguest: {
|
||||||
|
headers: [
|
||||||
|
{ text: '標記/狀態', value: 'indicators', align: 'center', sortable: false, width: '130px' },
|
||||||
|
{ text: '姓名', value: 'name' },
|
||||||
|
{ text: '性別', value: 'sex' },
|
||||||
|
{ text: '掛單開始時間', value: 'checkinat' },
|
||||||
|
{ text: '掛單結束時間', value: 'checkoutat' },
|
||||||
|
{ text: '床位', value: 'room' },
|
||||||
|
{ text: '操作', value: 'actions', sortable: false },
|
||||||
|
],
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
checkInGuest: {
|
||||||
|
showSelectGuadanOrderGuest: false,
|
||||||
|
inGuest: {
|
||||||
|
checkInAt: null,
|
||||||
|
checkOutAt: null,
|
||||||
|
orderNo: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
automaticBedAllocation: {
|
||||||
|
showModal: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedGuestForBed: null,
|
||||||
|
activeBuildingPanel: null, // 控制大樓的展開面板
|
||||||
|
|
||||||
|
// 模擬資料層級: 大樓 -> 房間 -> 床位
|
||||||
|
mockBuildings: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activityNum: {
|
||||||
|
handler(newVal) {
|
||||||
|
let act = this.activityList.find(activity => activity.num == newVal);
|
||||||
|
if (act) {
|
||||||
|
this.guadanorder.order_form.startdate = act.startDate;
|
||||||
|
this.guadanorder.order_form.enddate = act.endDate;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
formData: {
|
||||||
|
handler(newVal) {
|
||||||
|
//用掛單的uuid去抓掛單資料跟明細檔
|
||||||
|
console.log('掛單uuid', newVal);
|
||||||
|
if (newVal != "") {
|
||||||
|
this.getGuadanData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getActivityList()
|
||||||
|
this.getGuadanLimits()
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
assignedBedUuids() {
|
||||||
|
return this.guadanguest.items
|
||||||
|
.map(item => item.bedUuid)
|
||||||
|
.filter(uuid => uuid);
|
||||||
|
},
|
||||||
|
filteredMockBuildings() {
|
||||||
|
if (!this.selectedGuestForBed) return [];
|
||||||
|
|
||||||
|
const guestGender = this.selectedGuestForBed.gender;
|
||||||
|
const currentGuestBedUuid = this.selectedGuestForBed.bedUuid;
|
||||||
|
const guestNeeds = (this.selectedGuestForBed.specialNeeds || '').split(',').filter(c => c);
|
||||||
|
return this.mockBuildings.map(building => {
|
||||||
|
// 過濾房間並處理床位動態狀態
|
||||||
|
const filteredRooms = building.rooms.map(room => {
|
||||||
|
return {
|
||||||
|
...room,
|
||||||
|
beds: room.beds.map(bed => {
|
||||||
|
const isTakenByOthers = this.assignedBedUuids.includes(bed.id) && bed.id !== currentGuestBedUuid;
|
||||||
|
// 檢查條件是否完全滿足
|
||||||
|
const bedConditions = bed.limits || [];
|
||||||
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
|
return {
|
||||||
|
...bed,
|
||||||
|
isAvailableNow: bed.isAvailable && !isTakenByOthers && isMatchConditions,
|
||||||
|
isMatchConditions: isMatchConditions
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}).filter(room =>
|
||||||
|
!guestGender || guestGender === '請選擇' || room.genderLimit === guestGender
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...building,
|
||||||
|
rooms: filteredRooms
|
||||||
|
};
|
||||||
|
}).filter(building => building.rooms.length > 0); // 隱藏完全沒有符合條件房間的大樓
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getGuadanData() {//抓出掛單資料根明細檔
|
||||||
|
let self = this;
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/getorderbyuuid', { uuid: self.formData }).then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
console.log('掛單資料', res.data);
|
||||||
|
self.guadanorder.order_form = res.data.order_form;
|
||||||
|
self.guadanguest.items = res.data.details;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getStatusColor(code) {
|
||||||
|
switch (code) {
|
||||||
|
case '401': return 'blue';
|
||||||
|
case '402': return 'green';
|
||||||
|
default: return 'grey';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// 算整棟大樓的可用床位總和
|
||||||
|
buildingAvailableBedsCount(building) {
|
||||||
|
let count = 0;
|
||||||
|
building.rooms.forEach(room => {
|
||||||
|
count += room.beds.filter(b => b.isAvailableNow).length;
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 算單一房間的可用床位
|
||||||
|
roomAvailableBedsCount(room) {
|
||||||
|
return room.beds.filter(b => b.isAvailableNow).length;
|
||||||
|
},
|
||||||
|
getSpecialNeedsText(specialNeedsCodes) {
|
||||||
|
if (!specialNeedsCodes) return '';
|
||||||
|
const codes = specialNeedsCodes.split(',');
|
||||||
|
let self = this;
|
||||||
|
const names = codes.map(code => {
|
||||||
|
const target = self.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
});
|
||||||
|
return names.join('、');
|
||||||
|
},
|
||||||
|
getGuadanLimits() {//抓掛單條件
|
||||||
|
this.states.length = 0; // 清空陣列
|
||||||
|
let self = this;
|
||||||
|
let data = [];
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/getGuadanLimit').then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
res.data.forEach(item => {
|
||||||
|
|
||||||
|
self.states.push({
|
||||||
|
text: item.paramName,
|
||||||
|
value: item.paramNo
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
genGuestList() {
|
||||||
|
if (!this.e4) { console.log('請輸入人數'); return; }
|
||||||
|
if (!this.e5 || this.e5 == 0) { console.log("請選擇男眾或女眾"); return; }
|
||||||
|
if (!this.s_date) { console.log('請選擇開始日期'); return; }
|
||||||
|
if (!this.e_date) { console.log('請選擇結束日期'); return; }
|
||||||
|
const today = moment().format('YYYY-MM-DD');
|
||||||
|
if (this.s_date < today) {
|
||||||
|
this.message = '開始日期不可小於今天';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 檢查 2:結束日期不可小於開始日期
|
||||||
|
if (this.e_date < this.s_date) {
|
||||||
|
this.message = '結束日期不可小於開始日期';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < this.e4; i++) {
|
||||||
|
const tempUuid = 'temp-' + Date.now() + '-' + i;
|
||||||
|
this.guadanguest.items.push({
|
||||||
|
uuid: tempUuid,
|
||||||
|
fullName: '',
|
||||||
|
gender: this.e5,
|
||||||
|
checkinat: this.s_date,
|
||||||
|
checkoutat: this.e_date,
|
||||||
|
statuscode: '401',
|
||||||
|
statusName: '已預訂',
|
||||||
|
note: '',
|
||||||
|
specialNeeds: this.e6.join(",")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.s_date = null;
|
||||||
|
this.e_date = null;
|
||||||
|
this.e5 = "";
|
||||||
|
this.e4 = null;
|
||||||
|
this.e6 = [];
|
||||||
|
this.checkInGuest.showSelectGuadanOrderGuest = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getActivityList() {
|
||||||
|
const params = { page: '1', pageSize: 10000 };
|
||||||
|
axios.post(HTTP_HOST + 'api/activity/GetListNewYet', {
|
||||||
|
up_time1: moment(new Date()).format('YYYY-MM-DD')
|
||||||
|
}, { params: params }).then((res) => {
|
||||||
|
if (res.status == 200 && res.data && res.data.list) {
|
||||||
|
this.activityList = res.data.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOrderForm() {
|
||||||
|
if (!this.guadanorder.order_form.startdate) { this.message = '請輸入開始日期'; this.message_dialog = true; return false; }
|
||||||
|
if (!this.guadanorder.order_form.enddate) { this.message = '請輸入結束日期'; this.message_dialog = true; return false; }
|
||||||
|
const startDate = this.guadanorder.order_form.startdate;
|
||||||
|
const endDate = this.guadanorder.order_form.enddate;
|
||||||
|
// 取得今天日期字串 (YYYY-MM-DD)
|
||||||
|
const today = moment().format('YYYY-MM-DD');
|
||||||
|
|
||||||
|
// 檢查 1:預約開始日期不可小於今天
|
||||||
|
if (startDate < today) {
|
||||||
|
this.message = '預約開始日期不可小於今天';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 檢查 2:預約結束日期不可小於預約開始日期
|
||||||
|
if (endDate < startDate) {
|
||||||
|
this.message = '預約結束日期不可小於預約開始日期';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!this.guadanorder.order_form.bookerName) { this.message = '請輸入姓名'; this.message_dialog = true; return false; }
|
||||||
|
if (!this.guadanorder.order_form.bookerPhone) { this.message = '請輸入電話'; this.message_dialog = true; return false; }
|
||||||
|
// 檢查 3:若有掛單明細,檢查是否有「未分配床位」的人員
|
||||||
|
if (this.guadanguest.items && this.guadanguest.items.length > 0) {
|
||||||
|
// 找出沒有 bedUuid 的人員
|
||||||
|
const unassignedGuests = this.guadanguest.items.filter(item => !item.bedUuid);
|
||||||
|
|
||||||
|
if (unassignedGuests.length > 0) {
|
||||||
|
// 找出第一個未分配人員的顯示名稱或順位號碼
|
||||||
|
const firstUnassignedIdx = this.guadanguest.items.indexOf(unassignedGuests[0]) + 1;
|
||||||
|
const guestIdentifier = unassignedGuests[0].fullName || `第 ${firstUnassignedIdx} 位預訂人`;
|
||||||
|
|
||||||
|
this.message = `無法存檔!尚有 ${unassignedGuests.length} 位人員未分配床位(例如:${guestIdentifier})。請先完成床位分配再存檔!`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
createGuadanOrder() {
|
||||||
|
if (!this.validateOrderForm()) return;
|
||||||
|
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/create', this.guadanorder.order_form)
|
||||||
|
.then((res => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料建立成功'
|
||||||
|
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||||
|
this.guadanorder.order_form.orderNo = res.data.guaDanOrderNo;
|
||||||
|
|
||||||
|
const currentUrl = window.location.origin + window.location.pathname;
|
||||||
|
window.location.href = `${currentUrl}?orderId=${res.data.guaDanOrderNo}`;
|
||||||
|
})).catch((error) => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '建立掛單資料失敗:' + (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateGuadanOrder() {
|
||||||
|
if (!this.validateOrderForm()) return;
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/updateGandan', { order: this.guadanorder.order_form })
|
||||||
|
.then((res => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料更新成功'
|
||||||
|
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||||
|
})).catch((error) => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料更新失敗:' + (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showCheckInModal() {
|
||||||
|
this.checkInGuest.inGuest.checkInAt = this.guadanorder.order_form.startdate || null;
|
||||||
|
this.checkInGuest.inGuest.checkOutAt = this.guadanorder.order_form.enddate || null;
|
||||||
|
this.checkInGuest.inGuest.orderNo = this.guadanorder.order_form.orderNo;
|
||||||
|
this.s_date = this.guadanorder.order_form.startdate || null;
|
||||||
|
this.e_date = this.guadanorder.order_form.enddate || null;
|
||||||
|
this.checkInGuest.showSelectGuadanOrderGuest = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
async showAutomaticBedAllocation() {
|
||||||
|
console.log(this.guadanguest.items);
|
||||||
|
// 1. 篩選出尚未分配床位的人員
|
||||||
|
const unassignedGuests = this.guadanguest.items.filter(item => !item.bedUuid);
|
||||||
|
|
||||||
|
if (unassignedGuests.length === 0) {
|
||||||
|
this.message = '目前所有人員皆已完成床位分配!';
|
||||||
|
this.message_dialog = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unassignedGuests.sort((a, b) => {
|
||||||
|
const needsA = (a.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
|
const needsB = (b.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
|
return needsB - needsA; // 數量多的排在前面 (降冪)
|
||||||
|
});
|
||||||
|
let successCount = 0;
|
||||||
|
let failCount = 0;
|
||||||
|
|
||||||
|
// 2. 逐一處理未分配床位的人員
|
||||||
|
for (const guest of unassignedGuests) {
|
||||||
|
try {
|
||||||
|
// 取得該人員入住時間區間的可分配床位
|
||||||
|
const resp = await axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: guest.checkinat,
|
||||||
|
endTime: guest.checkoutat
|
||||||
|
});
|
||||||
|
|
||||||
|
const availableBeds = resp.data?.availableBeds || [];
|
||||||
|
// 過濾出真正的特殊需求 (排除「無特殊需求」與空字串)
|
||||||
|
const rawNeeds = (guest.specialNeeds || '').split(',');
|
||||||
|
const guestNeeds = rawNeeds.filter(need => need && need !== '無特殊需求');
|
||||||
|
|
||||||
|
// 3. 搜尋合適的床位
|
||||||
|
const matchedBed = availableBeds.find(bed => {
|
||||||
|
// A. 床位狀態需為可用 ('101')
|
||||||
|
if (bed.statusCode !== '101') return false;
|
||||||
|
|
||||||
|
// B. 不能已被目前列表中的其他人佔用
|
||||||
|
if (this.assignedBedUuids.includes(bed.uuid)) return false;
|
||||||
|
|
||||||
|
// C. 性別限制過濾
|
||||||
|
const regionName = bed.room?.regionName || '';
|
||||||
|
let roomGenderLimit = null;
|
||||||
|
if (regionName.includes('男眾')) roomGenderLimit = '男眾';
|
||||||
|
else if (regionName.includes('女眾')) roomGenderLimit = '女眾';
|
||||||
|
|
||||||
|
if (guest.gender && guest.gender !== '請選擇' && roomGenderLimit) {
|
||||||
|
if (guest.gender !== roomGenderLimit) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// D. 特殊需求條件檢查 (人員需要的,床位必須具備)
|
||||||
|
const bedConditions = bed.limits || [];
|
||||||
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
|
if (!isMatchConditions) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 4. 若找到合適床位,進行分配
|
||||||
|
if (matchedBed) {
|
||||||
|
const buildingName = matchedBed.room?.regionName || '';
|
||||||
|
const roomName = matchedBed.room?.name || '';
|
||||||
|
const bedName = matchedBed.name || '';
|
||||||
|
|
||||||
|
this.$set(guest, 'bedName', `${buildingName} - ${roomName} - ${bedName}`);
|
||||||
|
this.$set(guest, 'bedUuid', matchedBed.uuid);
|
||||||
|
this.$set(guest, 'roomUuid', matchedBed.roomUuid);
|
||||||
|
|
||||||
|
successCount++;
|
||||||
|
} else {
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('自動分配床位發生錯誤:', error);
|
||||||
|
failCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. 分配完成提示
|
||||||
|
this.message = `自動分配完成!成功分配 ${successCount} 位,失敗/無合適床位 ${failCount} 位。`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
//if (!this.guadanorder.order_form.uuid) {
|
||||||
|
// this.message_dialog = true;
|
||||||
|
// this.message = '請先儲存掛單資訊';
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
//this.automaticBedAllocation.showModal = true;
|
||||||
|
//this.getavailablebedcountbytime(this.guadanorder.order_form.startdate, this.guadanorder.order_form.enddate);
|
||||||
|
},
|
||||||
|
|
||||||
|
getavailablebedcountbytime(startTime, endTime) {
|
||||||
|
axios.get(HTTP_HOST + 'api/region/bed/getavailablebedcountbytime', {
|
||||||
|
params: { startTime: startTime, endTime: endTime }
|
||||||
|
}).then((res) => {
|
||||||
|
this.availableBedCount = res.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
selectGuestForBed(item) {
|
||||||
|
this.selectedGuestForBed = item;
|
||||||
|
this.activeBuildingPanel = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 參數加入 building 用來串接完整名稱
|
||||||
|
assignBedToGuest(building, room, bed) {
|
||||||
|
if (!bed.isAvailableNow && bed.id !== this.selectedGuestForBed.bedUuid) return;
|
||||||
|
|
||||||
|
// 1. 安全轉換函數:強制將各種型別轉換為標準陣列
|
||||||
|
const ensureArray = (val) => {
|
||||||
|
if (!val) return [];
|
||||||
|
if (Array.isArray(val)) return val;
|
||||||
|
if (typeof val === 'string') return val.split(',').filter(c => c && c.trim() !== '');
|
||||||
|
if (typeof val === 'object') return Object.values(val).filter(c => c);
|
||||||
|
return [String(val)];
|
||||||
|
};
|
||||||
|
|
||||||
|
// 取出安全的床位條件陣列
|
||||||
|
const bedConditions = ensureArray(bed.limits);
|
||||||
|
// 2. 條件比對檢查 (檢核特殊需求)
|
||||||
|
const guestNeedsStr = this.selectedGuestForBed.specialNeeds || '';
|
||||||
|
// 將人員需求轉換為代碼陣列 (過濾空值)
|
||||||
|
const guestNeeds = guestNeedsStr ? guestNeedsStr.split(',').filter(c => c) : [];
|
||||||
|
// 床位條件 (若後端未傳回則預設為空陣列)
|
||||||
|
//const bedConditions = bed.limits || [];
|
||||||
|
|
||||||
|
// 檢查人員有的需求,床位是否未滿足 (找出不合適的條件代碼)
|
||||||
|
const unmatchedNeeds = guestNeeds.filter(need => !bedConditions.includes(need));
|
||||||
|
|
||||||
|
if (unmatchedNeeds.length > 0) {
|
||||||
|
// 將未滿足的需求代碼轉換為中文名稱
|
||||||
|
const unmatchedNames = unmatchedNeeds.map(code => {
|
||||||
|
const target = this.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
}).join('、');
|
||||||
|
|
||||||
|
// 跳出提示阻擋分配(或改為 confirm 提醒)
|
||||||
|
this.message = `不符合分配條件!該人員需要「${unmatchedNames}」,但此床位未具備對應條件。`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
return; // 中斷分配
|
||||||
|
}
|
||||||
|
// 將大樓名稱也組進去顯示
|
||||||
|
// 2. 取得床位具備的特殊條件文字
|
||||||
|
let bedConditionNotice = '';
|
||||||
|
if (bedConditions.length > 0) {
|
||||||
|
const bedConditionNames = bedConditions.map(code => {
|
||||||
|
const target = this.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
}).join('、');
|
||||||
|
bedConditionNotice = `\n【床位具備條件】:${bedConditionNames}`;
|
||||||
|
} else {
|
||||||
|
bedConditionNotice = `\n【床位具備條件】:無特殊限制`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 設定床位並跳出點擊後的二次提示
|
||||||
|
this.$set(this.selectedGuestForBed, 'bedName', `${building.name} - ${room.name} - ${bed.name}`);
|
||||||
|
this.$set(this.selectedGuestForBed, 'bedUuid', bed.id);
|
||||||
|
|
||||||
|
this.message = `已將「${building.name} ${room.name} ${bed.name}」分配給該明細!`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async getavailablebedbytime(startTime, endTime) {
|
||||||
|
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: startTime, endTime: endTime
|
||||||
|
}).then((res) => {
|
||||||
|
//this.availableBedCount = res.data;
|
||||||
|
return res.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async selectGuestForBed(item) {
|
||||||
|
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: item.checkinat, endTime: item.checkoutat
|
||||||
|
}).then((resp) => {
|
||||||
|
const rawData = resp.data;
|
||||||
|
|
||||||
|
const transformData = (data) => {
|
||||||
|
// 1. 使用 reduce 依據 regionUuid 與 roomUuid 進行分群
|
||||||
|
const grouped = data.availableBeds.reduce((acc, bed) => {
|
||||||
|
const regionId = bed.room.regionUuid;
|
||||||
|
const regionName = bed.room.regionName;
|
||||||
|
const roomId = bed.roomUuid;
|
||||||
|
const roomName = bed.room.name;
|
||||||
|
|
||||||
|
// 自動判斷性別限制 (若區域名稱包含"男眾"則為"男眾",反之女眾)
|
||||||
|
const genderLimit = regionName.includes('男眾') ? '男眾' : '女眾';
|
||||||
|
|
||||||
|
// 假設 statusCode '101' 代表可用 (true),其他代表不可用 (false)
|
||||||
|
const isAvailable = bed.statusCode === '101';
|
||||||
|
|
||||||
|
// 如果大樓/區域還不存在,建立新大樓
|
||||||
|
if (!acc[regionId]) {
|
||||||
|
acc[regionId] = {
|
||||||
|
id: regionId,
|
||||||
|
name: regionName,
|
||||||
|
roomsMap: {} // 使用 Map 方便後續依 roomId 查找
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果該大樓下的客房還不存在,建立新客房
|
||||||
|
if (!acc[regionId].roomsMap[roomId]) {
|
||||||
|
acc[regionId].roomsMap[roomId] = {
|
||||||
|
id: roomId,
|
||||||
|
name: `${roomName} (${genderLimit})`, // 組合區分名稱,如:客房1 (男眾)
|
||||||
|
genderLimit: genderLimit,
|
||||||
|
beds: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 將床位資料推入該客房的 beds 陣列中
|
||||||
|
acc[regionId].roomsMap[roomId].beds.push({
|
||||||
|
id: bed.uuid,
|
||||||
|
name: bed.name,
|
||||||
|
isAvailable: isAvailable,
|
||||||
|
limits: bed.limits || [],
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// 2. 將物件格式扁平化轉換成您要求的陣列格式 []
|
||||||
|
return Object.values(grouped).map(region => ({
|
||||||
|
id: region.id,
|
||||||
|
name: region.name,
|
||||||
|
rooms: Object.values(region.roomsMap) // 將 rooms 轉換成陣列
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 執行轉換
|
||||||
|
const result = transformData(rawData);
|
||||||
|
this.mockBuildings = result;
|
||||||
|
this.selectedGuestForBed = item;
|
||||||
|
this.activeRoomPanel = null;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
changeGuadanGuest(item) {//可以變更人員、床位
|
||||||
|
console.log('變更人員、床位', item);
|
||||||
|
},
|
||||||
|
confirmDeleteGuadanOrderGuest(item) {
|
||||||
|
console.log('取消預訂', item);
|
||||||
|
},
|
||||||
|
checkinGuadanGuest(item) {
|
||||||
|
console.log('入住', item);
|
||||||
|
},
|
||||||
|
showXuzhuGuestModalMethod(item) {
|
||||||
|
console.log('續住', item);
|
||||||
|
},
|
||||||
|
checkoutGuadanOrderGuest(item) {
|
||||||
|
console.log('退房', item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-group label {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+56
-12
@@ -49,20 +49,53 @@
|
|||||||
<v-icon>mdi-close</v-icon>
|
<v-icon>mdi-close</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
<v-toolbar-title>掛單作業</v-toolbar-title>
|
<v-toolbar-title>掛單作業</v-toolbar-title>
|
||||||
<%-- <v-spacer></v-spacer>
|
|
||||||
<v-toolbar-items>
|
|
||||||
<v-btn
|
|
||||||
dark
|
|
||||||
text
|
|
||||||
@click="dialog = false"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</v-btn>
|
|
||||||
</v-toolbar-items>--%>
|
|
||||||
</v-toolbar>
|
</v-toolbar>
|
||||||
<%--<v-card-title>Cafe Badilico</v-card-title>--%>
|
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<apply-component v-if="dialog" @close="dialog = false" />
|
<apply-component v-if="dialog" @close="dialog = false" />
|
||||||
|
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog
|
||||||
|
v-model="viewdialog"
|
||||||
|
min-width="85%"
|
||||||
|
max-width="95%"
|
||||||
|
min-height="900"
|
||||||
|
max-height="95%"
|
||||||
|
hide-overlay
|
||||||
|
transition="dialog-bottom-transition">
|
||||||
|
<v-card>
|
||||||
|
<v-toolbar dark color="primary">
|
||||||
|
<v-btn icon dark @click="viewdialog = false">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>掛單作業</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-card-text>
|
||||||
|
<view-component v-if="viewdialog" @close="viewdialog = false" :form-Data="formData" />
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
|
||||||
|
<v-dialog
|
||||||
|
v-model="editdialog"
|
||||||
|
min-width="85%"
|
||||||
|
max-width="95%"
|
||||||
|
min-height="900"
|
||||||
|
max-height="95%"
|
||||||
|
hide-overlay
|
||||||
|
transition="dialog-bottom-transition">
|
||||||
|
<v-card>
|
||||||
|
<v-toolbar dark color="primary">
|
||||||
|
<v-btn icon dark @click="editdialog = false">
|
||||||
|
<v-icon>mdi-close</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
<v-toolbar-title>掛單作業</v-toolbar-title>
|
||||||
|
</v-toolbar>
|
||||||
|
<v-card-text>
|
||||||
|
<edit-component v-if="editdialog" @close="editdialog = false" :form-Data="formData" />
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
@@ -82,17 +115,22 @@
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dialog: false,
|
dialog: false,
|
||||||
|
viewdialog: false,
|
||||||
|
editdialog: false,
|
||||||
notifications: false,
|
notifications: false,
|
||||||
sound: true,
|
sound: true,
|
||||||
widgets: false,
|
widgets: false,
|
||||||
currentView: 'main-component',
|
currentView: 'main-component',
|
||||||
twoData: {},
|
twoData: {},
|
||||||
|
formData: null,
|
||||||
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'main-component': httpVueLoader('./main.vue'),
|
'main-component': httpVueLoader('./main.vue'),
|
||||||
'apply-component': httpVueLoader('./apply.vue'),
|
'apply-component': httpVueLoader('./apply.vue'),
|
||||||
|
'view-component': httpVueLoader('./view.vue'),
|
||||||
|
'edit-component': httpVueLoader('./edit.vue'),
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
options: {
|
options: {
|
||||||
@@ -110,9 +148,15 @@
|
|||||||
console.log("go to new");
|
console.log("go to new");
|
||||||
this.dialog = true;
|
this.dialog = true;
|
||||||
} else if (item.action === "view") {
|
} else if (item.action === "view") {
|
||||||
console.log("go to view");
|
console.log("go to view", item.item);
|
||||||
|
this.formData = item.item.uuid;
|
||||||
|
//Object.assign(this.formData , item.item);
|
||||||
|
this.viewdialog = true;
|
||||||
} else if (item.action === "edit") {
|
} else if (item.action === "edit") {
|
||||||
|
//修改只能改主檔,明細要個別新增或個別修改
|
||||||
console.log("go to edit");
|
console.log("go to edit");
|
||||||
|
this.formData = item.item.uuid;
|
||||||
|
this.editdialog = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="container-fluid">
|
<div class="container-fluid">
|
||||||
<nav>
|
<nav>
|
||||||
<!--<a href="create.aspx" class="btn btn-primary">新增</a>-->
|
<!--<a href="create.aspx" class="btn btn-primary">新增</a>-->
|
||||||
<button class="btn btn-primary" @click.prevent="changeViews()">新增</button>
|
<button class="btn btn-primary" @click.prevent="changeViews('new',{})">新增</button>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="d-flex align-items-center gap-3">
|
<div class="d-flex align-items-center gap-3">
|
||||||
<label class="mb-0">掛單單號</label>
|
<label class="mb-0">掛單單號</label>
|
||||||
@@ -26,10 +26,10 @@
|
|||||||
:item-class="item => item.is_timeout ? 'row-timeout' : ''"
|
:item-class="item => item.is_timeout ? 'row-timeout' : ''"
|
||||||
hide-default-footer>
|
hide-default-footer>
|
||||||
<template #item.actions="{item}">
|
<template #item.actions="{item}">
|
||||||
<button class="btn btn-primary">查看</button>
|
<button class="btn btn-primary" @click.prevent="changeViews('view',item)">查看</button>
|
||||||
<!--<a :href="'view.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看</a>-->
|
<!--<a :href="'view.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看</a>-->
|
||||||
<button class="btn btn-secondary"
|
<button class="btn btn-secondary"
|
||||||
:style="item.guadan_status?.code == 502 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''">編輯</button>
|
:style="item.guadan_status?.code == 502 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''" @click.prevent="changeViews('edit',item)">編輯</button>
|
||||||
<!--<a :href="'create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-secondary"
|
<!--<a :href="'create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-secondary"
|
||||||
:style="item.guadan_status?.code == 502 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''">編輯</a>-->
|
:style="item.guadan_status?.code == 502 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''">編輯</a>-->
|
||||||
<button class="btn btn-outline-danger" :style="item.guest_count != 0 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''"
|
<button class="btn btn-outline-danger" :style="item.guest_count != 0 ? 'pointer-events: none; opacity: 0.5; cursor: not-allowed;' : ''"
|
||||||
@@ -147,9 +147,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
changeViews() {
|
changeViews(action,item) {
|
||||||
console.log("changeViews");
|
console.log("changeViews");
|
||||||
this.$emit('custom-event', { action: 'new', item: "1" });
|
this.$emit('custom-event', { action: action, item: item });
|
||||||
},
|
},
|
||||||
resetTableOptions() {
|
resetTableOptions() {
|
||||||
this.options = {
|
this.options = {
|
||||||
|
|||||||
@@ -0,0 +1,637 @@
|
|||||||
|
<template>
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div>
|
||||||
|
<v-tabs>
|
||||||
|
<v-tab value="tab-1" @click="tab='tab-1'">
|
||||||
|
掛單資訊
|
||||||
|
</v-tab>
|
||||||
|
<v-tab value="tab-2" @click="tab='tab-2'">
|
||||||
|
掛單明細
|
||||||
|
</v-tab>
|
||||||
|
</v-tabs>
|
||||||
|
|
||||||
|
<v-tabs-items v-model="tab">
|
||||||
|
<!-- ================== Tab 1: 掛單資訊 ================== -->
|
||||||
|
<v-tab-item value="tab-1">
|
||||||
|
<div class="border rounded p-3 bg-white shadow-sm mt-3">
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">掛單單號(不可修改)</label>
|
||||||
|
<div class="col-sm-4 text-left">
|
||||||
|
<input class="form-control" v-model="guadanorder.order_form.orderNo" readonly />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">關聯活動</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<select class="form-control" v-model="activityNum" disabled>
|
||||||
|
<option :value="null">未關聯</option>
|
||||||
|
<option v-for="activity in activityList" :key="activity.num" :value="activity.num">
|
||||||
|
{{activity.subject}}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預約開始日期</label>
|
||||||
|
<div class="col-sm-4 text-left">
|
||||||
|
<input class="form-control" disabled type="date" v-model="guadanorder.order_form.startdate" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預約結束日期</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" disabled type="date" v-model="guadanorder.order_form.enddate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預定人姓名</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" readonly v-model="guadanorder.order_form.bookerName" />
|
||||||
|
</div>
|
||||||
|
<label class="col-sm-2 col-form-label text-center">預定人電話</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<input class="form-control" readonly v-model="guadanorder.order_form.bookerPhone" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mt-3">
|
||||||
|
<label class="col-sm-2 col-form-label text-center">備註</label>
|
||||||
|
<div class="col-sm-4">
|
||||||
|
<textarea class="form-control" v-model="guadanorder.order_form.note"></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-tab-item>
|
||||||
|
|
||||||
|
<!-- ================== Tab 2: 掛單明細 ================== -->
|
||||||
|
<v-tab-item value="tab-2">
|
||||||
|
<v-row class="mt-2">
|
||||||
|
|
||||||
|
<!-- 左側:掛單明細列表 -->
|
||||||
|
<v-col cols="12" md="12">
|
||||||
|
<v-data-table :headers="guadanguest.headers" :items="guadanguest.items" class="elevation-1 rounded" dense>
|
||||||
|
<template #item.checkinat="{item}">
|
||||||
|
{{item.checkinat |timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template #item.checkoutat="{item}">
|
||||||
|
{{item.checkoutat |timeString('YYYY-MM-DD')}}
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.room="{item}">
|
||||||
|
<span v-if="item.bedName || item.room">
|
||||||
|
{{ item.room ? item.room.resion.join("/") : '' }}
|
||||||
|
{{ item.room ? item.room.name : '' }}
|
||||||
|
{{ item.bedName || '' }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-muted">
|
||||||
|
未分配床位
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
<!--<template v-slot:item.name="{item}">-->
|
||||||
|
<!--</template>-->
|
||||||
|
<!-- 姓名欄位改為輸入框:未輸入時預設顯示當前順位編號 -->
|
||||||
|
<template v-slot:item.name="{item}">
|
||||||
|
<v-text-field v-model="item.fullName"
|
||||||
|
dense
|
||||||
|
hide-details
|
||||||
|
outlined
|
||||||
|
class="my-1"
|
||||||
|
:placeholder="item.fullName==null?item.name:(String(guadanguest.items.indexOf(item) + 1))"
|
||||||
|
style="min-width: 50px;max-width:120px; font-size: 14px;"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<template v-slot:item.sex="{item}">
|
||||||
|
{{item.gender}}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:item.indicators="{item}">
|
||||||
|
<div class="d-flex justify-center align-center">
|
||||||
|
|
||||||
|
<v-chip small :color="getStatusColor(item.statuscode)" text-color="white" class="me-2" style="font-size: 12px; height: 20px;">
|
||||||
|
{{ item.statusName || '待入住' }}
|
||||||
|
</v-chip>
|
||||||
|
|
||||||
|
<v-tooltip bottom v-if="item.note">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-icon color="warning" v-bind="attrs" v-on="on" size="20" class="me-1">mdi-note-text</v-icon>
|
||||||
|
</template>
|
||||||
|
<span>備註: {{ item.note }}</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-icon v-else color="grey lighten-3" size="20" class="me-1">mdi-note-text-outline</v-icon>
|
||||||
|
|
||||||
|
<v-tooltip bottom v-if="item.specialNeeds && item.specialNeeds !== '無特殊需求'">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-icon color="error" v-bind="attrs" v-on="on" size="20">mdi-alert-circle</v-icon>
|
||||||
|
</template>
|
||||||
|
<span>特殊需求: {{ getSpecialNeedsText(item.specialNeeds) }}</span>
|
||||||
|
</v-tooltip>
|
||||||
|
<v-icon v-else color="grey lighten-3" size="20">mdi-alert-circle-outline</v-icon>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
</v-data-table>
|
||||||
|
</v-col>
|
||||||
|
|
||||||
|
|
||||||
|
</v-row>
|
||||||
|
</v-tab-item>
|
||||||
|
</v-tabs-items>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<v-dialog v-model="message_dialog" max-width="500">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title class="text-h6">系統提示</v-card-title>
|
||||||
|
<v-card-text class="pt-4">{{message}}</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="primary" text @click="message_dialog = false">確認</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
|
||||||
|
<v-dialog v-model="checkInGuest.showSelectGuadanOrderGuest" max-width="600">
|
||||||
|
<v-card>
|
||||||
|
<v-card-title>設定人數條件</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-container>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12"><v-text-field label="人數" type="number" v-model="e4"></v-text-field></v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-menu v-model="menu2" :close-on-content-click="false" transition="scale-transition" offset-y min-width="auto">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field v-model="s_date" label="開始日期" prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="s_date" @input="menu2 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-menu v-model="menu3" :close-on-content-click="false" transition="scale-transition" offset-y min-width="auto">
|
||||||
|
<template v-slot:activator="{ on, attrs }">
|
||||||
|
<v-text-field v-model="e_date" label="結束日期" prepend-icon="mdi-calendar" readonly v-bind="attrs" v-on="on"></v-text-field>
|
||||||
|
</template>
|
||||||
|
<v-date-picker v-model="e_date" @input="menu3 = false"></v-date-picker>
|
||||||
|
</v-menu>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-select :items="e2" v-model="e5" label="性別"></v-select>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12">
|
||||||
|
<v-select v-model="e6" :items="states" label="特殊需求" multiple hint="選擇條件" persistent-hint></v-select>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</v-card-text>
|
||||||
|
<v-card-actions>
|
||||||
|
<v-spacer></v-spacer>
|
||||||
|
<v-btn color="grey" text @click="checkInGuest.showSelectGuadanOrderGuest = false">關閉</v-btn>
|
||||||
|
<v-btn color="primary" @click.prevent="genGuestList">產生</v-btn>
|
||||||
|
</v-card-actions>
|
||||||
|
</v-card>
|
||||||
|
</v-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
module.exports = {
|
||||||
|
name: "view-component",
|
||||||
|
props: {
|
||||||
|
formData: {
|
||||||
|
type: String,
|
||||||
|
default: "",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tab: "tab-1",
|
||||||
|
e1: null,
|
||||||
|
e2: ['請選擇', '男眾', '女眾'],
|
||||||
|
e4: "",
|
||||||
|
e5: "",
|
||||||
|
e6: [],
|
||||||
|
s_date: null,
|
||||||
|
menu2: false,
|
||||||
|
menu3: false,
|
||||||
|
e_date: null,
|
||||||
|
states: [
|
||||||
|
//'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
|
||||||
|
],
|
||||||
|
message_dialog: false,
|
||||||
|
message: "",
|
||||||
|
activityList: [],
|
||||||
|
activityNum: null,
|
||||||
|
availableBedCount: { male: 0, female: 0 },
|
||||||
|
|
||||||
|
guadanorder: {
|
||||||
|
order_form: {
|
||||||
|
uuid: null,
|
||||||
|
startdate: null,
|
||||||
|
enddate: null,
|
||||||
|
note: null,
|
||||||
|
orderNo: null,
|
||||||
|
bookerName: null,
|
||||||
|
bookerPhone: null,
|
||||||
|
bookerFollowerNum: null,
|
||||||
|
activityNum: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
guadanguest: {
|
||||||
|
headers: [
|
||||||
|
{ text: '標記/狀態', value: 'indicators', align: 'center', sortable: false, width: '130px' },
|
||||||
|
{ text: '姓名', value: 'name' },
|
||||||
|
{ text: '性別', value: 'sex' },
|
||||||
|
{ text: '掛單開始時間', value: 'checkinat' },
|
||||||
|
{ text: '掛單結束時間', value: 'checkoutat' },
|
||||||
|
{ text: '床位', value: 'room' },
|
||||||
|
{ text: '操作', value: 'actions', sortable: false },
|
||||||
|
],
|
||||||
|
items: [],
|
||||||
|
},
|
||||||
|
|
||||||
|
checkInGuest: {
|
||||||
|
showSelectGuadanOrderGuest: false,
|
||||||
|
inGuest: {
|
||||||
|
checkInAt: null,
|
||||||
|
checkOutAt: null,
|
||||||
|
orderNo: null,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
automaticBedAllocation: {
|
||||||
|
showModal: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
selectedGuestForBed: null,
|
||||||
|
activeBuildingPanel: null, // 控制大樓的展開面板
|
||||||
|
|
||||||
|
// 模擬資料層級: 大樓 -> 房間 -> 床位
|
||||||
|
mockBuildings: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
activityNum: {
|
||||||
|
handler(newVal) {
|
||||||
|
let act = this.activityList.find(activity => activity.num == newVal);
|
||||||
|
if (act) {
|
||||||
|
this.guadanorder.order_form.startdate = act.startDate;
|
||||||
|
this.guadanorder.order_form.enddate = act.endDate;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
},
|
||||||
|
formData: {
|
||||||
|
handler(newVal) {
|
||||||
|
//用掛單的uuid去抓掛單資料跟明細檔
|
||||||
|
console.log('掛單uuid', newVal);
|
||||||
|
if (newVal!="") {
|
||||||
|
this.getGuadanData();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.getActivityList()
|
||||||
|
this.getGuadanLimits()
|
||||||
|
console.log('掛單明細', this.formData);
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
assignedBedUuids() {
|
||||||
|
return this.guadanguest.items
|
||||||
|
.map(item => item.bedUuid)
|
||||||
|
.filter(uuid => uuid);
|
||||||
|
},
|
||||||
|
filteredMockBuildings() {
|
||||||
|
if (!this.selectedGuestForBed) return [];
|
||||||
|
|
||||||
|
const guestGender = this.selectedGuestForBed.gender;
|
||||||
|
const currentGuestBedUuid = this.selectedGuestForBed.bedUuid;
|
||||||
|
|
||||||
|
return this.mockBuildings.map(building => {
|
||||||
|
// 過濾房間並處理床位動態狀態
|
||||||
|
const filteredRooms = building.rooms.map(room => {
|
||||||
|
return {
|
||||||
|
...room,
|
||||||
|
beds: room.beds.map(bed => {
|
||||||
|
const isTakenByOthers = this.assignedBedUuids.includes(bed.id) && bed.id !== currentGuestBedUuid;
|
||||||
|
return {
|
||||||
|
...bed,
|
||||||
|
isAvailableNow: bed.isAvailable && !isTakenByOthers
|
||||||
|
};
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}).filter(room =>
|
||||||
|
!guestGender || guestGender === '請選擇' || room.genderLimit === guestGender
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...building,
|
||||||
|
rooms: filteredRooms
|
||||||
|
};
|
||||||
|
}).filter(building => building.rooms.length > 0); // 隱藏完全沒有符合條件房間的大樓
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getGuadanData() {//抓出掛單資料根明細檔
|
||||||
|
let self = this;
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/getorderbyuuid', { uuid: self.formData }).then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
console.log('掛單資料', res.data);
|
||||||
|
self.guadanorder.order_form = res.data.order_form;
|
||||||
|
self.guadanguest.items = res.data.details;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getStatusColor(code) {
|
||||||
|
switch (code) {
|
||||||
|
case '401': return 'blue';
|
||||||
|
case '402': return 'green';
|
||||||
|
default: return 'grey';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getSpecialNeedsText(specialNeedsCodes) {
|
||||||
|
if (!specialNeedsCodes) return '';
|
||||||
|
const codes = specialNeedsCodes.split(',');
|
||||||
|
let self = this;
|
||||||
|
const names = codes.map(code => {
|
||||||
|
console.log("getSpecialNeedsText:", self.states, this.states);
|
||||||
|
const target = self.states.find(s => s.value === code);
|
||||||
|
return target ? target.text : code;
|
||||||
|
});
|
||||||
|
return names.join('、');
|
||||||
|
},
|
||||||
|
// 算整棟大樓的可用床位總和
|
||||||
|
buildingAvailableBedsCount(building) {
|
||||||
|
let count = 0;
|
||||||
|
building.rooms.forEach(room => {
|
||||||
|
count += room.beds.filter(b => b.isAvailableNow).length;
|
||||||
|
});
|
||||||
|
return count;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 算單一房間的可用床位
|
||||||
|
roomAvailableBedsCount(room) {
|
||||||
|
return room.beds.filter(b => b.isAvailableNow).length;
|
||||||
|
},
|
||||||
|
getGuadanLimits() {//抓掛單條件
|
||||||
|
this.states.length = 0; // 清空陣列
|
||||||
|
let self = this;
|
||||||
|
let data = [];
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/getGuadanLimit').then((res) => {
|
||||||
|
if (res.status == 200) {
|
||||||
|
res.data.forEach(item => {
|
||||||
|
console.log('掛單條件', item);
|
||||||
|
self.states.push({
|
||||||
|
text: item.paramName,
|
||||||
|
value: item.paramNo
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
genGuestList() {
|
||||||
|
if (!this.e4) { console.log('請輸入人數'); return; }
|
||||||
|
if (!this.e5 || this.e5 == 0) { console.log("請選擇男眾或女眾"); return; }
|
||||||
|
if (!this.s_date) { console.log('請選擇開始日期'); return; }
|
||||||
|
if (!this.e_date) { console.log('請選擇結束日期'); return; }
|
||||||
|
|
||||||
|
for (let i = 0; i < this.e4; i++) {
|
||||||
|
const tempUuid = 'temp-' + Date.now() + '-' + i;
|
||||||
|
this.guadanguest.items.push({
|
||||||
|
uuid: tempUuid,
|
||||||
|
fullName: '',
|
||||||
|
gender: this.e5,
|
||||||
|
checkinat: this.s_date,
|
||||||
|
checkoutat: this.e_date,
|
||||||
|
statuscode: '401',
|
||||||
|
statusName: '已預訂',
|
||||||
|
note: '',
|
||||||
|
specialNeeds: this.e6.join(",")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.s_date = null;
|
||||||
|
this.e_date = null;
|
||||||
|
this.e5 = "";
|
||||||
|
this.e4 = null;
|
||||||
|
this.e6 = [];
|
||||||
|
this.checkInGuest.showSelectGuadanOrderGuest = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getActivityList() {
|
||||||
|
const params = { page: '1', pageSize: 10000 };
|
||||||
|
axios.post(HTTP_HOST + 'api/activity/GetListNewYet', {
|
||||||
|
up_time1: moment(new Date()).format('YYYY-MM-DD')
|
||||||
|
}, { params: params }).then((res) => {
|
||||||
|
if (res.status == 200 && res.data && res.data.list) {
|
||||||
|
this.activityList = res.data.list;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
validateOrderForm() {
|
||||||
|
if (!this.guadanorder.order_form.startdate) { this.message = '請輸入開始日期'; this.message_dialog = true; return false; }
|
||||||
|
if (!this.guadanorder.order_form.enddate) { this.message = '請輸入結束日期'; this.message_dialog = true; return false; }
|
||||||
|
if (!this.guadanorder.order_form.bookerName) { this.message = '請輸入姓名'; this.message_dialog = true; return false; }
|
||||||
|
if (!this.guadanorder.order_form.bookerPhone) { this.message = '請輸入電話'; this.message_dialog = true; return false; }
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
createGuadanOrder() {
|
||||||
|
if (!this.validateOrderForm()) return;
|
||||||
|
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/create', this.guadanorder.order_form)
|
||||||
|
.then((res => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料建立成功'
|
||||||
|
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||||
|
this.guadanorder.order_form.orderNo = res.data.guaDanOrderNo;
|
||||||
|
|
||||||
|
const currentUrl = window.location.origin + window.location.pathname;
|
||||||
|
window.location.href = `${currentUrl}?orderId=${res.data.guaDanOrderNo}`;
|
||||||
|
})).catch((error) => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '建立掛單資料失敗:' + (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
updateGuadanOrder() {
|
||||||
|
|
||||||
|
let detail = []
|
||||||
|
this.guadanguest.items.forEach(item => {
|
||||||
|
console.log('明細', item);
|
||||||
|
detail.push({
|
||||||
|
uuid: item.uuid,
|
||||||
|
fullName: item.fullName,
|
||||||
|
gender: item.gender,
|
||||||
|
checkInAt: item.checkinat,
|
||||||
|
checkOutAt: item.checkoutat,
|
||||||
|
statuscode: item.statuscode,
|
||||||
|
statusName: item.statusName,
|
||||||
|
note: item.note,
|
||||||
|
handi: item.specialNeeds,
|
||||||
|
bedUuid: item.bedUuid,
|
||||||
|
name: item.fullName
|
||||||
|
})
|
||||||
|
})
|
||||||
|
//console.log('掛單主檔', this.guadanorder.order_form);
|
||||||
|
if (!this.validateOrderForm()) return;
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/saveGandan', { order: this.guadanorder.order_form, detail: detail })
|
||||||
|
.then((res => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料更新成功'
|
||||||
|
this.guadanorder.order_form.uuid = res.data.uuid;
|
||||||
|
})).catch((error) => {
|
||||||
|
this.message_dialog = true
|
||||||
|
this.message = '掛單資料更新失敗:' + (error.response?.data?.message || error.message)
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
showCheckInModal() {
|
||||||
|
//if (!this.guadanorder.order_form.uuid) {
|
||||||
|
// this.message_dialog = true;
|
||||||
|
// this.message = '請先儲存掛單資訊';
|
||||||
|
// return;
|
||||||
|
//}
|
||||||
|
this.checkInGuest.inGuest.checkInAt = this.guadanorder.order_form.startdate || null;
|
||||||
|
this.checkInGuest.inGuest.checkOutAt = this.guadanorder.order_form.enddate || null;
|
||||||
|
this.checkInGuest.inGuest.orderNo = this.guadanorder.order_form.orderNo;
|
||||||
|
this.s_date = this.guadanorder.order_form.startdate || null;
|
||||||
|
this.e_date = this.guadanorder.order_form.enddate || null;
|
||||||
|
this.checkInGuest.showSelectGuadanOrderGuest = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
showAutomaticBedAllocation() {
|
||||||
|
if (!this.guadanorder.order_form.uuid) {
|
||||||
|
this.message_dialog = true;
|
||||||
|
this.message = '請先儲存掛單資訊';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.automaticBedAllocation.showModal = true;
|
||||||
|
this.getavailablebedcountbytime(this.guadanorder.order_form.startdate, this.guadanorder.order_form.enddate);
|
||||||
|
},
|
||||||
|
|
||||||
|
getavailablebedcountbytime(startTime, endTime) {
|
||||||
|
axios.get(HTTP_HOST + 'api/region/bed/getavailablebedcountbytime', {
|
||||||
|
params: { startTime: startTime, endTime: endTime }
|
||||||
|
}).then((res) => {
|
||||||
|
this.availableBedCount = res.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
selectGuestForBed(item) {
|
||||||
|
this.selectedGuestForBed = item;
|
||||||
|
this.activeBuildingPanel = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
// 參數加入 building 用來串接完整名稱
|
||||||
|
assignBedToGuest(building, room, bed) {
|
||||||
|
if (!bed.isAvailableNow && bed.id !== this.selectedGuestForBed.bedUuid) return;
|
||||||
|
|
||||||
|
// 將大樓名稱也組進去顯示
|
||||||
|
this.$set(this.selectedGuestForBed, 'bedName', `${building.name} - ${room.name} - ${bed.name}`);
|
||||||
|
this.$set(this.selectedGuestForBed, 'bedUuid', bed.id);
|
||||||
|
|
||||||
|
this.message = `已將「${building.name} ${room.name} ${bed.name}」分配給該明細!`;
|
||||||
|
this.message_dialog = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
async getavailablebedbytime(startTime, endTime) {
|
||||||
|
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: startTime, endTime: endTime
|
||||||
|
}).then((res) => {
|
||||||
|
//this.availableBedCount = res.data;
|
||||||
|
return res.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
async selectGuestForBed(item) {
|
||||||
|
console.log('選床', item);
|
||||||
|
axios.post(HTTP_HOST + 'api/region/bed/getAvailableBeds', {
|
||||||
|
startTime: item.checkinat, endTime: item.checkoutat
|
||||||
|
}).then((resp) => {
|
||||||
|
const rawData = resp.data;
|
||||||
|
|
||||||
|
const transformData = (data) => {
|
||||||
|
// 1. 使用 reduce 依據 regionUuid 與 roomUuid 進行分群
|
||||||
|
const grouped = data.availableBeds.reduce((acc, bed) => {
|
||||||
|
const regionId = bed.room.regionUuid;
|
||||||
|
const regionName = bed.room.regionName;
|
||||||
|
const roomId = bed.roomUuid;
|
||||||
|
const roomName = bed.room.name;
|
||||||
|
|
||||||
|
// 自動判斷性別限制 (若區域名稱包含"男眾"則為"男眾",反之女眾)
|
||||||
|
const genderLimit = regionName.includes('男眾') ? '男眾' : '女眾';
|
||||||
|
|
||||||
|
// 假設 statusCode '101' 代表可用 (true),其他代表不可用 (false)
|
||||||
|
const isAvailable = bed.statusCode === '101';
|
||||||
|
|
||||||
|
// 如果大樓/區域還不存在,建立新大樓
|
||||||
|
if (!acc[regionId]) {
|
||||||
|
acc[regionId] = {
|
||||||
|
id: regionId,
|
||||||
|
name: regionName,
|
||||||
|
roomsMap: {} // 使用 Map 方便後續依 roomId 查找
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果該大樓下的客房還不存在,建立新客房
|
||||||
|
if (!acc[regionId].roomsMap[roomId]) {
|
||||||
|
acc[regionId].roomsMap[roomId] = {
|
||||||
|
id: roomId,
|
||||||
|
name: `${roomName} (${genderLimit})`, // 組合區分名稱,如:客房1 (男眾)
|
||||||
|
genderLimit: genderLimit,
|
||||||
|
beds: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 將床位資料推入該客房的 beds 陣列中
|
||||||
|
acc[regionId].roomsMap[roomId].beds.push({
|
||||||
|
id: bed.uuid,
|
||||||
|
name: bed.name,
|
||||||
|
isAvailable: isAvailable
|
||||||
|
});
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
// 2. 將物件格式扁平化轉換成您要求的陣列格式 []
|
||||||
|
return Object.values(grouped).map(region => ({
|
||||||
|
id: region.id,
|
||||||
|
name: region.name,
|
||||||
|
rooms: Object.values(region.roomsMap) // 將 rooms 轉換成陣列
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
// 執行轉換
|
||||||
|
const result = transformData(rawData);
|
||||||
|
//console.log(JSON.stringify(result, null, 4));
|
||||||
|
|
||||||
|
|
||||||
|
this.mockBuildings = result;
|
||||||
|
this.selectedGuestForBed = item;
|
||||||
|
this.activeRoomPanel = null;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
confirmDeleteGuadanOrderGuest(item) {
|
||||||
|
console.log('取消預訂', item);
|
||||||
|
},
|
||||||
|
checkinGuadanGuest(item) {
|
||||||
|
console.log('入住', item);
|
||||||
|
},
|
||||||
|
showXuzhuGuestModalMethod(item) {
|
||||||
|
console.log('續住', item);
|
||||||
|
},
|
||||||
|
checkoutGuadanOrderGuest(item) {
|
||||||
|
console.log('退房', item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.form-group label {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -213,6 +213,13 @@
|
|||||||
:headers="room_bed.bed_headers"
|
:headers="room_bed.bed_headers"
|
||||||
:items ="room_bed.bed_items"
|
:items ="room_bed.bed_items"
|
||||||
>
|
>
|
||||||
|
<!-- 顯示設定條件名稱 -->
|
||||||
|
<template #item.limits="{item}">
|
||||||
|
<span v-if="item.limits && item.limits.length">
|
||||||
|
{{ getConditionNames(item.limits) }}
|
||||||
|
</span>
|
||||||
|
<span v-else class="text-muted">無</span>
|
||||||
|
</template>
|
||||||
<template #item.isactive="{item}">
|
<template #item.isactive="{item}">
|
||||||
{{item.isactive ? '啟用' : '停用'}}
|
{{item.isactive ? '啟用' : '停用'}}
|
||||||
</template>
|
</template>
|
||||||
@@ -257,7 +264,20 @@
|
|||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- ⭐️ 新增:設定條件選單 ⭐️ -->
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label d-block">設定條件</label>
|
||||||
|
<div v-for="item in room_bed.bed_conditions" :key="item.paramNo" class="form-check form-check-inline">
|
||||||
|
<input class="form-check-input"
|
||||||
|
type="checkbox"
|
||||||
|
:id="'cond_' + item.paramNo"
|
||||||
|
:value="item.paramNo"
|
||||||
|
v-model="room_bed.newBedForm.Limits">
|
||||||
|
<label class="form-check-label" :for="'cond_' + item.paramNo">
|
||||||
|
{{ item.paramName }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-check form-switch mb-3">
|
<div class="form-check form-switch mb-3">
|
||||||
<input type="checkbox" class="form-check-input" id="isActiveCheck" v-model="room_bed.newBedForm.IsActive" />
|
<input type="checkbox" class="form-check-input" id="isActiveCheck" v-model="room_bed.newBedForm.IsActive" />
|
||||||
<label class="form-check-label" for="isActiveCheck">是否啟用</label>
|
<label class="form-check-label" for="isActiveCheck">是否啟用</label>
|
||||||
@@ -547,9 +567,15 @@
|
|||||||
{ text: '床位編號', value: 'uuid' },
|
{ text: '床位編號', value: 'uuid' },
|
||||||
{ text: '床位名稱', value: 'name' },
|
{ text: '床位名稱', value: 'name' },
|
||||||
{ text: '床位狀態', value: 'statuscode' },
|
{ text: '床位狀態', value: 'statuscode' },
|
||||||
|
{ text: '設定條件', value: 'limits' }, // 可選:在表格中顯示條件
|
||||||
{ text: '是否啟用', value: 'isactive' },
|
{ text: '是否啟用', value: 'isactive' },
|
||||||
{ text: '', value: 'action' },
|
{ text: '', value: 'action' },
|
||||||
],
|
],
|
||||||
|
// 1. 新增條件來源選單 (可經由 API 載入,這裡預設填入您提供的 JSON)
|
||||||
|
bed_conditions: [
|
||||||
|
{ "paramNo": "01", "paramName": "需要輪椅", "remark": "" },
|
||||||
|
{ "paramNo": "02", "paramName": "需要拐杖", "remark": "" }
|
||||||
|
],
|
||||||
newBedForm: {
|
newBedForm: {
|
||||||
uuid: null,
|
uuid: null,
|
||||||
RegionUuid: null,
|
RegionUuid: null,
|
||||||
@@ -557,13 +583,37 @@
|
|||||||
statuscode: null,
|
statuscode: null,
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
Gender: null,
|
Gender: null,
|
||||||
|
Limits:[]
|
||||||
},
|
},
|
||||||
showBedModal: false,
|
showBedModal: false,
|
||||||
bed_status: [], //床位狀態列表
|
bed_status: [], //床位狀態列表
|
||||||
|
//bed_conditions:[]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
loadBedConditions() {
|
||||||
|
this.room_bed.bed_conditions = 0; // 清空陣列
|
||||||
|
let self = this;
|
||||||
|
let data = [];
|
||||||
|
axios.post(HTTP_HOST + 'api/guadan/getGuadanLimit').then((res) => {
|
||||||
|
|
||||||
|
if (res.status == 200) {
|
||||||
|
res.data.forEach(item => {
|
||||||
|
console.log('掛單條件', item);
|
||||||
|
})
|
||||||
|
this.room_bed.bed_conditions = res.data;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getConditionNames(conditionIds) {
|
||||||
|
let condition = conditionIds.split(",");
|
||||||
|
if (!condition || !Array.isArray(condition)) return '';
|
||||||
|
return this.room_bed.bed_conditions
|
||||||
|
.filter(c => condition.includes(c.paramNo))
|
||||||
|
.map(c => c.paramName)
|
||||||
|
.join('、');
|
||||||
|
},
|
||||||
closeBedInUsedModal() {
|
closeBedInUsedModal() {
|
||||||
this.bed_is_used_modal = false;
|
this.bed_is_used_modal = false;
|
||||||
this.bed_is_used_modal_message = null;
|
this.bed_is_used_modal_message = null;
|
||||||
@@ -759,6 +809,7 @@
|
|||||||
statuscode: "101",
|
statuscode: "101",
|
||||||
IsActive: true,
|
IsActive: true,
|
||||||
Gender: this.currentSelectRoom.gender, // 不設預設值,強制選擇
|
Gender: this.currentSelectRoom.gender, // 不設預設值,強制選擇
|
||||||
|
Limits: [] // 重置為空陣列
|
||||||
};
|
};
|
||||||
this.room_bed.showBedModal = true;
|
this.room_bed.showBedModal = true;
|
||||||
},
|
},
|
||||||
@@ -834,13 +885,24 @@
|
|||||||
statuscode: bed.statuscode,
|
statuscode: bed.statuscode,
|
||||||
IsActive: bed.isactive,
|
IsActive: bed.isactive,
|
||||||
Gender: bed.gender,
|
Gender: bed.gender,
|
||||||
|
// 確保將後端回傳的條件清單帶入(如果是字串或陣列,建議統一轉為陣列)
|
||||||
|
Limits: bed.limits ? [...bed.limits] : []
|
||||||
};
|
};
|
||||||
this.room_bed.showBedModal = true;
|
this.room_bed.showBedModal = true;
|
||||||
},
|
},
|
||||||
async saveEditBed() {
|
async saveEditBed() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axios.post(HTTP_HOST + 'api/region/bed/update', this.room_bed.newBedForm);
|
let data= {
|
||||||
|
uuid: this.room_bed.newBedForm.uuid,
|
||||||
|
RoomUuid: this.room_bed.newBedForm.RoomUuid,
|
||||||
|
Name: this.room_bed.newBedForm.Name,
|
||||||
|
statuscode: this.room_bed.newBedForm.statuscode,
|
||||||
|
IsActive: this.room_bed.newBedForm.IsActive,
|
||||||
|
Gender: this.room_bed.newBedForm.Gender,
|
||||||
|
Limits: this.room_bed.newBedForm.Limits.join(',') // 假設後端接受逗號分隔的字串
|
||||||
|
};
|
||||||
|
await axios.post(HTTP_HOST + 'api/region/bed/update', data);
|
||||||
this.room_bed.showBedModal = false;
|
this.room_bed.showBedModal = false;
|
||||||
|
|
||||||
const updated = this.room_bed.newBedForm;
|
const updated = this.room_bed.newBedForm;
|
||||||
@@ -852,7 +914,8 @@
|
|||||||
roomUuid: updated.RoomUuid,
|
roomUuid: updated.RoomUuid,
|
||||||
name: updated.Name,
|
name: updated.Name,
|
||||||
statuscode: updated.statuscode,
|
statuscode: updated.statuscode,
|
||||||
isactive: updated.IsActive
|
isactive: updated.IsActive,
|
||||||
|
limits: updated.Limits
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1015,6 +1078,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.loadBedConditions();
|
||||||
this.loadRegions();
|
this.loadRegions();
|
||||||
this.loadRegionType();
|
this.loadRegionType();
|
||||||
this.getBedStatus();
|
this.getBedStatus();
|
||||||
|
|||||||
Reference in new issue
Block a user