This commit is contained in:
minom committed 2026-11-10 18:03:52 +08:00
1 parent 9e251fc7d4
commit 98ee587dc0
6 files changed
+1154 -216

No files matched your search

+116
View File
@@ -304,7 +304,122 @@ public class guadanOrderController : ApiController
if (json != null && json.guest != null)
{
var guest = json.guest;
if (((string)guest.uuid).StartsWith("temp"))
{
//建立掛單明細
var new_guest = new GuaDanOrderGuest
{
GuaDanOrderNo = guest.guaDanOrderNo,
Uuid = Guid.NewGuid(),
StatusCode = GuaDanOrderGuest.STATUS_BOOKED, // 預約狀態
RoomUuid = guest.roomUuid,
BedUuid = guest.bedUuid,
CheckInAt = guest.checkInAt,
CheckOutAt = guest.checkOutAt,
Sex = guest.gender,
Handi = guest.handi,
IsDeleted = false,
Name = guest.name,
OrderUuid=guest.orderUuid,
};
//_db.GuaDanOrderGuest.Remove(old);
_db.GuaDanOrderGuest.Add(new_guest);
int totalDays = (new_guest.CheckOutAt.Value - new_guest.CheckInAt.Value).Days;
var bedList = new List<RegionAndRoomAndBedSchedule>();
for (int i = 0; i < totalDays; i++)
{
var scheduleDate = new_guest.CheckOutAt.Value.AddDays(i);
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單",
ScheduleDate = scheduleDate,
IsDeleted = false,
IsCancel = false,
TargetUuid = new_guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = new_guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = new_guest.Uuid,
};
//_db.RegionAndRoomAndBedSchedule.Add(schedul);
bedList.Add(schedul);
}
_db.RegionAndRoomAndBedSchedule.AddRange(bedList);
}
else
{
if (!Guid.TryParse((string)guest.uuid, out Guid targetGuid))
{
return BadRequest("無效的 GUID 格式");
}
var old = _db.GuaDanOrderGuest.Where(a => a.Uuid == targetGuid).FirstOrDefault();
if (old == null)
{
return BadRequest("未找到對應掛單明細資料");
}
var sch = _db.RegionAndRoomAndBedSchedule.Where(a => a.GuaDanOrderGuestUuid == old.Uuid).ToList();
if (sch != null)
{
_db.RegionAndRoomAndBedSchedule.RemoveRange(sch);
}
//建立掛單明細
var new_guest = new GuaDanOrderGuest
{
GuaDanOrderNo = old.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
StatusCode = GuaDanOrderGuest.STATUS_BOOKED, // 預約狀態
RoomUuid = guest.roomUuid,
BedUuid = guest.bedUuid,
CheckInAt = guest.checkInAt,
CheckOutAt = guest.checkOutAt,
Sex = guest.gender,
Handi = guest.handi,
IsDeleted = false,
Name = guest.name,
};
_db.GuaDanOrderGuest.Remove(old);
_db.GuaDanOrderGuest.Add(new_guest);
int totalDays = (new_guest.CheckOutAt.Value - new_guest.CheckInAt.Value).Days;
var bedList = new List<RegionAndRoomAndBedSchedule>();
for (int i = 0; i < totalDays; i++)
{
var scheduleDate = new_guest.CheckOutAt.Value.AddDays(i);
var schedul = new RegionAndRoomAndBedSchedule
{
Title = "掛單",
Description = "床位掛單",
ScheduleDate = scheduleDate,
IsDeleted = false,
IsCancel = false,
TargetUuid = new_guest.BedUuid,
UseType = (int)RegionAndRoomAndBedSchedule.SchedulePurpose.Bed_Reservation,
CreatedAt = DateTime.Now,
GuaDanOrderNo = new_guest.GuaDanOrderNo,
Uuid = Guid.NewGuid(),
GuaDanOrderGuestUuid = new_guest.Uuid,
};
//_db.RegionAndRoomAndBedSchedule.Add(schedul);
bedList.Add(schedul);
}
_db.RegionAndRoomAndBedSchedule.AddRange(bedList);
}
_db.SaveChanges();
}
else {
return BadRequest("請提供掛單明細資料");
}
return Ok();
}
@@ -383,6 +498,7 @@ public class guadanOrderController : ApiController
Handi = detail.handi,
IsDeleted = false,
Name = detail.name,
OrderUuid=guadanorder.Uuid
};
list.Add(guest);
if (!Guid.TryParse((string)detail.bedUuid, out Guid targetGuid))
+12 -1
View File
@@ -61,7 +61,9 @@ public class regionController : ApiController
{
query = query.Where(r => r.Room.Any(room => room.Uuid == filter.RoomId.Value));
}
var allGuaDanLimits = _db.GuaDanLimits
.Select(g => new { g.ParamNo, g.ParamName })
.ToList();
var data = query
.ToList()
.Select(r => new
@@ -101,6 +103,15 @@ public class regionController : ApiController
bed.StatusCode,
bed.IsActive,
bed.IsDeleted,
Limits = allGuaDanLimits
.Where(g => (bed.Limits ?? "")
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Contains(g.ParamNo))
.Select(g => new
{
g.ParamNo,
g.ParamName
}).ToList(),
canuse = bed.IsAvailableDuring(startDate, endDate, _db),
statusname = bed.RegionRoomBedStatus.Name,
schedules = _db.RegionAndRoomAndBedSchedule
+46 -18
View File
@@ -187,7 +187,7 @@
<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) }})
{{ building.regionPath?building.regionPath.join("/"):building.name }} (剩餘: {{ buildingAvailableBedsCount(building) }})
</div>
</v-expansion-panel-header>
@@ -223,7 +223,7 @@
<span>
{{ bed.name }}
<template v-if="bed.limits && bed.limits.length > 0">
<br>【具備條件】:{{ getSpecialNeedsText(Array.isArray(bed.limits) ? bed.limits.join(',') : String(bed.limits)) }}
<br>【具備條件】:{{ getSpecialNeedsText(Array.isArray(bed.limits)&&bed.limits!=undefined ? bed.limits.join(',') : String(bed.limits)) }}
</template>
<template v-else>
<br>(無特殊限制床位)
@@ -330,7 +330,7 @@
menu3: false,
e_date: null,
states: [
'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
//'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
],
message_dialog: false,
message: "",
@@ -416,6 +416,7 @@
const guestNeeds = (this.selectedGuestForBed.specialNeeds || '').split(',').filter(c => c);
return this.mockBuildings.map(building => {
console.log('filteredMockBuildings:', building);
// 過濾房間並處理床位動態狀態
const filteredRooms = building.rooms.map(room => {
return {
@@ -425,8 +426,9 @@
// 檢查條件是否完全滿足
const bedConditions = bed.limits || [];
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
building["regionPath"] = bed.regionPath;
room["regionPath"] = bed.regionPath;
return {
...bed,
isAvailableNow: bed.isAvailable && !isTakenByOthers && isMatchConditions,
@@ -661,15 +663,27 @@
this.message_dialog = true;
return;
}
// 2. 關鍵排序:依據「特殊需求數量」降冪排序 (需求多的人先選床位,避免資源被搶)
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. 逐一處理未分配床位的人員
// 3. 安全轉陣列函數
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)];
};
// 4. 逐一處理未分配床位的人員
for (const guest of unassignedGuests) {
try {
// 取得該人員入住時間區間的可分配床位
@@ -679,12 +693,12 @@
});
const availableBeds = resp.data?.availableBeds || [];
// 過濾出真正的特殊需求 (排除「無特殊需求」與空字串)
// 過濾出人員真正的特殊需求 (排除「無特殊需求」與空字串)
const rawNeeds = (guest.specialNeeds || '').split(',');
const guestNeeds = rawNeeds.filter(need => need && need !== '無特殊需求');
// 3. 搜尋合適的床位
const matchedBed = availableBeds.find(bed => {
// 先篩選出符合 basic 條件 (狀態、未被佔用、性別、需求匹配) 的床位列表
const validBeds = availableBeds.filter(bed => {
// A. 床位狀態需為可用 ('101')
if (bed.statusCode !== '101') return false;
@@ -702,14 +716,35 @@
}
// D. 特殊需求條件檢查 (人員需要的,床位必須具備)
const bedConditions = bed.limits || [];
const bedConditions = ensureArray(bed.limits);
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
if (!isMatchConditions) return false;
return true;
});
// 4. 若找到合適床位,進行分配
// =========================================================
// 關鍵優化:對符合條件的床位進行排序
// 無特殊需求的人員 (guestNeeds.length === 0):優先選 limits 數量少的床位 (普通床位)
// 有特殊需求的人員:優先選符合需求且 limits 最精準匹配的床位
// =========================================================
validBeds.sort((a, b) => {
const limitsA = ensureArray(a.limits).length;
const limitsB = ensureArray(b.limits).length;
if (guestNeeds.length === 0) {
// 無需求者:limits 少的排前面 (升冪排序,無限制床位優先)
return limitsA - limitsB;
} else {
// 有需求者:優先分配條件數量接近其需求的床位 (避免大材小用)
return limitsA - limitsB;
}
});
// 取出最合適的床位
const matchedBed = validBeds[0];
// 5. 若找到合適床位,進行分配
if (matchedBed) {
const buildingName = matchedBed.room?.regionName || '';
const roomName = matchedBed.room?.name || '';
@@ -729,16 +764,9 @@
}
}
// 5. 分配完成提示
// 6. 分配完成提示
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) {
+26
View File
@@ -897,6 +897,32 @@
},
changeGuadanGuest(item) {//可以變更人員、床位
console.log('變更人員、床位', item);
let detail = {
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,
roomUuid: item.roomUuid,
name: item.fullName,
guaDanOrderNo: this.guadanorder.order_form.orderNo
orderUuid: this.guadanorder.order_form.uuid
}
axios.post(HTTP_HOST + 'api/guadan/changeGuadanGuest', { guest: 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)
});
},
confirmDeleteGuadanOrderGuest(item) {
console.log('取消預訂', item);
+2 -2
View File
@@ -279,7 +279,7 @@
formData: {
handler(newVal) {
//用掛單的uuid去抓掛單資料跟明細檔
console.log('掛單uuid', newVal);
//console.log('掛單uuid', newVal);
if (newVal!="") {
this.getGuadanData();
}
@@ -291,7 +291,7 @@
mounted() {
this.getActivityList()
this.getGuadanLimits()
console.log('掛單明細', this.formData);
//console.log('掛單明細', this.formData);
},
computed: {
assignedBedUuids() {
File diff suppressed because it is too large. Load diff