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

1809 lines
83 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<%@ 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 v-slot:item.sex="{item}">
{{item.follower?.sex}}
</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 && bed.isActive && !bed.bedIsStop) ? '#f6ffed' : '#fff1f0'), // 可用綠色,不可用紅色
color: (bed.canUsed && bed.isActive && !bed.bedIsStop) ? 'black' : '#999', // 不可用時灰色文字
pointerEvents: (bed.canUsed && bed.isActive && !bed.bedIsStop) ? 'auto' : 'none' // 不可用時無法點擊
}">
<div style="font-weight: 500;">{{ bed.name }}</div>
<div style="margin-top: 4px; font-size: 12px;">
{{ (!bed.isActive || bed.bedIsStop) ? '停用' : (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: 'sex'
},
{
text: '掛單開始時間',
value: 'checkinat'
},
{
text: '掛單結束時間',
value: 'checkoutat'
},
{
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(HTTP_HOST + '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(HTTP_HOST + 'api/activity/GetList?page=1&pageSize=500', { kind: 0, subject: "" })
.then((res) => {
this.activityList = res.data.list
})
},
getavailablebedcountbytime(startTime, endTime) {
axios.get(HTTP_HOST + '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(HTTP_HOST + '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();
}).catch((error) => {
this.$refs.messageModal.open({
message: (error.response?.data?.message || error.message)
});
});
},
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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + 'api/guadanorderguest/getbyorderno', {
params: {
orderNo: this.guadanorder.order_form.orderNo
}
}).then((res => {
this.guadanguest.items = res.data;
}))
}
},
getGuadanOrderStatus() {
axios.get(HTTP_HOST + 'api/region/guadan/status/list')
.then((res) => {
this.guadanorder.status_items = res.data;
})
},
createGuadanOrder() {
if (!this.validateOrderForm()) {
return;
}
axios.post(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + 'api/guadanorderguest/create', this.checkInGuest.inGuest)
},
checkBedAndFollower() {
this.checkInGuest.inGuest
},
getGuadanGuestStatus() {
axios.get(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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(HTTP_HOST + '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>