调整挂单统计,修改删除区域报错

This commit is contained in:
2025-09-16 11:49:02 +08:00
parent f1e3f555e6
commit 40da17b414
11 changed files with 220 additions and 294 deletions

View File

@@ -33,6 +33,10 @@ public class guadanGuestQueryController: ApiController
{ {
query = query.Where(guest => guest.CheckInAt == search.searchCheckInDate); query = query.Where(guest => guest.CheckInAt == search.searchCheckInDate);
} }
if(search.searchCheckOutDate != null)
{
query = query.Where(guest => guest.CheckOutAt == search.searchCheckOutDate);
}
if(search.searchCheckInDateStart != null) if(search.searchCheckInDateStart != null)
{ {
query = query.Where(guest => guest.CheckInAt >= search.searchCheckInDateStart); query = query.Where(guest => guest.CheckInAt >= search.searchCheckInDateStart);

View File

@@ -330,31 +330,31 @@ public class guadanOrderGuestController : ApiController
[Route("api/guadanorderguest/xuzhu")] [Route("api/guadanorderguest/xuzhu")]
public async Task<IHttpActionResult> ExtendStay([FromBody] XuZhuModel model) public async Task<IHttpActionResult> ExtendStay([FromBody] XuZhuModel model)
{ {
//住方法 //住方法
if (model == null) if (model == null)
return BadRequest("请求数据为空"); return BadRequest("請求數據為空");
if (model.GuestUuid == Guid.Empty || model.GuestBedUuid == Guid.Empty) if (model.GuestUuid == Guid.Empty || model.GuestBedUuid == Guid.Empty)
return BadRequest("GuestUuid 或 GuestBedUuid 效"); return BadRequest("GuestUuid 或 GuestBedUuid 效");
var guest = await _db.GuaDanOrderGuest.FindAsync(model.GuestUuid); var guest = await _db.GuaDanOrderGuest.FindAsync(model.GuestUuid);
if (guest == null) if (guest == null)
{ {
return BadRequest("挂单不存在"); return BadRequest("掛單不存在");
} }
if (guest.BedUuid != model.GuestBedUuid) if (guest.BedUuid != model.GuestBedUuid)
{ {
return BadRequest("床位不正"); return BadRequest("床位不正");
} }
var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(_db, model.GuestBedUuid, model.CurrentCheckoutDate, model.NewCheckoutDate); var bedIsCanUse = await RegionAndRoomAndBedSchedule.IsBedAvailableAsync(_db, model.GuestBedUuid, model.CurrentCheckoutDate, model.NewCheckoutDate);
if (!bedIsCanUse) if (!bedIsCanUse)
{ {
return BadRequest("床位在续住时间段内被预定,无法续住"); return BadRequest("床位在續住時間段內被預定,無法續住");
} }
var newStartDate = model.CurrentCheckoutDate.Date; var newStartDate = model.CurrentCheckoutDate.Date;
var newEndDate = model.NewCheckoutDate.Date.AddDays(-1); var newEndDate = model.NewCheckoutDate.Date.AddDays(-1);
if (newEndDate < newStartDate) if (newEndDate < newStartDate)
return BadRequest("住日期区间无效"); return BadRequest("住日期區間無效");
for (var date = newStartDate; date <= newEndDate; date = date.AddDays(1)) for (var date = newStartDate; date <= newEndDate; date = date.AddDays(1))
{ {
var newSchedule = new RegionAndRoomAndBedSchedule var newSchedule = new RegionAndRoomAndBedSchedule
@@ -364,8 +364,8 @@ public class guadanOrderGuestController : ApiController
TargetUuid = model.GuestBedUuid, TargetUuid = model.GuestBedUuid,
GuaDanOrderGuestUuid = model.GuestUuid, GuaDanOrderGuestUuid = model.GuestUuid,
ScheduleDate = date, ScheduleDate = date,
Title = "续住挂单", // 一天一条,开始和束是同一天 Title = "續住掛單", // 一天一條,開始和束是同一天
Description = "续住挂单", Description = "續住掛單",
UseType = 30, UseType = 30,
CreatedAt = DateTime.UtcNow CreatedAt = DateTime.UtcNow
}; };
@@ -373,8 +373,8 @@ public class guadanOrderGuestController : ApiController
_db.RegionAndRoomAndBedSchedule.Add(newSchedule); _db.RegionAndRoomAndBedSchedule.Add(newSchedule);
} }
guest.CheckOutAt = model.NewCheckoutDate.Date; guest.CheckOutAt = model.NewCheckoutDate.Date;
await _db.SaveChangesAsync(); // 保存数据库操作 await _db.SaveChangesAsync(); // 保存資料庫操作
return Ok(new { message = "住成功" }); return Ok(new { message = "住成功" });
} }
[HttpPost] [HttpPost]
[Route("api/guadanorderguest/cancel")] [Route("api/guadanorderguest/cancel")]
@@ -495,13 +495,13 @@ public class guadanOrderGuestController : ApiController
//更新未來排程為取消 //更新未來排程為取消
var latestCheckoutStr = _db.GuadanTimeSetting var latestCheckoutStr = _db.GuadanTimeSetting
.Select(a => a.LatestCheckOut) // 字串 "HH:mm" .Select(a => a.LatestCheckOut) // 字串 "HH:mm"
.FirstOrDefault(); .FirstOrDefault();
TimeSpan? latestCheckoutTime = null; TimeSpan? latestCheckoutTime = null;
if (!string.IsNullOrEmpty(latestCheckoutStr)) if (!string.IsNullOrEmpty(latestCheckoutStr))
{ {
// 尝试解析字 // 嘗試解析字串
if (TimeSpan.TryParse(latestCheckoutStr, out var ts)) if (TimeSpan.TryParse(latestCheckoutStr, out var ts))
{ {
latestCheckoutTime = ts; latestCheckoutTime = ts;
@@ -598,7 +598,7 @@ public class guadanOrderGuestController : ApiController
} }
else else
{ {
return BadRequest($"前床位状态{bed.RegionRoomBedStatus.Name} 不能入住"); return BadRequest($"前床位狀態{bed.RegionRoomBedStatus.Name} 不能入住");
} }
} }
else if (guest.BedUuid == null) else if (guest.BedUuid == null)
@@ -653,10 +653,10 @@ public class guadanOrderGuestController : ApiController
} }
public class XuZhuModel public class XuZhuModel
{ {
public Guid GuestUuid { get; set; } // 不可 public Guid GuestUuid { get; set; } // 不可
public Guid GuestBedUuid { get; set; } // 不可 public Guid GuestBedUuid { get; set; } // 不可
public DateTime CurrentCheckoutDate { get; set; } // 前退房时间 public DateTime CurrentCheckoutDate { get; set; } // 前退房時間
public DateTime NewCheckoutDate { get; set; } // 新退房时间 public DateTime NewCheckoutDate { get; set; } // 新退房時間
} }
} }

View File

@@ -21,39 +21,49 @@ public class guadanStatisticsController: ApiController
//挂单统计:房间,床位,挂单笔数,挂单人数的统计 //挂单统计:房间,床位,挂单笔数,挂单人数的统计
var now = DateTime.Now; var now = DateTime.Now;
var roomCount = await _db.Room.Where(a => a.IsDeleted == false).CountAsync(); var guadanTotalCount = await _db.GuaDanOrder
var rooms = await _db.Room.Include(r => r.RegionRoomBed).ToListAsync(); .Where(a => a.IsDeleted == false)
.Where(a => a.IsCancel == false)
var emptyRoomCount = rooms .CountAsync();
.Where(r => r.RegionRoomBed.All(b => b.IsAvailableDuring(now, now, _db))) // 這裡就能用方法 var guadanCurrentCount = await _db.GuaDanOrderGuest
.Count(); .Where(guest => guest.StatusCode != "403")
var bedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false).CountAsync(); .Where(guest => guest.StatusCode != "404")
var maleBedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false && a.Gender == true).CountAsync(); .Select(guest => guest.GuaDanOrderNo)
var femaleBedCount = await _db.RegionRoomBed.Where(a => a.IsDeleted == false && a.Gender == false).CountAsync(); .Distinct()
.CountAsync();
var guadanTotalCount = await _db.GuaDanOrder.Where(a => a.IsDeleted == false).CountAsync(); var guadanPeopleTotal = await _db.GuaDanOrderGuest
var guadanPeopleTotal = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false).CountAsync(); .Where(a => a.IsDeleted == false)
var guadanPeopleMale = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false && a.followers.sex == "男眾").CountAsync(); .Where(guest => guest.StatusCode != "404")
var guadanPeopleFemale = await _db.GuaDanOrderGuest.Where(a => a.IsDeleted == false && a.followers.sex == "女眾").CountAsync(); .CountAsync();
dynamic bedCounts = await RegionAndRoomAndBedSchedule.GetAvailableBedCountsAsync(_db, DateTime.Now, DateTime.Now); var guadanPeopleMale = await _db.GuaDanOrderGuest
var guadanCurrentCount = await _db.GuaDanOrder.Where(a => now < a.EndDate).CountAsync(); .Where(guest => guest.StatusCode != "404")
var guadanPeopleCurrent = await _db.GuaDanOrderGuest.Where( a => a.CheckOutAt > now).CountAsync(); .Where(a => a.IsDeleted == false && a.followers.sex == "男眾")
var guadanPeopleCurrentMale = await _db.GuaDanOrderGuest.Where(a => a.CheckOutAt > now && a.followers.sex == "男眾").CountAsync(); .CountAsync();
var guadanPeopleCurrentFemale = await _db.GuaDanOrderGuest.Where(a => a.CheckOutAt > now && a.followers.sex == "女眾").CountAsync(); var guadanPeopleFemale = await _db.GuaDanOrderGuest
.Where(guest => guest.StatusCode != "404")
.Where(a => a.IsDeleted == false && a.followers.sex == "女眾")
.CountAsync();
var guadanPeopleCurrent = await _db.GuaDanOrderGuest
.Where(a => a.IsDeleted == false)
.Where(guest => guest.StatusCode != "404")
.Where(guest => guest.StatusCode != "403")
.Where( a => a.CheckOutAt >= now.Date)
.CountAsync();
var guadanPeopleCurrentMale = await _db.GuaDanOrderGuest
.Where(a => a.IsDeleted == false)
.Where(guest => guest.StatusCode != "404")
.Where(guest => guest.StatusCode != "403")
.Where(a => a.CheckOutAt >= now.Date && a.followers.sex == "男眾")
.CountAsync();
var guadanPeopleCurrentFemale = await _db.GuaDanOrderGuest
.Where(a => a.IsDeleted == false)
.Where(guest => guest.StatusCode != "404")
.Where(guest => guest.StatusCode != "403")
.Where(a => a.CheckOutAt >= now.Date && a.followers.sex == "女眾")
.CountAsync();
var result = new var result = new
{ {
roomStatistics = new
{
roomCount = roomCount,
emptyRoomCount = emptyRoomCount,
bedCount = bedCount,
maleBedCount = maleBedCount,
femaleBedCount = femaleBedCount,
emptyBedCount = bedCounts.male + bedCounts.female,
emptyMaleBedCount = bedCounts.male,
emptyFemaleBedCount = bedCounts.female
},
guadanStatistics = new guadanStatistics = new
{ {
guadanTotalCount = guadanTotalCount, // 总挂单次数 guadanTotalCount = guadanTotalCount, // 总挂单次数
@@ -61,7 +71,7 @@ public class guadanStatisticsController: ApiController
guadanPeopleTotal = guadanPeopleTotal, // 总挂单人数 guadanPeopleTotal = guadanPeopleTotal, // 总挂单人数
guadanPeopleMale = guadanPeopleMale, guadanPeopleMale = guadanPeopleMale,
guadanPeopleFemale = guadanPeopleFemale, guadanPeopleFemale = guadanPeopleFemale,
guadanPeopleCurrent = guadanPeopleCurrent, // 当前挂单人数 guadanPeopleCurrent = guadanPeopleCurrent, // 已預約掛單人數
guadanPeopleCurrentMale = guadanPeopleCurrentMale, guadanPeopleCurrentMale = guadanPeopleCurrentMale,
guadanPeopleCurrentFemale = guadanPeopleCurrentFemale guadanPeopleCurrentFemale = guadanPeopleCurrentFemale
} }

View File

@@ -63,16 +63,6 @@ public class guadanStatisticsTableController: ApiController
.OrderBy(x => x.date) .OrderBy(x => x.date)
.ToList(); .ToList();
var todayDate = DateTime.Today; var todayDate = DateTime.Today;
dynamic today = statistics.FirstOrDefault(x => x.date == todayDate);
if (today == null)
{
var todayCount = _db.RegionAndRoomAndBedSchedule
.Where(s => s.ScheduleDate == todayDate && !s.IsCancel)
.Count();
today = new { date = todayDate, todaytotalbookers = todayCount };
}
var bedcount = _db.RegionRoomBed var bedcount = _db.RegionRoomBed
.Where(a => a.IsDeleted == false) .Where(a => a.IsDeleted == false)
@@ -83,11 +73,6 @@ public class guadanStatisticsTableController: ApiController
bedcount, bedcount,
roomcount, roomcount,
statistics, statistics,
today,
totalbookers = _db.RegionAndRoomAndBedSchedule
.Where(s => s.IsCancel == false)
.Where(s => s.ScheduleDate >= DateTime.Today)
.Count(),
}; };
return Ok(result); return Ok(result);

View File

@@ -107,7 +107,7 @@ public class regionController : ApiController
&& (s.ScheduleDate == null && (s.ScheduleDate == null
|| (s.ScheduleDate >= startDate))) || (s.ScheduleDate >= startDate)))
.Where(s => s.GuaDanOrderGuest.StatusCode != "403" && s.GuaDanOrderGuest.StatusCode != "404") .Where(s => s.GuaDanOrderGuest.StatusCode != "403" && s.GuaDanOrderGuest.StatusCode != "404")
.OrderByDescending(a => a.ScheduleDate) .OrderBy(a => a.ScheduleDate)
.Select(s => new .Select(s => new
{ {
s.Uuid, s.Uuid,

View File

@@ -6,6 +6,9 @@
<nav> <nav>
<a href="create.aspx" class="btn btn-primary" >新建掛單</a> <a href="create.aspx" class="btn btn-primary" >新建掛單</a>
</nav> </nav>
<div class="me-10">
<button class="btn btn-primary" type="button">查询</button>
</div>
</asp:Content> </asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server"> <asp:Content ID="Content3" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
@@ -27,10 +30,10 @@
{{item.status}} {{item.status}}
</template> </template>
<template #item.start_date="{item}"> <template #item.start_date="{item}">
{{item.start_date | timeString('YYYY/MM/DD HH:mm')}} {{item.start_date | timeString('YYYY/MM/DD')}}
</template> </template>
<template #item.end_date="{item}"> <template #item.end_date="{item}">
{{item.end_date | timeString('YYYY/MM/DD HH:mm')}} {{item.end_date | timeString('YYYY/MM/DD')}}
</template> </template>
<template #item.created_at="{item}"> <template #item.created_at="{item}">
{{item.created_at | timeString('YYYY/MM/DD HH:mm')}} {{item.created_at | timeString('YYYY/MM/DD HH:mm')}}
@@ -43,6 +46,7 @@
<confirm-modal ref="confirmModal"></confirm-modal> <confirm-modal ref="confirmModal"></confirm-modal>
</asp:Content> </asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server"> <asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
<div>test</div>
</asp:Content> </asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server"> <asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
<script> <script>

View File

@@ -1,143 +0,0 @@
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="statistics.aspx.cs" Inherits="admin_guadan_statistics" %>
<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">
<div class="container my-4">
<!-- 客房统计 -->
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3">
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">🏠</div>
<div class="text-muted small mt-1">总房间数量</div>
<div class="fw-bold fs-5 mt-1">{{ roomStatistics.roomCount }}</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">🚪</div>
<div class="text-muted small mt-1">空房间数量</div>
<div class="fw-bold fs-5 mt-1">{{ roomStatistics.emptyRoomCount }}</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">🛏️</div>
<div class="text-muted small mt-1">总床位数量</div>
<div class="fw-bold fs-5 mt-1">
{{ roomStatistics.bedCount }} (男:{{ roomStatistics.maleBedCount }},女:{{ roomStatistics.femaleBedCount }}
</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">🛌</div>
<div class="text-muted small mt-1">可用空床</div>
<div class="fw-bold fs-5 mt-1">
{{ roomStatistics.emptyBedCount }} (男:{{ roomStatistics.emptyMaleBedCount }},女:{{ roomStatistics.emptyFemaleBedCount }}
</div>
</div>
</div>
</div>
<!-- 挂单统计 -->
<div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3 mt-1">
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">📝</div>
<div class="text-muted small mt-1">总挂单次数</div>
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanTotalCount }}</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">📋</div>
<div class="text-muted small mt-1">当前挂单数量</div>
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanCurrentCount }}</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">👥</div>
<div class="text-muted small mt-1">总挂单人数</div>
<div class="fw-bold fs-5 mt-1">
{{ guadanStatistics.guadanPeopleTotal }} (男:{{ guadanStatistics.guadanPeopleMale }},女:{{ guadanStatistics.guadanPeopleFemale }}
</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">👨👩</div>
<div class="text-muted small mt-1">当前挂单人数</div>
<div class="fw-bold fs-5 mt-1">
{{ guadanStatistics.guadanPeopleCurrent }} (男:{{ guadanStatistics.guadanPeopleCurrentMale }},女:{{ guadanStatistics.guadanPeopleCurrentFemale }}
</div>
</div>
</div>
</div>
</div>
</asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
</asp:Content>
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(vuetify_options),
data() {
return {
roomStatistics: {
roomCount: 0,
emptyRoomCount: 0,
bedCount: 0,
maleBedCount: 0,
femaleBedCount: 0,
emptyBedCount: 0,
emptyMaleBedCount: 0,
emptyFemaleBedCount: 0
},
guadanStatistics: {
guadanTotalCount: 0,
guadanCurrentCount: 0,
guadanPeopleTotal: 0,
guadanPeopleMale: 0,
guadanPeopleFemale: 0,
guadanPeopleCurrent: 0,
guadanPeopleCurrentMale: 0,
guadanPeopleCurrentFemale: 0
},
}
},
methods: {
GetGuadanStatistics() {
axios.get('/api/guadanStatistics/GetGuadanStatistics')
.then((res) => {
this.roomStatistics = res.data.roomStatistics;
this.guadanStatistics = res.data.guadanStatistics;
})
}
},
watch: {
},
mounted() {
this.GetGuadanStatistics();
// 每两分钟更新一次 (2 * 60 * 1000 毫秒)
setInterval(() => {
this.GetGuadanStatistics();
}, 1 * 60 * 1000);
},
})
</script>
</asp:Content>

View File

@@ -1,14 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class admin_guadan_statistics : MyWeb.config
{
protected void Page_Load(object sender, EventArgs e)
{
}
}

View File

@@ -9,41 +9,56 @@
<div class="section mb-6"> <div class="section mb-6">
<v-card outlined class="pa-1"> <v-card outlined class="pa-1">
<v-card-title class="headline grey--text text--darken-2"> <v-card-title class="headline grey--text text--darken-2">
今日使用情况 掛單統計
</v-card-title> </v-card-title>
<v-divider class="mb-4"></v-divider> <v-divider class="mb-4"></v-divider>
<v-card-text> <v-card-text>
<div class="d-flex flex-wrap justify-space-around"> <div class="row row-cols-2 row-cols-sm-3 row-cols-md-4 row-cols-lg-5 g-3 mt-1">
<v-card class="ma-2 pa-3 text-center" color="#e3f2fd" outlined> <div class="col">
<div class="subtitle-1 font-weight-bold">总预订人数</div> <div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="headline">{{totalbookers }}</div> <div class="fs-2">📝</div>
</v-card> <div class="text-muted small mt-1">总挂单次数</div>
<v-card class="ma-2 pa-3 text-center" color="#e3f2fd" outlined> <div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanTotalCount }}</div>
<div class="subtitle-1 font-weight-bold">今日预订人数</div>
<div class="headline">{{today.todaytotalbookers }}</div>
</v-card>
<v-card class="ma-2 pa-3 text-center" color="#e3f2fd" outlined>
<div class="subtitle-1 font-weight-bold">今日已入住人数</div>
<div class="headline">{{today.checkin }}</div>
</v-card>
<v-card class="ma-2 pa-3 text-center" color="#e3f2fd" outlined>
<div class="subtitle-1 font-weight-bold">今日待入住人数</div>
<div class="headline">{{today.todaytotalbookers - today.checkin }}</div>
</v-card>
<v-card class="ma-2 pa-3 text-center" color="#fce4ec" outlined>
<div class="subtitle-1 font-weight-bold">空床數</div>
<div class="headline">{{ bedcount - today.todaytotalbookers}}</div>
</v-card>
</div> </div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">📋</div>
<div class="text-muted small mt-1">当前挂单数量</div>
<div class="fw-bold fs-5 mt-1">{{ guadanStatistics.guadanCurrentCount }}</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">👥</div>
<div class="text-muted small mt-1">总挂单人数</div>
<div class="fw-bold fs-5 mt-1">
{{ guadanStatistics.guadanPeopleTotal }} (男:{{ guadanStatistics.guadanPeopleMale }},女:{{ guadanStatistics.guadanPeopleFemale }}
</div>
</div>
</div>
<div class="col">
<div class="p-3 bg-light text-center rounded shadow" style="min-height: 180px;">
<div class="fs-2">👨👩</div>
<div class="text-muted small mt-1">已預約掛單人數</div>
<div class="fw-bold fs-5 mt-1">
{{ guadanStatistics.guadanPeopleCurrent }} (男:{{ guadanStatistics.guadanPeopleCurrentMale }},女:{{ guadanStatistics.guadanPeopleCurrentFemale }}
</div>
</div>
</div>
</div>
</v-card-text> </v-card-text>
</v-card> </v-card>
</div> </div>
<!-- 近期床位使用統計 --> <!-- 近期床位使用統計 -->
<div class="section container"> <div class="section container">
<!-- 日期筛选区 --> <!-- 日期筛选区 -->
<div class="d-flex align-center flex-wrap" style="gap: 12px;"> <div class="d-flex align-center flex-wrap" style="gap: 5px;">
<!-- 开始日期 --> <!-- 开始日期 -->
<v-menu <v-menu
ref="menu1" ref="menu1"
@@ -100,6 +115,12 @@
> >
查詢 查詢
</v-btn> </v-btn>
<v-btn
color="primary"
style="align-self: stretch;"
@click="exportStatisticsToExcel">
導出下面表格數據到Excel
</v-btn>
</div> </div>
</div> </div>
@@ -119,6 +140,16 @@
<template #item.date="{ item }"> <template #item.date="{ item }">
<span>{{ item.date | timeString('YYYY-MM-DD') }}</span> <span>{{ item.date | timeString('YYYY-MM-DD') }}</span>
</template> </template>
<template #item.todaytotalbookers="{item}">
<span>
{{item?.todaytotalbookers + '(男' + '女)'}}
</span>
</template>
<template #item.checkin="{item}">
<span>
{{item?.checkin + '(男' + '女)'}}
</span>
</template>
<template #item.bedusagerate="{ item }"> <template #item.bedusagerate="{ item }">
{{ ((item.todaytotalbookers / bedcount) * 100).toFixed(2) + '%' }} {{ ((item.todaytotalbookers / bedcount) * 100).toFixed(2) + '%' }}
</template> </template>
@@ -154,14 +185,22 @@
{ text: '可用床位', value: 'availableBeds' }, { text: '可用床位', value: 'availableBeds' },
{ text: '床位利用率', value: 'bedusagerate' } { text: '床位利用率', value: 'bedusagerate' }
], ],
today: {},
totalbookers: 0,
startDate: null, startDate: null,
endDate: null, endDate: null,
menu1: false, menu1: false,
menu2: false, menu2: false,
bedcount: 0, bedcount: 0,
roomcount: 0, roomcount: 0,
guadanStatistics: {
guadanTotalCount: 0,
guadanCurrentCount: 0,
guadanPeopleTotal: 0,
guadanPeopleMale: 0,
guadanPeopleFemale: 0,
guadanPeopleCurrent: 0,
guadanPeopleCurrentMale: 0,
guadanPeopleCurrentFemale: 0
},
} }
}, },
methods: { methods: {
@@ -176,18 +215,52 @@
this.items = res.data.statistics; this.items = res.data.statistics;
this.roomcount = res.data.roomcount; this.roomcount = res.data.roomcount;
this.bedcount = res.data.bedcount; this.bedcount = res.data.bedcount;
this.today = res.data.today;
this.totalbookers = res.data.totalbookers;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
},
exportStatisticsToExcel() {
if (!this.items || !this.items.length) {
console.warn("没有数据可导出");
return;
} }
// 1. 取 items 数组并格式化
const sheetData = this.items.map(item => ({
日期: item.date.split('T')[0], // 格式化成 YYYY-MM-DD
预订人数: item.todaytotalbookers,
入住人数: item.checkin
}));
// 2. 转换成 XLSX Sheet
const ws = XLSX.utils.json_to_sheet(sheetData);
// 3. 创建 Workbook 并添加 Sheet
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "统计数据");
// 4. 写入 Excel 并下载
const wbout = XLSX.write(wb, { bookType: "xlsx", type: "array" });
saveAs(new Blob([wbout], { type: "application/octet-stream" }), "statistics.xlsx");
},
GetGuadanStatistics() {
axios.get('/api/guadanStatistics/GetGuadanStatistics')
.then((res) => {
this.guadanStatistics = res.data.guadanStatistics;
})
}
}, },
mounted() { mounted() {
this.getList(); this.getList();
this.GetGuadanStatistics();
} }
}) })
</script> </script>
<!-- CDN 方式引入 XLSX 和 FileSaver -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
</asp:Content> </asp:Content>

View File

@@ -172,42 +172,48 @@
</div> </div>
</div> </div>
<div> <div>
<v-dialog v-model="bedSchedule.dialogVisible" max-width="900"> <v-dialog v-model="bedSchedule.dialogVisible" max-width="900px">
<v-card> <v-card
style="min-height:50vh; max-height:80vh; display:flex; flex-direction:column;"
>
<v-card-title> <v-card-title>
<span class="text-h6">床位排程明細 - {{ bedSchedule.selectedBed?.name }}</span> <span class="text-h6">床位排程明細 - {{ bedSchedule.selectedBed?.name }}</span>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn icon @click="closeBedSchedule"> <v-btn icon @click="closeBedSchedule"><v-icon>mdi-close</v-icon></v-btn>
<v-icon>mdi-close</v-icon>
</v-btn>
</v-card-title> </v-card-title>
<v-card-text> <!-- 关键改动flex:1 1 auto; min-height:0; overflow-y:auto -->
<v-card-text style="flex:1 1 auto; min-height:0; overflow-y:auto;">
<div style="min-height:0;">
<v-data-table <v-data-table
:headers="bedSchedule.scheduleHeaders" :headers="bedSchedule.scheduleHeaders"
:items="bedSchedule.selectedBed?.schedules || []" :items="bedSchedule.selectedBed?.schedules || []"
:items-per-page="9999"
class="elevation-1" class="elevation-1"
dense dense
hide-default-footer hide-default-footer
:items-per-page="5"
> >
<template #item.scheduleDate="{item}"> <template #item.scheduleDate="{item}">
{{ item.scheduledate | timeString('YYYY-MM-DD') }} {{ item.scheduledate | timeString('YYYY-MM-DD') }}
</template> </template>
<template #item.actions="{item}"> <template #item.actions="{item}">
<a :href="'/admin/guadan/create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">查看掛單</a> <a :href="'/admin/guadan/create.aspx?orderId='+item.guaDanOrderNo" class="btn btn-primary">
查看掛單
</a>
</template> </template>
</v-data-table> </v-data-table>
</div>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn text color="primary" @click="closeBedSchedule">關閉</v-btn> <v-btn text color="primary" @click="closeBedSchedule">關閉</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
</v-dialog> </v-dialog>
</div>
</div>
</asp:Content> </asp:Content>
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server"> <asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
</asp:Content> </asp:Content>

View File

@@ -582,6 +582,7 @@
this.selectedType = 'region'; this.selectedType = 'region';
this.selectedRegionId = region.uuid; this.selectedRegionId = region.uuid;
this.currentSelectRegion = region; this.currentSelectRegion = region;
console.log(this.currentSelectRegion)
this.currentSelectRoom = null; this.currentSelectRoom = null;
this.resetRoomForm(); this.resetRoomForm();
this.form = { this.form = {
@@ -664,7 +665,7 @@
}); });
}, },
confirmDeleteRegion() { confirmDeleteRegion() {
axios.post('/api/region/delete', { statuscode: this.form.statuscode }) axios.post('/api/region/delete', { Uuid: this.form.uuid })
.then(() => { .then(() => {
this.showDeleteModal = false; this.showDeleteModal = false;
this.$refs.messageModal.open({ this.$refs.messageModal.open({