Files
17168ERP/web/admin/guadan/create.aspx
T

1801 lines
83 KiB
Plaintext

<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="create.aspx.cs" Inherits="admin_guadan_create" %>
<asp:Content ID="Content1" ContentPlaceHolderID="page_header" Runat="Server">
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="page_nav" Runat="Server">
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<fieldset class="border rounded p-4 mb-5 shadow-sm bg-white">
<legend class="w-auto px-3 font-weight-bold text-primary">掛單資訊</legend>
<!-- 🟢 區塊一:掛單資訊 -->
<div class="border rounded p-3 bg-white shadow-sm">
<h6 class="text-secondary mb-3">📝掛單資訊</h6>
<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="guadanorder.order_form.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" 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" 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 class="row mt-3">
<button v-if="guadanorder.order_form.uuid" type="button" class="btn btn-primary mx-auto" style="width: 120px;" @click="updateGuadanOrder">修改</button>
<button v-else v-on:click="createGuadanOrder" type="button" class="btn btn-primary mx-auto" style="width: 120px;">儲存</button>
</div>
</div>
</fieldset>
<fieldset class="border rounded p-4 mb-5 shadow-sm bg-white">
<!-- 表格標題緊貼表格上方,居中 -->
<div class="d-flex align-items-center mb-3">
<!-- 左側按鈕 -->
<v-btn color="primary" variant="elevated" @click="showCheckInModal" class="me-3">
<v-icon start>mdi-plus</v-icon>
增加蓮友
</v-btn>
<v-btn @click="showAutomaticBedAllocation">
自動分配床位
</v-btn>
<!-- 中間標題(flex-grow撐開居中) -->
<div class="flex-grow-1 text-center">
<h5 class="text-primary fw-bold mb-0">
<i class="bi bi-people-fill me-2"></i>掛單蓮友
</h5>
</div>
</div>
<!-- v-data-table 表格 -->
<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}">
{{item.follower?.u_name}}
</template>
<template #item.actions="{ item }">
<div>
<!-- 取消預訂 -->
<v-btn
color="red"
variant="outlined"
size="small"
class="me-2"
:disabled="item.statuscode !== '401'"
@click="confirmDeleteGuadanOrderGuest(item)"
>
取消預訂
</v-btn>
<v-btn
color="red"
variant="outlined"
size="small"
class="me-2"
:disabled="item.statuscode !== '401'"
@click="checkinGuadanGuest(item)"
>
入住
</v-btn>
<v-btn
color="red"
variant="outlined"
size="small"
class="me-2"
:disabled="item.statuscode !== '402'"
@click="showXuzhuGuestModalMethod(item)">
續住
</v-btn>
<!-- 退房 -->
<v-btn
color="primary"
variant="outlined"
size="small"
:disabled="item.statuscode !== '402'"
@click="checkoutGuadanOrderGuest(item)"
>
<v-icon start>mdi-exit-run</v-icon>
退房
</v-btn>
</div>
</template>
</v-data-table>
</fieldset>
<!-- 🟢 續住彈出視窗 -->
<div>
<v-dialog v-model="guadanguest.xuzhu.showXuzhuGuestModal" max-width="50%">
<v-card
class="pa-6 d-flex flex-column" style="min-height: 60vh; border-radius: 12px;"
style="min-height: 40vh; border-radius: 12px; box-shadow: 0 8px 20px rgba(0,0,0,0.15);"
>
<!-- 弹窗标题 -->
<v-card-title
class="text-h6 d-flex align-center justify-space-between pb-4"
style="border-bottom: 1px solid #eee;"
>
<div class="d-flex align-center">
<span class="font-weight-bold">续住</span>
</div>
<v-btn icon @click="closeXuzhuGuestModalMethod">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<!-- 弹窗内容 -->
<v-card-text class="flex-grow-1 py-6" style="overflow-y: auto;">
<div class="mb-4">
<span class="font-weight-medium">当前退房时间:</span>
<span class="text-primary">{{ guadanguest.xuzhu.currentCheckoutDate }}</span>
</div>
<div class="d-flex align-center">
<span class="font-weight-medium mr-2">续住后退房时间:</span>
<input
type="date"
id="newCheckoutDate"
v-model="guadanguest.xuzhu.newCheckoutDate"
class="pa-2"
style="border: 1px solid #ccc; border-radius: 6px; padding: 6px 10px;"
/>
</div>
</v-card-text>
<!-- 弹窗操作按钮 -->
<v-card-actions class="justify-end pt-4" style="border-top: 1px solid #eee;">
<v-btn color="primary" class="px-6" @click="xuzhuPost">续住</v-btn>
<v-btn text class="ml-2" @click="closeXuzhuGuestModalMethod">取消</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</div>
<!-- 🟢 掛單蓮友彈出視窗 -->
<div>
<v-dialog v-model="checkInGuest.showSelectGuadanOrderGuest" max-width="80%">
<v-card class="pa-6" style="min-height: 90vh;">
<!-- 標題列 -->
<v-card-title class="text-h6 d-flex align-center justify-space-between pb-4">
<div class="d-flex align-center">
<v-icon class="me-2">mdi-account-multiple-plus</v-icon>
<span>掛單蓮友資料</span>
</div>
<v-btn icon @click="closeCheckInModal">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<!-- 內容區 -->
<v-card-text class="py-6">
<v-container>
<v-row dense>
<!-- 掛單單號 -->
<v-col cols="12">
<v-text-field v-model="checkInGuest.inGuest.orderNo" label="掛單單號" readonly variant="underlined"></v-text-field>
</v-col>
<!-- 入住時間 -->
<v-col cols="12" sm="6">
<v-text-field
v-model="checkInGuest.inGuest.checkInAt"
label="入住時間" type="date"
variant="underlined"></v-text-field>
</v-col>
<!-- 退房時間 -->
<v-col cols="12" sm="6">
<v-text-field
v-model="checkInGuest.inGuest.checkOutAt"
label="退房時間" type="date"
variant="underlined"></v-text-field>
</v-col>
<!-- 蓮友選擇 -->
<v-col cols="12" sm="6">
<div class="d-flex align-center" style="height: 100%;">
<v-btn color="teal" variant="outlined" block @click="showSelectGuestModalMethod">
<v-icon left class="me-2">mdi-account-search</v-icon>
選擇掛單蓮友
</v-btn>
</div>
</v-col>
<v-col cols="12" sm="6">
<div class="d-flex flex-column justify-center" style="height: 100%;">
<div>
<div class="text-muted text-sm">
已選:<strong>{{ selectGuestModal?.fullNameText || '未選擇' }}</strong>
</div>
<div class="text-info text-xs mt-1">如無符合,請先新增蓮友資料</div>
</div>
</div>
</v-col>
<!-- 床位選擇 -->
<v-col cols="12" sm="6">
<div class="d-flex align-center" style="height: 100%;">
<v-btn color="indigo" variant="outlined" block @click="openSelectBedModal">
<v-icon left class="me-2">mdi-bed</v-icon>
選擇床位
</v-btn>
</div>
</v-col>
<v-col cols="12" sm="6">
<div class="d-flex flex-column justify-center" style="height: 100%;">
<div class="text-muted text-sm">
已選床位:<strong>{{ region_modal.currentSelectBedText }}</strong>
</div>
<div class="text-info text-xs mt-1">請從床位清單中選擇</div>
</div>
</v-col>
</v-row>
</v-container>
</v-card-text>
<!-- 操作按鈕 -->
<v-card-actions class="justify-end pt-6">
<v-btn color="primary" @click="saveEditGuadanOrderGuest" v-if="checkInGuest.isEdit">
<v-icon left class="me-1">mdi-content-save</v-icon>
修改
</v-btn>
<v-btn color="primary" @click="saveCheckInGuest" v-else>
<v-icon left class="me-1">mdi-content-save</v-icon>
儲存
</v-btn>
<v-btn variant="text" @click="closeCheckInModal">
<v-icon left class="me-1">mdi-close-circle-outline</v-icon>
取消
</v-btn>
</v-card-actions>
</v-card>
<!-- 子彈出視窗打開時,添加一個透明遮罩層覆蓋整個界面 -->
<v-overlay v-if="selectGuestModal.showSelectGuestModal" :scrim="false" persistent style="z-index: 202;"></v-overlay>
</v-dialog>
</div>
<!-- 選擇床位彈出視窗 -->
<div id="bedSelectionModal" v-if="region_modal.showSelectBedModal" style="position: fixed; top: 0; left: 0; width: 100%; height: 100%;
background-color: rgba(0,0,0,0.5); z-index: 10000; display: flex; justify-content: center; align-items: center;">
<div style="background: white; min-width: 70%; min-height: 80%; max-width: 80%; max-height: 80%;
display: flex; border-radius: 4px; height: 100%;">
<div style="display: flex; width: 100%; height: 100%;">
<!-- 左側 30% -->
<div style="width: 30%; border-right: 1px solid #e8e8e8; height: 100%; display: flex; flex-direction: column;">
<div style="padding: 12px 16px; border-bottom: 1px solid #e8e8e8; flex-shrink: 0;">
<h3 style="margin: 0; font-size: 16px; font-weight: normal;">區域列表</h3> <span>當前可用床位:{{availableBedCount.male + '(男)'}} {{availableBedCount.female + '(女)'}}</span>
</div>
<div style="padding: 8px 0; overflow-y: auto; flex: 1;">
<div v-for="region in region_modal.regions" :key="region.id">
<div class="tree" style="padding: 8px 16px; cursor: pointer; display: flex; align-items: center;">
<region-item :item="region" :selected-id="region_modal.selectedId" :selected-type="region_modal.selectedType" @select-region="selectRegion" @select-room="selectRoom" :expand-all="region_modal.expandAllFlag" :collapse-all="region_modal.collapseAllFlag" @clear-expand-all="region_modal.expandAllFlag = false" @clear-collapse-all="region_modal.collapseAllFlag = false" />
</div>
</div>
</div>
</div>
<!-- 右側 70% -->
<div style="width: 70%; display: flex; flex-direction: column; height: 100%;">
<div style="padding: 12px 16px; border-bottom: 1px solid #e8e8e8; flex-shrink: 0;">
<h3 style="margin: 0; font-size: 16px; font-weight: normal;">床位列表</h3>
<div>掛單起訖時間:{{checkInGuest.inGuest.checkInAt|timeString('YYYY-MM-DD')}} - {{checkInGuest.inGuest.checkOutAt|timeString('YYYY-MM-DD')}}</div>
</div>
<div style="flex: 1; padding: 8px; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; overflow-y: auto;">
<div v-for="bed in region_modal.currentSelectBeds" :key="bed.uuid" @click="selectBed(bed)" style="padding: 8px; border: 1px solid #d9d9d9; cursor: pointer; max-height: 250px;" :style="{
backgroundColor: region_modal.currentSelectBed?.uuid === bed.uuid
? '#bae7ff' // 當前選中
: (bed.canUsed ? '#f6ffed' : '#fff1f0'), // 可用綠色,不可用紅色
color: bed.canUsed ? 'black' : '#999', // 不可用時灰色文字
pointerEvents: bed.canUsed ? 'auto' : 'none' // 不可用時無法點擊
}">
<div style="font-weight: 500;">{{ bed.name }}</div>
<div style="margin-top: 4px; font-size: 12px;">
{{ bed.canUsed ? '可用' : '不可用' }}
</div>
<div
v-for="schedule in bed.schedule"
:key="schedule.id"
style="margin-top: 4px; font-size: 12px; background-color: #fafafa; padding: 4px; border-radius: 4px;"
>
<div style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
🕒 {{ schedule.scheduledate|timeString("YYYY-MM-DD") }}
</div>
<div style="color: #555;">📌 {{ schedule.title }}</div>
</div>
</div>
</div>
<div style="padding: 12px 16px; text-align: right; border-top: 1px solid #e8e8e8; flex-shrink: 0;">
<span class="me-8 shadow-lg">當前已選擇床位: {{ region_modal.currentSelectBedText }}</span>
<button type="button" @click="cancelSelectBed" style="margin-right: 8px; padding: 4px 15px; background: #fff; border: 1px solid #d9d9d9; border-radius: 2px; cursor: pointer;">
取消
</button>
<button type="button" @click="confirmSelectBed" v-if="region_modal.currentSelectBed" style="padding: 4px 15px; background: #1890ff; color: #fff; border: 1px solid #1890ff; border-radius: 2px; cursor: pointer;">
確定
</button>
</div>
</div>
</div>
</div>
</div>
<!-- 選擇蓮友彈出視窗 -->
<div>
<v-dialog v-model="selectGuestModal.showSelectGuestModal" max-width="70%" scrollable persistent>
<v-card>
<v-card-title class="text-h6 d-flex align-center justify-space-between pb-4">
<div class="d-flex align-center">
<v-icon class="me-2">mdi-account-multiple-plus</v-icon>
<span>蓮友列表</span>
</div>
<div class="mx-4 d-flex align-center" style="flex: 1 1 50%; max-width: 50%;">
<input class="form-control me-2" style="flex: 1 1 auto; min-width: 0;" placeholder="搜尋..." v-model="selectGuestModal.searchNameOrPhone" />
<button @click="getGuadanFollowers" type="button" class="btn btn-primary" style="white-space: nowrap;">搜索</button>
</div>
<v-btn icon @click="selectGuestModal.showSelectGuestModal=false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text style="max-height: 500px; overflow-y: auto;">
<v-data-table
:headers="selectGuestModal.headers"
:items="selectGuestModal.items"
:options.sync="selectGuestModal.options"
:footer-props="selectGuestModal.footer"
hide-default-footer
:server-items-length="selectGuestModal.count"
:page.sync="selectGuestModal.page"
:items-per-page.sync="selectGuestModal.pageSize">
<template v-slot:item.actions="{item}">
<button type="button" @click="selectGuadanOrderGuest(item)" class="btn btn-primary">選擇</button>
</template>
</v-data-table>
</v-card-text>
<div class="ms-10">
<v-container>
<v-row class="align-baseline" wrap>
<v-col cols="12" md="9">
<v-pagination v-model="selectGuestModal.page" :length="pageCount">
</v-pagination>
</v-col>
<v-col class="text-truncate text-right" cols="12" md="2">
共 {{ selectGuestModal.count }} 筆, 頁數:
</v-col>
<v-col cols="6" md="1">
<v-text-field v-model="selectGuestModal.page" type="number" hide-details dense min="1" :max="pageCount" @input="selectGuestModal.page = parseInt($event, 10)"></v-text-field>
</v-col>
</v-row>
</v-container>
</div>
</v-card>
</v-dialog>
</div>
<!-- 自動分配彈出視窗 -->
<div>
<v-dialog v-model="automaticBedAllocation.showModal" max-width="80%">
<v-card class="pa-6" style="height: 90vh; display: flex; flex-direction: column;">
<!-- 標題列 -->
<v-card-title class="text-h6 d-flex align-center justify-space-between pb-4" style="flex: 0 0 auto;">
<div class="d-flex align-center">
<v-icon class="me-2">mdi-account-multiple-plus</v-icon>
<span>床位自動分配</span>
</div>
<div>
<span>當前可用床位:{{availableBedCount.male + '(男)'}} {{availableBedCount.female + '(女)'}}</span>
</div>
</v-card-title>
<!-- 內容區,高度自動填滿 -->
<div style="flex: 1 1 auto; display: flex; overflow: hidden; gap: 16px;">
<!-- 左側 30% -->
<div
style="
width: 30%;
border: 1px solid #ccc;
border-radius: 8px;
padding: 0;
box-sizing: border-box;
overflow: hidden;
display: flex;
flex-direction: column;
background-color: #fafafa;
box-shadow: 0 2px 6px rgb(0 0 0 / 0.08);
"
>
<!-- 左側標題 -->
<div
style="
padding: 14px 20px;
font-weight: 700;
font-size: 1.1rem;
background: linear-gradient(90deg, #6a8cff, #3b5de7);
color: white;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
box-shadow: 0 2px 6px rgb(58 94 255 / 0.5);
user-select: none;
"
>
自動分配條件
</div>
<!-- 左側內容滾動區 -->
<div style="padding: 16px; overflow: auto; flex: 1;">
<!-- 這裡放左側具體內容 -->
指定區域<br />
指定房間<br />
便利設施<br />
盡量分配在同一個房間<br />
<br />
<br />
</div>
</div>
<!-- 右側 70%,上下分割 -->
<div
style="
width: 70%;
display: flex;
flex-direction: column;
gap: 16px;
padding: 0;
box-sizing: border-box;
"
>
<!-- 右側上半部 -->
<div
style="
flex: 1;
border: 1px solid #ccc;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 2px 6px rgb(0 0 0 / 0.08);
background-color: #fff;
"
>
<!-- 右側上半部標題列 -->
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
padding: 14px 20px;
font-weight: 700;
font-size: 1.1rem;
background: linear-gradient(90deg, #4f86f7, #1c5bd9);
color: white;
border-top-left-radius: 8px;
border-top-right-radius: 8px;
box-shadow: 0 3px 8px rgb(31 78 250 / 0.5);
user-select: none;
"
>
<span>待分配蓮友列表</span>
<div>
<button
@click="showautomaticBedAllocationMethod"
type="button"
style="
padding: 8px 18px;
background-color: #ffffff;
color: #1c5bd9;
border: none;
border-radius: 20px;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0 2px 6px rgba(28, 91, 217, 0.4);
user-select: none;
"
onmouseover="this.style.backgroundColor='#e6e6e6';"
onmouseout="this.style.backgroundColor='white';"
>
選擇蓮友
</button>
<button
type="button"
style="
padding: 8px 18px;
background-color: #ffffff;
color: #1c5bd9;
border: none;
border-radius: 20px;
font-weight: 600;
font-size: 0.9rem;
cursor: pointer;
transition: background-color 0.3s ease;
box-shadow: 0 2px 6px rgba(28, 91, 217, 0.4);
user-select: none;
"
onmouseover="this.style.backgroundColor='#e6e6e6';"
onmouseout="this.style.backgroundColor='white';"
@click="preAllocation"
>按條件自動預分配</button>
</div>
</div>
<!-- 右側上半部內容滾動區 -->
<div style="padding: 16px; overflow: auto; flex: 1;">
<v-data-table
:items="automaticBedAllocation.selectedFollowers"
:headers="automaticBedAllocation.headers">
<template #item.prebed="{item}">
{{ getPreBed(item.num)?.bedUuid}}
</template>
<template #item.actions="{item}">
<button
class="btn btn-outline-danger btn-sm"
type="button"
style="min-width: 70px;"
@click="removeSelectedFollower(item.num);removePreBed(item.num)"
>
<i class="mdi mdi-delete-outline me-1"></i> 刪除
</button>
</template>
</v-data-table>
</div>
</div>
</div>
</div>
<!-- 底部按鈕區 -->
<v-card-actions
style="
justify-content: flex-end;
border-top: 1px solid #eee;
padding: 16px 24px;
background-color: #f9f9f9;
flex: 0 0 auto;
"
>
<v-btn color="primary" @click="cancelAutomaticBedAllocation">
取消分配
</v-btn>
<v-btn color="primary" @click="confirmAllocation" class="ms-3" :disabled="automaticBedAllocation.preBeds.length === 0">
確認分配
</v-btn>
</v-card-actions>
</v-card>
<!-- 子彈出視窗打開時,添加一個透明遮罩層覆蓋整個界面 -->
<v-overlay v-if="automaticBedAllocation.followerModal.showModal" :scrim="false" persistent style="z-index: 202;"></v-overlay>
</v-dialog>
</div>
<!-- 自動分配選擇蓮友彈出視窗 -->
<div>
<v-dialog v-model="automaticBedAllocation.followerModal.showModal" max-width="70%" scrollable persistent>
<v-card>
<v-card-title class="text-h6 d-flex align-center justify-space-between pb-4">
<div class="d-flex align-center">
<v-icon class="me-2">mdi-account-multiple-plus</v-icon>
<span>蓮友列表</span>
</div>
<div class="mx-4 d-flex align-center" style="flex: 1 1 50%; max-width: 50%;">
<input class="form-control me-2" style="flex: 1 1 auto; min-width: 0;" placeholder="搜尋..." v-model="automaticBedAllocation.followerModal.searchNameOrPhone" />
<button @click="getMultiSelectFollowers" type="button" class="btn btn-primary" style="white-space: nowrap;">搜索</button>
</div>
<v-btn icon @click="automaticBedAllocation.followerModal.showModal=false">
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title>
<v-card-text style="max-height: 500px; overflow-y: auto;">
<v-data-table
:headers="automaticBedAllocation.followerModal.headers"
:items="automaticBedAllocation.followerModal.followerList"
:items-per-page="automaticBedAllocation.followerModal.pageSize"
:page.sync="automaticBedAllocation.followerModal.page"
:value="automaticBedAllocation.followerModal.selectedFollowerItems"
@input="onMultiSelectChange"
show-select
item-key="num"
hide-default-footer
:item-class="getFollowerRowClass"
>
<template #item.data-table-select="{ item, isSelected, select }">
<v-simple-checkbox
:value="isSelected"
:disabled="isFollowerDisabled(item)"
@input="select($event)"
/>
</template>
<template #header.data-table-select>
<!-- 留空即可去掉全選 -->
</template>
<template #item.actions="{item}">
{{isFollowerDisabled(item) ? '已掛單' : ''}}
</template>
</v-data-table>
</v-card-text>
<div class="ms-10">
<v-container>
<v-row class="align-baseline" wrap>
<v-col cols="12" md="9">
<!-- 分頁 -->
<v-pagination
v-model="automaticBedAllocation.followerModal.page"
:length="pageCount2"
></v-pagination>
</v-col>
<v-col class="text-truncate text-right" cols="12" md="2">
共 {{ automaticBedAllocation.followerModal.totalCount }} 筆
</v-col>
</v-row>
</v-container>
</div>
</v-card>
</v-dialog>
</div>
<!-- 更新修改確認彈出視窗 -->
<message-modal ref="messageModal"></message-modal>
<!-- 刪除確認彈出視窗 -->
<confirm-modal ref="confirmModal"></confirm-modal>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
<style>
/* 調整 fieldset 風格 */
fieldset {
border: 1px solid #dee2e6;
border-radius: 0.5rem;
background-color: #fff;
}
legend {
font-size: 1.25rem;
font-weight: 700;
color: #0d6efd;
width: auto;
padding: 0 0.75rem;
}
.form-group label {
font-weight: 600;
}
/* 按鈕置右 */
.text-right {
text-align: right;
}
/* 選擇床位相關 */
.tree,
.tree ul {
list-style: none;
margin: 0;
padding-left: 1rem;
}
.toggle-icon {
cursor: pointer;
user-select: none;
width: 1rem;
display: inline-block;
color: #007bff;
}
.region-item-label {
cursor: pointer;
padding: 2px 6px;
border-radius: 4px;
display: inline-block;
}
.region-item-label.selected {
background-color: #eaf4ff;
color: #0d6efd;
font-weight: bold;
}
.selected-room {
background-color: #cce5ff;
font-weight: bold;
}
/* 選擇床位相關 */
</style>
<script>
Vue.component('region-item', {
props: ['item', 'selectedId', 'selectedType', 'expandAll', 'collapseAll'],
data() {
return {
expanded: false, // 預設全部收起
selectedRoomId: null,
}
},
watch: {
expandAll(newVal) {
if (newVal) {
this.expanded = true;
// 執行完後發事件通知父組件清除標誌
this.$nextTick(() => this.$emit('clear-expand-all'));
}
},
collapseAll(newVal) {
if (newVal) {
this.expanded = false;
this.$nextTick(() => this.$emit('clear-collapse-all'));
}
}
},
computed: {
hasChildren() {
return this.item.children && this.item.children.length > 0;
},
icon() {
// 無論有無子節點,皆可點擊展開/收起
return this.expanded ? '▼' : '▶';
},
isSelected() {
return this.selectedType === 'region' && this.item.uuid === this.selectedId;
}
},
methods: {
toggle() {
this.expanded = !this.expanded;
},
select() {
this.$emit('select-region', this.item);
},
selectRoom(room) {
this.selectedRoomId = room.uuid;
this.$emit('select-room', room); // 可以發事件給父組件
}
},
template: `
<div>
<span class="toggle-icon" @click="toggle">{{ icon }}</span>
<span @click="select"
class="region-item-label"
:class="{ 'selected': isSelected }">
{{ item.rooms.length>0 ? (item.name + '(' + item.rooms.length + '房)'): item.name }}
</span>
<!-- 子區域列表 -->
<ul v-if="hasChildren && expanded">
<li v-for="(child, index) in item.children" :key="child.id + '-' + index">
<region-item
:item="child"
:selected-id="selectedId"
:selected-type="selectedType"
:expand-all="expandAll"
:collapse-all="collapseAll"
@select-region="$emit('select-region', $event)"
@select-room="$emit('select-room', $event)"
@clear-expand-all="$emit('clear-expand-all')"
@clear-collapse-all="$emit('clear-collapse-all')"
/>
</li>
</ul>
<!-- 客房列表:無論是否有子區域,只要展開就顯示 -->
<ul v-if="item.rooms && item.rooms.length > 0 && expanded">
<li v-for="room in item.rooms" :key="'room-' + room.uuid"
@click="selectRoom(room)"
:class="{ 'selected-room': selectedType === 'room' && selectedId === room.uuid }"
style="cursor: pointer;">
<span class="bed-label">
🛏️ {{ room.name + ' (' + room.beds.length + '床) ' + (room.gender === true ? '(男客房)' : room.gender === false ? '(女客房)' : '') }}
</span>
</li>
</ul>
</div>
`
});
Vue.filter('timeString', function (value, myFormat) {
return value == null || value == "" ? "" : moment(value).format(myFormat || 'YYYY-MM-DD, HH:mm:ss');
});
new Vue({
el: '#app',
vuetify: new Vuetify(vuetify_options),
data() {
return {
activityList: [],
availableBedCount: {
male: 0,
female: 0,
},
guadanorder: {
order_form: {
uuid: '<%= Request.QueryString["orderid"] %>' || null,
startdate: null,
enddate: null,
note: null,
orderNo: null,
bookerName: null,
bookerPhone: null,
bookerFollowerNum: null,
activityNum: null,
},
status_items: [],
},
guadanguest: {
guest: {
uuid: null, // int?
fullName: '', // string
gender: null, // int?
phone: '', // string
idNumber: '', // string
birthday: null, // Date (建議用 date picker)
email: '', // string
address: '', // string
emergencyContact: '', // string
emergencyPhone: '', // string
status: null, // int?
notes: '' // string
},
headers: [{
text: '姓名',
value: 'name'
},
{
text: '掛單開始時間',
value: 'checkinat'
},
{
text: '掛單結束時間',
value: 'checkoutat'
},
{
text: '房間',
value: 'roomName'
},
{
text: '床位',
value: 'bedName'
},
{
text: '狀態',
value: 'statusName'
},
{
text: '備註',
value: 'note'
},
{
text: '',
value: 'actions'
},
],
items: [],
showCreateGuestModal: false,
xuzhu: {
showXuzhuGuestModal: false,
currentCheckoutDate: null,
newCheckoutDate: null,
guestUuid: null,
guestBedUuid: null,
}
},
checkInGuest: {
showSelectGuadanOrderGuest: false,
isEdit: false,
inGuest: {
uuid: null,
orderNo: null,
followerNum: null,
roomUuid: null,
bedUuid: null,
checkInAt: null,
checkOutAt: null,
statuscode: null,
},
status: [],
},
region_modal: {
regions: [],
currentSelectRegion: null,
currentSelectRoom: null,
currentSelectBeds: [],
currentSelectBed: null,
showSelectBedModal: false,
selectedId: null, // 被選中項目ID
selectedType: null, // 'region' 或 'room'
expandAllFlag: false, // 控制全部展開
collapseAllFlag: false, // 控制全部收起
currentSelectBedText: null,
},
selectGuestModal: {
showSelectGuestModal: false,
currentSelectedGuest: null,
fullNameText: null,
headers: [{
text: '姓名',
value: 'u_name'
},
{
text: '電話',
value: 'phone'
},
{
text: '',
value: 'actions'
},
],
items: [],
options: { //v-data-table參數
page: 1,
itemsPerPage: 10,
sortBy: [],
sortDesc: [],
multiSort: false,
},
page: 1,
pageSize: 10,
count: 0,
footer: {
showFirstLastPage: true,
disableItemsPerPage: true,
itemsPerPageAllText: '',
itemsPerPageText: '',
},
searchNameOrPhone: null,
},
automaticBedAllocation: {
showModal: false,
// 蓮友選擇彈出視窗
followerModal: {
showModal: false,
followerList: [],
selectedFollowerItems: [],
page: 1,
pageSize: 10,
totalCount: 0,
searchNameOrPhone: '',
headers: [
{ text: '姓名', value: 'u_name' },
{ text: '電話', value: 'phone' },
{ text: '操作', value: 'actions', sortable: false }
],
},
// 已選擇的待分配列表
selectedFollowers: [],
preBeds: [],
headers: [
{ text: '姓名', value: 'u_name' },
{ text: '電話', value: 'phone' },
{ text: '性別', value: 'sex' },
{ text: '預分配床位', value: 'prebed' },
{ text: '', value: 'actions' }
],
},
}
},
methods: {
//续住相關方法--------------------start
showXuzhuGuestModalMethod(guest) {
if (!guest.checkoutat) {
return;
}
this.guadanguest.xuzhu.showXuzhuGuestModal = true;
this.guadanguest.xuzhu.currentCheckoutDate = guest.checkoutat;
this.guadanguest.xuzhu.guestUuid = guest.uuid;
this.guadanguest.xuzhu.guestBedUuid = guest.bedUuid;
this.$nextTick(() => { // 确保弹窗 DOM 已渲染
const input = document.getElementById('newCheckoutDate');
if (input) {
const checkoutDate = new Date(guest.checkoutat); // 用指定日期
checkoutDate.setDate(checkoutDate.getDate() + 1); // 明天
const year = checkoutDate.getFullYear();
const month = String(checkoutDate.getMonth() + 1).padStart(2, '0');
const day = String(checkoutDate.getDate()).padStart(2, '0');
const tomorrow = `${year}-${month}-${day}`;
input.min = tomorrow; // 限制最小值
//input.value = tomorrow; // 默认选中明天
}
});
console.log(guest.checkoutat)
},
closeXuzhuGuestModalMethod() {
console.log(this.guadanguest.xuzhu.newCheckoutDate)
this.guadanguest.xuzhu.showXuzhuGuestModal = false;
this.guadanguest.xuzhu.currentCheckoutDate = null;
this.guadanguest.xuzhu.newCheckoutDate = null;
this.guadanguest.xuzhu.guestUuid = null;
this.guadanguest.xuzhu.guestBedUuid = null;
console.log(this.guadanguest.xuzhu.newCheckoutDate)
console.log(this.guadanguest.xuzhu.currentCheckoutDate)
console.log(this.guadanguest.xuzhu.guestUuid)
console.log(this.guadanguest.xuzhu.guestBedUuid)
},
xuzhuPost() {
// 校验必填
if (!this.guadanguest.xuzhu.guestUuid || !this.guadanguest.xuzhu.guestBedUuid) {
alert("GuestUuid 和 GuestBedUuid 不能为空");
return;
}
if (!this.guadanguest.xuzhu.newCheckoutDate || !this.guadanguest.xuzhu.currentCheckoutDate) {
alert("续住时间不能为空");
return;
}
const payload = {
guestUuid: this.guadanguest.xuzhu.guestUuid,
guestBedUuid: this.guadanguest.xuzhu.guestBedUuid,
currentCheckoutDate: this.guadanguest.xuzhu.currentCheckoutDate,
newCheckoutDate: this.guadanguest.xuzhu.newCheckoutDate
};
axios.post('/api/guadanorderguest/xuzhu', payload)
.then((res) => {
this.$refs.messageModal.open({
title: '续住成功',
message: '客人续住已处理',
status: 'success',
callback: () => {
// 弹窗关闭后的回调
try {
this.getGuadanOrderGuestByOrderNo();
}
catch (error) {
console.error("发生错误:", error.message);
} finally {
this.closeXuzhuGuestModalMethod();
}
}
});
})
.catch((error) => {
this.$refs.messageModal.open({
title: '续住失败',
message: error.response?.data?.message || '系统异常,请稍后重试',
status: 'error'
});
});
},
//续住相關方法--------------------end
getActivityList() {
axios.post('/api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
.then((res) => {
this.activityList = res.data.list
})
},
getavailablebedcountbytime(startTime, endTime) {
axios.get('/api/region/bed/getavailablebedcountbytime', {
params: {
startTime: startTime,
endTime: endTime
}
}).then((res) => {
this.availableBedCount = res.data;
})
},
//自動分配相關方法--------------------start
showAutomaticBedAllocation() {
if (!this.guadanorder.order_form.uuid) {
this.$refs.messageModal.open({
message: '請先創建掛單',
});
return;
}
this.automaticBedAllocation.showModal = true;
this.getavailablebedcountbytime(this.guadanorder.order_form.startdate, this.guadanorder.order_form.enddate);
},
confirmAllocation() {
//確認分配
axios.post('/api/region/bed/confirmallocation', {
preBeds: this.automaticBedAllocation.preBeds,
orderNo: this.guadanorder.order_form.orderNo,
checkInAt: this.guadanorder.order_form.startdate,
checkOutAt: this.guadanorder.order_form.enddate
})
.then(res => {
this.resetAutomaticBedAllocation();
this.getGuadanOrderGuestByOrderNo();
});
},
preAllocation() {
const follower = this.automaticBedAllocation.selectedFollowers.map(({ num, sex }) => ({
num,
sex: sex === '男眾' ? 'M' : sex === '女眾' ? 'F' : ''
}));
console.log(follower);
const payload = {
PreBeds: follower, // 這裡傳待分配人員列表
OrderNo: this.guadanorder.order_form.orderNo || '', // 訂單號
CheckInAt: this.guadanorder.order_form.startdate || new Date(), // 入住時間
CheckOutAt: this.guadanorder.order_form.enddate || null // 退房時間,可為空
};
axios.post('/api/region/bed/preallocation', payload)
.then(res => {
this.automaticBedAllocation.preBeds = res.data.data;
})
.catch(error => {
this.$refs.messageModal.open({
title: '分配失敗',
message: (error.response?.data?.message || error.message)
});
});
},
getPreBed(num) {
return this.automaticBedAllocation.preBeds.find(a => a.num == num) || null;
},
resetAutomaticBedAllocation() {
this.automaticBedAllocation.showModal = false;
this.automaticBedAllocation.followerModal.showModal = false;
this.automaticBedAllocation.followerModal.followerList = [];
this.automaticBedAllocation.followerModal.selectedFollowerItems = [];
this.automaticBedAllocation.followerModal.page = 1;
this.automaticBedAllocation.followerModal.pageSize = 10;
this.automaticBedAllocation.followerModal.totalCount = 0;
this.automaticBedAllocation.selectedFollowers = [];
this.automaticBedAllocation.preBeds = [];
this.automaticBedAllocation.searchNameOrPhone = '';
},
cancelAutomaticBedAllocation() {
this.resetAutomaticBedAllocation();
},
isFollowerDisabled(item) {
return this.guadanguest.items.some(f => f.followerNum === item.num);
},
getFollowerRowClass(item) {
return this.isFollowerDisabled(item) ? 'bg-secondary' : '';
},
onMultiSelectChange(selectedItems) {
// 這裡拿到最新選中的列表
this.automaticBedAllocation.followerModal.selectedFollowerItems = selectedItems;
this.automaticBedAllocation.selectedFollowers = [...selectedItems];
},
showautomaticBedAllocationMethod() {
this.automaticBedAllocation.followerModal.showModal = true;
this.getMultiSelectFollowers();
},
// 獲取蓮友分頁數據
getMultiSelectFollowers: function () {
var fm = this.automaticBedAllocation.followerModal;
var self = this;
axios.post('/api/lianyou/getfollowers', null, {
params: {
page: fm.page,
pageSize: fm.pageSize,
searchName: fm.searchNameOrPhone || null
}
}).then(function (res) {
fm.followerList = res.data.data || [];
fm.totalCount = res.data.count || 0;
}).catch(function (err) {
console.error('獲取蓮友列表失敗', err);
});
},
// 選擇蓮友到右側
selectMultiFollower: function (item) {
var exists = this.automaticBedAllocation.selectedFollowers.some(function (f) {
return f.num === item.num;
});
if (!exists) {
this.automaticBedAllocation.selectedFollowers.push(item);
console.log(item)
}
},
// 移除已選蓮友
removeSelectedFollower: function (num) {
var arr = this.automaticBedAllocation.selectedFollowers;
this.automaticBedAllocation.selectedFollowers = arr.filter(function (f) {
return f.num !== num;
});
this.automaticBedAllocation.followerModal.selectedFollowerItems = this.automaticBedAllocation.followerModal.selectedFollowerItems.filter(f => f.num !== num);
},
removePreBed(num) {
this.automaticBedAllocation.preBeds = this.automaticBedAllocation.preBeds.filter(item => item.num !== num);
console.log(this.automaticBedAllocation.preBeds.length)
},
//自動分配相關方法--------------------end
//掛單相關方法-------------------start
validateOrderForm() {
if (!this.guadanorder.order_form.startdate) {
this.$refs.messageModal.open({
message: '請輸入必填資訊'
});
return false;
}
if (!this.guadanorder.order_form.enddate) {
this.$refs.messageModal.open({
message: '請輸入必填資訊'
});
return false;
}
if (!this.guadanorder.order_form.bookerName) {
this.$refs.messageModal.open({
message: '請輸入姓名'
});
return false;
}
if (this.guadanorder.order_form.bookerPhone && !/^\d{2,4}-?\d{3,4}-?\d{3,4}$/.test(this.guadanorder.order_form.bookerPhone)) {
this.$refs.messageModal.open({
message: '電話輸入有誤'
});
return false;
}
return true;
},
getGuadanOrderById() {
if (this.guadanorder.order_form.uuid) {
axios.get('/api/guadan/getorderbyid', {
params: {
orderId: this.guadanorder.order_form.uuid
}
}).then((res) => {
this.guadanorder.order_form.note = res.data.notes;
this.guadanorder.order_form.startdate = res.data.startDate;
this.guadanorder.order_form.enddate = res.data.endDate;
this.guadanorder.order_form.orderNo = res.data.guaDanOrderNo;
this.guadanorder.order_form.bookerName = res.data.bookerName;
this.guadanorder.order_form.bookerPhone = res.data.bookerPhone;
this.guadanorder.order_form.bookerFollowerNum = res.data.bookerFollowerNum;
this.guadanorder.order_form.uuid = res.data.uuid;
this.guadanorder.order_form.activityNum = res.data.activityNum;
})
}
},
getGuadanOrderGuestByOrderNo() {
if (this.guadanorder.order_form.orderNo) {
axios.get('/api/guadanorderguest/getbyorderno', {
params: {
orderNo: this.guadanorder.order_form.orderNo
}
}).then((res => {
this.guadanguest.items = res.data;
}))
}
},
getGuadanOrderStatus() {
axios.get('/api/region/guadan/status/list')
.then((res) => {
this.guadanorder.status_items = res.data;
})
},
createGuadanOrder() {
if (!this.validateOrderForm()) {
return;
}
axios.post('/api/guadan/create', this.guadanorder.order_form)
.then((res => {
this.$refs.messageModal.open({
title: '掛單提示',
message: '掛單資料建立成功'
})
this.guadanorder.order_form.uuid = res.data.uuid;
this.guadanorder.order_form.orderNo = res.data.guaDanOrderNo;
console.log(this.guadanorder.order_form.uuid);
// 跳转到当前 URL 加上 ?orderId=UUID
const currentUrl = window.location.origin + window.location.pathname;
window.location.href = `${currentUrl}?orderId=${res.data.guaDanOrderNo}`;
})).catch((error) => {
this.$refs.messageModal.open({
title: '錯誤',
message: '建立掛單資料失敗:' + (error.response?.data?.message || error.message)
});
});
},
updateGuadanOrder() {
if (!this.validateOrderForm()) {
return;
}
axios.post('/api/guadan/update', this.guadanorder.order_form)
.then((res => {
this.$refs.messageModal.open({
title: '掛單提示',
message: '掛單資料更新成功'
})
this.guadanorder.order_form.uuid = res.data.uuid;
console.log(this.guadanorder.order_form.uuid);
})).catch((error) => {
this.$refs.messageModal.open({
title: '錯誤',
message: '建立掛單資料失敗:' + (error.response?.data?.message || error.message)
});
});
},
showCheckInModal() {
if (!this.guadanorder.order_form.uuid) {
this.$refs.messageModal.open({
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.checkInGuest.showSelectGuadanOrderGuest = true;
},
closeCheckInModal() {
this.resetRegionModal();
this.resetInGuest();
this.selectGuestModal.currentSelectedGuest = null;
this.selectGuestModal.fullNameText = null;
this.checkInGuest.showSelectGuadanOrderGuest = false;
this.checkInGuest.isEdit = false;
},
//掛單相關方法-------------------end
//增加蓮友方法-------------------start
checkoutGuadanOrderGuest(guest) {
this.$refs.confirmModal.open({
message: `確定要將 ${guest.follower.u_name || ''} 退房嗎?`,
onConfirm: async () => {
try {
const response = await axios.post(`/api/guadanorderguest/checkout`, null, {
params: { uuid: guest.uuid }
});
// 成功提示
this.$refs.messageModal.open({
title: '操作成功',
message: '退房成功!',
status: 'success'
});
// 更新狀態並刷新資料
guest.statusCode = "403"; // 已退房
this.getGuadanOrderGuestByOrderNo();
} catch (error) {
console.error(error);
// 失敗提示
this.$refs.messageModal.open({
title: '操作失敗',
message: error.response?.data?.message || '退房過程中發生錯誤!',
status: 'error'
});
}
}
});
},
resetInGuest() {
this.checkInGuest.inGuest = {
uuid: null,
orderNo: null,
guestId: null,
roomUuid: null,
bedUuid: null,
checkInAt: null,
checkOutAt: null,
statuscode: null,
};
},
setInGuest() {
if (this.region_modal.currentSelectRoom) {
this.checkInGuest.inGuest.roomUuid = this.region_modal.currentSelectRoom.uuid;
}
if (this.region_modal.currentSelectBed) {
this.checkInGuest.inGuest.bedUuid = this.region_modal.currentSelectBed.uuid;
}
console.log(this.checkInGuest.inGuest)
},
validateCheckInGuest() {
//驗證添加掛單蓮友的時候輸入資料
if (!this.checkInGuest.inGuest.orderNo) {
this.$refs.messageModal.open({
message: '掛單編號不能為空'
})
}
if (!this.checkInGuest.inGuest.checkInAt) {
this.$refs.messageModal.open({
message: '入住時間不能為空'
})
return false;
}
if (!this.checkInGuest.inGuest.checkOutAt) {
this.$refs.messageModal.open({
message: '退單時間不能為空'
})
return false;
}
if (!this.checkInGuest.inGuest.roomUuid) {
this.$refs.messageModal.open({
message: '請選擇房間'
})
return false;
}
if (!this.checkInGuest.inGuest.bedUuid) {
this.$refs.messageModal.open({
message: '請選擇房間'
})
return false;
}
return true;
},
async saveCheckInGuest() {
if (!this.validateCheckInGuest()) {
return;
}
try {
const res = await this.createCheckInGuest();
this.getGuadanOrderGuestByOrderNo();
this.closeCheckInModal();
} catch (error) {
console.log(error)
this.$refs.messageModal.open({
message: (error.response?.data?.message || error.message)
})
}
},
createCheckInGuest() {
return axios.post('/api/guadanorderguest/create', this.checkInGuest.inGuest)
},
checkBedAndFollower() {
this.checkInGuest.inGuest
},
getGuadanGuestStatus() {
axios.get('/api/region/bed/status/list')
.then((res) => {
this.checkInGuest.status = res.data.filter(item => item.category === 4 && item.code != '404');
})
},
//增加蓮友方法-------------------end
//蓮友選擇相關方法---------------start
getGuadanFollowers() {
//從信眾表中獲取掛單人列表
const {
sortBy,
sortDesc,
page,
itemsPerPage
} = this.selectGuestModal.options
const params = {
sortBy: sortBy[0],
sortDesc: sortDesc[0],
page: page,
pageSize: itemsPerPage,
searchName: this.selectGuestModal.searchNameOrPhone
};
axios.post('/api/lianyou/getfollowers', null, {
params: params
}).then((res) => {
this.selectGuestModal.items = res.data.data
this.selectGuestModal.count = res.data.count;
})
},
showSelectGuestModalMethod() {
this.selectGuestModal.showSelectGuestModal = true;
},
selectGuadanOrderGuest(guest) {
this.selectGuestModal.currentSelectedGuest = guest;
console.log('----------' + guest)
this.selectGuestModal.fullNameText = guest.u_name;
this.checkInGuest.inGuest.followerNum = guest.num;
this.selectGuestModal.showSelectGuestModal = false;
},
editGuadanOrderGuest(guest) {
this.checkInGuest.inGuest.uuid = guest.uuid;
this.checkInGuest.inGuest.followerNum = guest.followerNum;
this.checkInGuest.inGuest.roomUuid = guest.roomUuid;
this.checkInGuest.inGuest.bedUuid = guest.bedUuid;
this.checkInGuest.inGuest.orderNo = guest.orderNo;
this.checkInGuest.inGuest.checkInAt = guest.checkinat;
this.checkInGuest.inGuest.checkOutAt = guest.checkoutat;
this.checkInGuest.showSelectGuadanOrderGuest = true;
this.checkInGuest.isEdit = true;
this.getCurrentSelectBedTextByBedId(guest.bedUuid);
this.selectGuestModal.fullNameText = guest.follower?.u_name;
this.selectGuestModal.currentSelectedGuest = guest.follower;
this.checkInGuest.inGuest.statuscode = guest.statuscode;
},
async saveEditGuadanOrderGuest() {
try {
const res = await axios.post('/api/guadanorderguest/update', this.checkInGuest.inGuest)
this.getGuadanOrderGuestByOrderNo();
this.closeCheckInModal();
} catch (error) {
this.$refs.messageModal.open({
message: (error.response?.data?.message || error.message)
})
}
},
deleteGuadanOrderGuest(guest) {
axios.post('/api/guadanorderguest/cancel?uuid=' + guest.uuid)
.then((res) => {
this.guadanguest.items = this.guadanguest.items.filter(i => i.uuid != guest.uuid);
}).catch((error) => {
this.$refs.messageModal.open({
message: (error.response?.data?.message || error.message)
})
});
},
confirmDeleteGuadanOrderGuest(guest) {
this.$refs.confirmModal.open({
'message': '確認取消?',
'onConfirm': () => {
this.deleteGuadanOrderGuest(guest);
}
})
},
async checkinGuadanGuest(guest) {
// 先確認操作
this.$refs.confirmModal.open({
message: '確認入住?',
onConfirm: async () => {
try {
// 發送請求到後端 API
const response = await axios.post(`/api/guadanorderguest/checkin`, null, {
params: { uuid: guest.uuid }
});
// 成功提示
this.$refs.messageModal.open({
title: '操作成功',
message: '入住成功!',
status: 'success'
});
// 更新本地列表,修改狀態為已入住 (402)
guest.statusCode = "402";
// 如果需要刷新整個列表,也可以調用
this.getGuadanOrderGuestByOrderNo();
} catch (error) {
console.error(error);
// 失敗提示
this.$refs.messageModal.open({
title: '操作失敗',
message: error.response?.data?.message || '入住過程中發生錯誤!',
status: 'error'
});
}
}
});
},
//蓮友選擇相關方法---------------end
//床位選擇相關方法----------------start
async loadRegions() {
const res = await axios.post('/api/region/getRegionList');
this.region_modal.regions = res.data;
},
async loadRegionsByGender() {
let isMale = null;
const guest = this.selectGuestModal.currentSelectedGuest;
if (guest && guest.sex) {
if (guest.sex === '男眾') {
isMale = true;
} else if (guest.sex === '女眾') {
isMale = false;
}
}
const res = await axios.post('/api/region/getRegionListByGender', {
IsMale: isMale
});
this.region_modal.regions = res.data;
},
selectRegion(region) {
this.region_modal.currentSelectRegion = region;
this.region_modal.selectedId = region.uuid;
this.region_modal.selectedType = 'region';
},
selectRoom(room) {
this.region_modal.currentSelectRoom = room;
this.region_modal.selectedId = room.uuid;
this.region_modal.selectedType = 'room';
this.region_modal.currentSelectBeds = room.beds;
if (this.checkInGuest.inGuest.checkInAt && this.checkInGuest.inGuest.checkOutAt) {
axios.get('/api/region/room/bed/list', {
params: {
roomUuid: room.uuid,
StartTime: this.checkInGuest.inGuest.checkInAt,
EndTime: this.checkInGuest.inGuest.checkOutAt
}
})
.then((res) => {
this.region_modal.currentSelectBeds = res.data
})
}
},
selectBed(bed) {
this.region_modal.currentSelectBed = bed;
this.getCurrentSelectBedTextByBedId(bed.uuid);
},
GetRegionRoomBedListByRoomId(roomUuid) {
if (this.checkInGuest.inGuest.checkInAt && this.checkInGuest.inGuest.checkOutAt) {
axios.get('/api/region/bed/list')
.then((res) => {
})
}
},
cancelSelectBed() {
this.resetRegionModal();
this.getCurrentSelectBedTextByBedId(this.checkInGuest.inGuest.bedUuid);
this.region_modal.showSelectBedModal = false;
},
confirmSelectBed() {
this.region_modal.showSelectBedModal = false;
//this.setOrderForm();
this.setInGuest();
},
openSelectBedModal() {
if (!this.checkInGuest.inGuest.checkInAt || !this.checkInGuest.inGuest.checkOutAt) {
this.$refs.messageModal.open({
message: '請先選擇時間'
});
return;
}
this.region_modal.showSelectBedModal = true;
this.loadRegionsByGender();
this.getavailablebedcountbytime(this.checkInGuest.inGuest.checkInAt, this.checkInGuest.inGuest.checkOutAt);
},
getCurrentSelectBedTextByBedId(bedUuid) {
//獲取當前選擇的床位和所有上級組成的字串
this.region_modal.currentSelectBedText = this.findBedPath(this.region_modal.regions, bedUuid)
},
findBedPath(data, targetBedId) {
const path = [];
function dfs(regions, currentPath) {
for (const region of regions) {
const regionPath = [...currentPath, region.name];
// 遍歷當前區域的 rooms
for (const room of region.rooms || []) {
const roomPath = [...regionPath, room.name];
// 尋找床位
for (const bed of room.beds || []) {
if (bed.uuid === targetBedId) {
// 找到目標床位
path.push(...roomPath, bed.name);
return true;
}
}
}
// 遍歷子區域
if (region.children && region.children.length > 0) {
if (dfs(region.children, regionPath)) {
return true;
}
}
}
return false;
}
dfs(data, []);
return path.length > 0 ? path.join(' / ') : null;
},
resetRegionModal() {
this.region_modal.currentSelectBeds = [];
this.region_modal.currentSelectRegion = null;
this.region_modal.currentSelectRoom = null;
this.region_modal.currentSelectBed = null;
this.region_modal.selectedId = null;
this.region_modal.selectedType = null;
this.region_modal.expandAllFlag = null;
this.region_modal.collapseAllFlag = null;
this.region_modal.currentSelectBedText = '';
},
//床位選擇相關方法----------------end
formatDate(datetimeStr) {
const d = new Date(datetimeStr);
return d.toLocaleDateString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
});
},
},
watch: {
'guadanorder.order_form.orderNo'(newValue, oldValue) {
if (newValue) {
this.getGuadanOrderGuestByOrderNo();
}
},
'selectGuestModal.options': {
handler() {
this.getGuadanFollowers();
},
deep: true
},
// 分頁變化時自動刷新
'automaticBedAllocation.followerModal.page': function () {
this.getMultiSelectFollowers();
},
'automaticBedAllocation.followerModal.pageSize': function () {
this.getMultiSelectFollowers();
}
},
mounted() {
if (this.guadanorder.order_form.uuid) {
this.getGuadanOrderById();
this.getGuadanOrderGuestByOrderNo();
}
this.loadRegions();
this.getGuadanOrderStatus();
this.getGuadanGuestStatus();
this.getActivityList();
},
computed: {
pageCount() {
return Math.ceil(this.selectGuestModal.count / this.selectGuestModal.pageSize)
},
pageCount2: function () {
var fm = this.automaticBedAllocation.followerModal;
return Math.ceil(fm.totalCount / fm.pageSize) || 1;
}
},
});
</script>
</asp:Content>