掛單
This commit is contained in:
1 parent
9e251fc7d4
commit
98ee587dc0
6 files changed
+1130
-192
No files matched your search
@@ -304,7 +304,122 @@ public class guadanOrderController : ApiController
|
|||||||
if (json != null && json.guest != null)
|
if (json != null && json.guest != null)
|
||||||
{
|
{
|
||||||
var guest = json.guest;
|
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();
|
return Ok();
|
||||||
}
|
}
|
||||||
@@ -383,6 +498,7 @@ public class guadanOrderController : ApiController
|
|||||||
Handi = detail.handi,
|
Handi = detail.handi,
|
||||||
IsDeleted = false,
|
IsDeleted = false,
|
||||||
Name = detail.name,
|
Name = detail.name,
|
||||||
|
OrderUuid=guadanorder.Uuid
|
||||||
};
|
};
|
||||||
list.Add(guest);
|
list.Add(guest);
|
||||||
if (!Guid.TryParse((string)detail.bedUuid, out Guid targetGuid))
|
if (!Guid.TryParse((string)detail.bedUuid, out Guid targetGuid))
|
||||||
|
|||||||
@@ -61,7 +61,9 @@ public class regionController : ApiController
|
|||||||
{
|
{
|
||||||
query = query.Where(r => r.Room.Any(room => room.Uuid == filter.RoomId.Value));
|
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
|
var data = query
|
||||||
.ToList()
|
.ToList()
|
||||||
.Select(r => new
|
.Select(r => new
|
||||||
@@ -101,6 +103,15 @@ public class regionController : ApiController
|
|||||||
bed.StatusCode,
|
bed.StatusCode,
|
||||||
bed.IsActive,
|
bed.IsActive,
|
||||||
bed.IsDeleted,
|
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),
|
canuse = bed.IsAvailableDuring(startDate, endDate, _db),
|
||||||
statusname = bed.RegionRoomBedStatus.Name,
|
statusname = bed.RegionRoomBedStatus.Name,
|
||||||
schedules = _db.RegionAndRoomAndBedSchedule
|
schedules = _db.RegionAndRoomAndBedSchedule
|
||||||
|
|||||||
+45
-17
@@ -187,7 +187,7 @@
|
|||||||
<v-expansion-panel-header class="font-weight-bold">
|
<v-expansion-panel-header class="font-weight-bold">
|
||||||
<div class="d-flex align-center">
|
<div class="d-flex align-center">
|
||||||
<v-icon color="indigo" class="me-2" size="20">mdi-office-building-marker</v-icon>
|
<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>
|
</div>
|
||||||
</v-expansion-panel-header>
|
</v-expansion-panel-header>
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@
|
|||||||
<span>
|
<span>
|
||||||
{{ bed.name }}
|
{{ bed.name }}
|
||||||
<template v-if="bed.limits && bed.limits.length > 0">
|
<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>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<br>(無特殊限制床位)
|
<br>(無特殊限制床位)
|
||||||
@@ -330,7 +330,7 @@
|
|||||||
menu3: false,
|
menu3: false,
|
||||||
e_date: null,
|
e_date: null,
|
||||||
states: [
|
states: [
|
||||||
'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
|
//'無特殊需求', '需要輪椅', '需要拐杖', '需要陪同人員', '需要特別飲食', '其他需求'
|
||||||
],
|
],
|
||||||
message_dialog: false,
|
message_dialog: false,
|
||||||
message: "",
|
message: "",
|
||||||
@@ -416,6 +416,7 @@
|
|||||||
const guestNeeds = (this.selectedGuestForBed.specialNeeds || '').split(',').filter(c => c);
|
const guestNeeds = (this.selectedGuestForBed.specialNeeds || '').split(',').filter(c => c);
|
||||||
return this.mockBuildings.map(building => {
|
return this.mockBuildings.map(building => {
|
||||||
console.log('filteredMockBuildings:', building);
|
console.log('filteredMockBuildings:', building);
|
||||||
|
|
||||||
// 過濾房間並處理床位動態狀態
|
// 過濾房間並處理床位動態狀態
|
||||||
const filteredRooms = building.rooms.map(room => {
|
const filteredRooms = building.rooms.map(room => {
|
||||||
return {
|
return {
|
||||||
@@ -425,6 +426,7 @@
|
|||||||
// 檢查條件是否完全滿足
|
// 檢查條件是否完全滿足
|
||||||
const bedConditions = bed.limits || [];
|
const bedConditions = bed.limits || [];
|
||||||
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
|
building["regionPath"] = bed.regionPath;
|
||||||
room["regionPath"] = bed.regionPath;
|
room["regionPath"] = bed.regionPath;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -661,15 +663,27 @@
|
|||||||
this.message_dialog = true;
|
this.message_dialog = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. 關鍵排序:依據「特殊需求數量」降冪排序 (需求多的人先選床位,避免資源被搶)
|
||||||
unassignedGuests.sort((a, b) => {
|
unassignedGuests.sort((a, b) => {
|
||||||
const needsA = (a.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
const needsA = (a.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
const needsB = (b.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
const needsB = (b.specialNeeds || '').split(',').filter(c => c && c !== '無特殊需求').length;
|
||||||
return needsB - needsA; // 數量多的排在前面 (降冪)
|
return needsB - needsA; // 數量多的排在前面 (降冪)
|
||||||
});
|
});
|
||||||
|
|
||||||
let successCount = 0;
|
let successCount = 0;
|
||||||
let failCount = 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) {
|
for (const guest of unassignedGuests) {
|
||||||
try {
|
try {
|
||||||
// 取得該人員入住時間區間的可分配床位
|
// 取得該人員入住時間區間的可分配床位
|
||||||
@@ -679,12 +693,12 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
const availableBeds = resp.data?.availableBeds || [];
|
const availableBeds = resp.data?.availableBeds || [];
|
||||||
// 過濾出真正的特殊需求 (排除「無特殊需求」與空字串)
|
// 過濾出人員真正的特殊需求 (排除「無特殊需求」與空字串)
|
||||||
const rawNeeds = (guest.specialNeeds || '').split(',');
|
const rawNeeds = (guest.specialNeeds || '').split(',');
|
||||||
const guestNeeds = rawNeeds.filter(need => need && need !== '無特殊需求');
|
const guestNeeds = rawNeeds.filter(need => need && need !== '無特殊需求');
|
||||||
|
|
||||||
// 3. 搜尋合適的床位
|
// 先篩選出符合 basic 條件 (狀態、未被佔用、性別、需求匹配) 的床位列表
|
||||||
const matchedBed = availableBeds.find(bed => {
|
const validBeds = availableBeds.filter(bed => {
|
||||||
// A. 床位狀態需為可用 ('101')
|
// A. 床位狀態需為可用 ('101')
|
||||||
if (bed.statusCode !== '101') return false;
|
if (bed.statusCode !== '101') return false;
|
||||||
|
|
||||||
@@ -702,14 +716,35 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// D. 特殊需求條件檢查 (人員需要的,床位必須具備)
|
// D. 特殊需求條件檢查 (人員需要的,床位必須具備)
|
||||||
const bedConditions = bed.limits || [];
|
const bedConditions = ensureArray(bed.limits);
|
||||||
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
const isMatchConditions = guestNeeds.every(need => bedConditions.includes(need));
|
||||||
if (!isMatchConditions) return false;
|
if (!isMatchConditions) return false;
|
||||||
|
|
||||||
return true;
|
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) {
|
if (matchedBed) {
|
||||||
const buildingName = matchedBed.room?.regionName || '';
|
const buildingName = matchedBed.room?.regionName || '';
|
||||||
const roomName = matchedBed.room?.name || '';
|
const roomName = matchedBed.room?.name || '';
|
||||||
@@ -729,16 +764,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 5. 分配完成提示
|
// 6. 分配完成提示
|
||||||
this.message = `自動分配完成!成功分配 ${successCount} 位,失敗/無合適床位 ${failCount} 位。`;
|
this.message = `自動分配完成!成功分配 ${successCount} 位,失敗/無合適床位 ${failCount} 位。`;
|
||||||
this.message_dialog = true;
|
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) {
|
||||||
|
|||||||
@@ -897,6 +897,32 @@
|
|||||||
},
|
},
|
||||||
changeGuadanGuest(item) {//可以變更人員、床位
|
changeGuadanGuest(item) {//可以變更人員、床位
|
||||||
console.log('變更人員、床位', 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) {
|
confirmDeleteGuadanOrderGuest(item) {
|
||||||
console.log('取消預訂', item);
|
console.log('取消預訂', item);
|
||||||
|
|||||||
@@ -279,7 +279,7 @@
|
|||||||
formData: {
|
formData: {
|
||||||
handler(newVal) {
|
handler(newVal) {
|
||||||
//用掛單的uuid去抓掛單資料跟明細檔
|
//用掛單的uuid去抓掛單資料跟明細檔
|
||||||
console.log('掛單uuid', newVal);
|
//console.log('掛單uuid', newVal);
|
||||||
if (newVal!="") {
|
if (newVal!="") {
|
||||||
this.getGuadanData();
|
this.getGuadanData();
|
||||||
}
|
}
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.getActivityList()
|
this.getActivityList()
|
||||||
this.getGuadanLimits()
|
this.getGuadanLimits()
|
||||||
console.log('掛單明細', this.formData);
|
//console.log('掛單明細', this.formData);
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
assignedBedUuids() {
|
assignedBedUuids() {
|
||||||
|
|||||||
+929
-172
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user