267 lines
9.8 KiB
Plaintext
267 lines
9.8 KiB
Plaintext
<%@ Page Title="" Language="C#" MasterPageFile="~/admin/Templates/TBS5ADM001/MasterPage.master" AutoEventWireup="true" CodeFile="statistics_table.aspx.cs" Inherits="admin_guadan_statistics_table" %>
|
||
|
||
<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="section mb-6">
|
||
<v-card outlined class="pa-1">
|
||
<v-card-title class="headline grey--text text--darken-2">
|
||
掛單統計
|
||
</v-card-title>
|
||
<v-divider class="mb-4"></v-divider>
|
||
<v-card-text>
|
||
<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>
|
||
|
||
</v-card-text>
|
||
</v-card>
|
||
</div>
|
||
|
||
<!-- 近期床位使用統計 -->
|
||
<div class="section container">
|
||
<!-- 日期筛选区 -->
|
||
<div class="d-flex align-center flex-wrap" style="gap: 5px;">
|
||
<!-- 开始日期 -->
|
||
<v-menu
|
||
ref="menu1"
|
||
v-model="menu1"
|
||
:close-on-content-click="false"
|
||
transition="scale-transition"
|
||
offset-y
|
||
min-width="auto"
|
||
>
|
||
<template v-slot:activator="{ on, attrs }">
|
||
<v-text-field
|
||
v-model="startDate"
|
||
label="開始日期"
|
||
prepend-icon="mdi-calendar"
|
||
readonly
|
||
v-bind="attrs"
|
||
v-on="on"
|
||
dense
|
||
outlined
|
||
></v-text-field>
|
||
</template>
|
||
<v-date-picker v-model="startDate" @input="menu1 = false"></v-date-picker>
|
||
</v-menu>
|
||
|
||
<!-- 结束日期 -->
|
||
<v-menu
|
||
ref="menu2"
|
||
v-model="menu2"
|
||
:close-on-content-click="false"
|
||
transition="scale-transition"
|
||
offset-y
|
||
min-width="auto"
|
||
>
|
||
<template v-slot:activator="{ on, attrs }">
|
||
<v-text-field
|
||
v-model="endDate"
|
||
label="結束日期"
|
||
prepend-icon="mdi-calendar"
|
||
readonly
|
||
v-bind="attrs"
|
||
v-on="on"
|
||
dense
|
||
outlined
|
||
></v-text-field>
|
||
</template>
|
||
<v-date-picker v-model="endDate" @input="menu2 = false"></v-date-picker>
|
||
</v-menu>
|
||
|
||
<!-- 查询按钮 -->
|
||
<v-btn
|
||
color="primary"
|
||
@click="getList"
|
||
style="align-self: stretch;"
|
||
>
|
||
查詢
|
||
</v-btn>
|
||
<v-btn
|
||
color="primary"
|
||
style="align-self: stretch;"
|
||
@click="exportStatisticsToExcel">
|
||
導出下面表格數據到Excel
|
||
</v-btn>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<v-divider class="mb-4"></v-divider>
|
||
|
||
<div>
|
||
<!-- 表格 -->
|
||
<v-data-table
|
||
:items="items"
|
||
:headers="headers"
|
||
class="elevation-2"
|
||
dense
|
||
hide-default-footer
|
||
:items-per-page="10"
|
||
>
|
||
<template #item.date="{ item }">
|
||
<span>{{ item.date | timeString('YYYY-MM-DD') }}</span>
|
||
</template>
|
||
<template #item.todaytotalbookers="{item}">
|
||
<span>
|
||
{{item?.todaytotalbookers + '(男' + '女)'}}
|
||
</span>
|
||
</template>
|
||
<template #item.checkin="{item}">
|
||
<span>
|
||
{{item?.checkin + '(男' + '女)'}}
|
||
</span>
|
||
</template>
|
||
<template #item.bedusagerate="{ item }">
|
||
{{ ((item.todaytotalbookers / bedcount) * 100).toFixed(2) + '%' }}
|
||
</template>
|
||
<template #item.roomcount="{item}">
|
||
{{roomcount}}
|
||
</template>
|
||
<template #item.bedcount="{item}">
|
||
{{bedcount}}
|
||
</template>
|
||
</v-data-table>
|
||
</div>
|
||
</asp:Content>
|
||
|
||
<asp:Content ID="Content4" ContentPlaceHolderID="offCanvasRight" Runat="Server">
|
||
</asp:Content>
|
||
<asp:Content ID="Content5" ContentPlaceHolderID="footer_script" Runat="Server">
|
||
<script>
|
||
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 {
|
||
items: [],
|
||
headers: [
|
||
{ text: '日期', value: 'date' },
|
||
{ text: '房间数量', value: 'roomcount' },
|
||
{ text: '床位数量', value: 'bedcount' },
|
||
{ text: '预约人数', value: 'todaytotalbookers' },
|
||
{ text: '已入住人数', value: 'checkin'},
|
||
{ text: '可用床位', value: 'availableBeds' },
|
||
{ text: '床位利用率', value: 'bedusagerate' }
|
||
],
|
||
startDate: null,
|
||
endDate: null,
|
||
menu1: false,
|
||
menu2: false,
|
||
bedcount: 0,
|
||
roomcount: 0,
|
||
guadanStatistics: {
|
||
guadanTotalCount: 0,
|
||
guadanCurrentCount: 0,
|
||
guadanPeopleTotal: 0,
|
||
guadanPeopleMale: 0,
|
||
guadanPeopleFemale: 0,
|
||
guadanPeopleCurrent: 0,
|
||
guadanPeopleCurrentMale: 0,
|
||
guadanPeopleCurrentFemale: 0
|
||
},
|
||
}
|
||
},
|
||
methods: {
|
||
async getList() {
|
||
try {
|
||
const res = await axios.get('/api/guadan/guadanstatisticstable/list', {
|
||
params: {
|
||
start: this.startDate || '',
|
||
end: this.endDate || ''
|
||
}
|
||
});
|
||
this.items = res.data.statistics;
|
||
this.roomcount = res.data.roomcount;
|
||
this.bedcount = res.data.bedcount;
|
||
} catch (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() {
|
||
this.getList();
|
||
this.GetGuadanStatistics();
|
||
}
|
||
|
||
})
|
||
</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>
|
||
|