You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1212 lines
60 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>宾馆信息管理系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root{
--primary:#3f51b5;
--primary-dark:#303f9f;
--success:#4caf50;
--warning:#ff9800;
--danger:#f44336;
--bg:#f3f5fb;
--card:#ffffff;
--text:#2c2c2c;
--muted:#777;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
background:var(--bg);
color:var(--text);
}
#login{
height:100vh;
display:flex;
align-items:center;
justify-content:center;
background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);
}
.login-box{
width:400px;
background:#fff;
padding:40px;
border-radius:16px;
box-shadow:0 24px 48px rgba(0,0,0,.25);
}
.login-box h2{
text-align:center;
margin-bottom:8px;
color:#3f51b5;
}
.login-box .subtitle{
text-align:center;
color:#888;
margin-bottom:28px;
font-size:14px;
}
.login-box input{
width:100%;
padding:12px 16px;
margin-bottom:16px;
border:2px solid #e0e0e0;
border-radius:8px;
font-size:14px;
}
.login-box input:focus{
outline:none;
border-color:#3f51b5;
}
.login-btn{
width:100%;
padding:14px;
font-size:16px;
background:#3f51b5;
color:#fff;
border:none;
border-radius:8px;
cursor:pointer;
}
.login-btn:hover{
background:#303f9f;
}
#main{display:flex;height:100vh}
.sidebar{
width:260px;
background:linear-gradient(180deg,#3949ab,#1a237e);
color:#fff;
flex-shrink:0;
}
.sidebar h3{
padding:24px;
margin:0;
font-weight:500;
border-bottom:1px solid rgba(255,255,255,.15);
font-size:18px;
}
.sidebar ul{list-style:none;padding:0;margin:0}
.sidebar li{
padding:16px 24px;
cursor:pointer;
transition:background .2s;
}
.sidebar li.active,
.sidebar li:hover{
background:rgba(255,255,255,.15);
}
.content{
flex:1;
padding:28px;
overflow:auto;
background:#f8f9fc;
}
.card{
background:var(--card);
border-radius:14px;
padding:24px;
margin-bottom:24px;
box-shadow:0 4px 20px rgba(0,0,0,.06);
}
.card h3{margin:0 0 20px 0;color:#333}
.hidden{display:none}
.stats{
display:grid;
grid-template-columns:repeat(4,1fr);
gap:20px;
margin-bottom:24px;
}
.stat-card{
background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);
color:#fff;
padding:24px;
border-radius:14px;
box-shadow:0 8px 24px rgba(102,126,234,.3);
}
.stat-card:nth-child(2){background:linear-gradient(135deg,#f093fb 0%,#f5576c 100%)}
.stat-card:nth-child(3){background:linear-gradient(135deg,#4facfe 0%,#00f2fe 100%)}
.stat-card:nth-child(4){background:linear-gradient(135deg,#43e97b 0%,#38f9d7 100%)}
.stat-card .number{font-size:32px;font-weight:700}
.stat-card .label{opacity:.9;margin-top:6px}
.toolbar{
display:flex;
gap:12px;
margin-bottom:20px;
flex-wrap:wrap;
align-items:center;
}
.toolbar input,.toolbar select{
padding:10px 14px;
border:1px solid #ddd;
border-radius:8px;
font-size:14px;
}
.btn{
padding:10px 20px;
border:none;
border-radius:8px;
cursor:pointer;
font-size:14px;
transition:all .2s;
}
.btn-primary{background:#3f51b5;color:#fff}
.btn-primary:hover{background:#303f9f}
.btn-success{background:#4caf50;color:#fff}
.btn-warning{background:#ff9800;color:#fff}
.btn-danger{background:#f44336;color:#fff}
.btn-sm{padding:6px 12px;font-size:12px}
table{
width:100%;
border-collapse:collapse;
}
th,td{
padding:14px 12px;
border-bottom:1px solid #eee;
text-align:left;
}
th{
background:#f8f9fc;
font-weight:600;
color:#555;
font-size:13px;
}
tr:hover{background:#fafbff}
.status{
display:inline-block;
padding:4px 12px;
border-radius:20px;
font-size:12px;
font-weight:500;
}
.status-free{background:#e8f5e9;color:#2e7d32}
.status-booked{background:#fff3e0;color:#ef6c00}
.status-checkin{background:#e3f2fd;color:#1565c0}
.status-cleaning{background:#fce4ec;color:#c2185b}
.status-checkout{background:#f3e5f5;color:#7b1fa2}
.tag{
display:inline-block;
padding:3px 10px;
border-radius:12px;
font-size:12px;
background:#e8eaf6;
color:#303f9f;
margin:2px 4px 2px 0;
}
.mono{font-family:Consolas,monospace;font-size:13px;color:#555}
.muted{color:var(--muted)}
.text-success{color:#4caf50}
.text-warning{color:#ff9800}
.text-danger{color:#f44336}
.actions{display:flex;gap:6px}
.modal{
position:fixed;
top:0;left:0;right:0;bottom:0;
background:rgba(0,0,0,.5);
display:flex;
align-items:center;
justify-content:center;
z-index:1000;
}
.modal-content{
background:#fff;
padding:32px;
border-radius:16px;
width:500px;
max-width:90%;
}
.modal-content h3{margin:0 0 24px 0}
.form-group{margin-bottom:18px}
.form-group label{display:block;margin-bottom:6px;font-weight:500;color:#555}
.form-group input,.form-group select{
width:100%;
padding:10px 14px;
border:2px solid #e0e0e0;
border-radius:8px;
font-size:14px;
}
.form-actions{
display:flex;
gap:12px;
justify-content:flex-end;
margin-top:24px;
}
.report-grid{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:20px;
margin-bottom:24px;
}
.report-card{
padding:24px;
color:#fff;
border-radius:14px;
}
.report-card .number{font-size:28px;font-weight:700}
.report-card .label{opacity:.9;margin-top:4px}
.report-card .trend{font-size:12px;margin-top:8px;opacity:.8}
.chart-bar{
display:flex;
align-items:center;
margin-bottom:12px;
}
.chart-bar-label{width:80px;font-size:13px}
.chart-bar-track{flex:1;height:24px;background:#e0e0e0;border-radius:12px;overflow:hidden}
.chart-bar-fill{height:100%;border-radius:12px;display:flex;align-items:center;justify-content:flex-end;padding-right:8px;color:#fff;font-size:12px;font-weight:500}
.summary-table{margin-top:20px}
.summary-table td{padding:12px 16px}
.summary-table tr:nth-child(odd){background:#f8f9fc}
</style>
</head>
<body>
<div id="login">
<div class="login-box">
<h2>🏨 宾馆信息管理系统</h2>
<p class="subtitle">Hotel Information Management System</p>
<input type="text" placeholder="用户名(任意输入)">
<input type="password" placeholder="密码(任意输入)">
<button class="login-btn" onclick="login()">登 录</button>
<p style="text-align:center;font-size:12px;color:#888;margin-top:18px">
提示:直接点击登录即可进入系统
</p>
</div>
</div>
<div id="main" class="hidden">
<div class="sidebar">
<h3>🏨 宾馆管理系统</h3>
<ul>
<li class="active" onclick="show('home',this)">📊 系统首页</li>
<li onclick="show('room',this)">🛏️ 房间管理</li>
<li onclick="show('customer',this)">👥 客户管理</li>
<li onclick="show('reserve',this)">📅 预定管理</li>
<li onclick="show('checkin',this)">✅ 入住记录</li>
<li onclick="show('report',this)">📈 统计报表</li>
<li onclick="logout()" style="margin-top:20px;border-top:1px solid rgba(255,255,255,.1);padding-top:20px">🚪 退出系统</li>
</ul>
</div>
<div class="content">
<!-- 首页 -->
<div id="home" class="module">
<div class="stats">
<div class="stat-card">
<div class="number" id="statRooms">16</div>
<div class="label">总房间数</div>
</div>
<div class="stat-card">
<div class="number" id="statCustomers">26</div>
<div class="label">注册客户</div>
</div>
<div class="stat-card">
<div class="number" id="statCheckin">4</div>
<div class="label">今日在住</div>
</div>
<div class="stat-card">
<div class="number" id="statIncome">¥86,752</div>
<div class="label">本月营收</div>
</div>
</div>
<div class="card">
<h3>📊 系统概览</h3>
<p>欢迎使用宾馆信息管理系统!当前系统运行正常,以下是今日运营概况。</p>
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:20px;margin-top:20px">
<div style="padding:20px;background:#f8f9fc;border-radius:12px">
<h4 style="margin:0 0 12px 0;color:#3f51b5">🛏️ 房间状态分布</h4>
<div id="roomStatusChart"></div>
</div>
<div style="padding:20px;background:#f8f9fc;border-radius:12px">
<h4 style="margin:0 0 12px 0;color:#3f51b5">📅 近期预定</h4>
<div id="recentOrders"></div>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:20px;margin-top:20px">
<div style="padding:20px;background:#f8f9fc;border-radius:12px">
<h4 style="margin:0 0 12px 0;color:#3f51b5">💰 今日收入</h4>
<div id="todayIncome"></div>
</div>
<div style="padding:20px;background:#f8f9fc;border-radius:12px">
<h4 style="margin:0 0 12px 0;color:#3f51b5">🔔 待办事项</h4>
<div id="todoList"></div>
</div>
</div>
</div>
</div>
<!-- 房间管理 -->
<div id="room" class="module hidden">
<div class="card">
<h3>🛏️ 房间管理</h3>
<div class="toolbar">
<input type="text" id="roomSearch" placeholder="搜索房间号/房型..." oninput="renderRooms()">
<select id="roomStatusFilter" onchange="renderRooms()">
<option value="">全部状态</option>
<option value="空闲">空闲</option>
<option value="已预定">已预定</option>
<option value="已入住">已入住</option>
<option value="清洁中">清洁中</option>
</select>
<button class="btn btn-primary" onclick="openRoomModal()">+ 添加房间</button>
</div>
<table>
<thead>
<tr>
<th>房间号</th>
<th>房型</th>
<th>楼层</th>
<th>朝向</th>
<th>面积</th>
<th>价格/晚</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="roomList"></tbody>
</table>
</div>
</div>
<!-- 客户管理 -->
<div id="customer" class="module hidden">
<div class="card">
<h3>👥 客户档案管理</h3>
<div class="toolbar">
<input type="text" id="customerSearch" placeholder="搜索姓名/手机号..." oninput="renderCustomers()">
<select id="customerVipFilter" onchange="renderCustomers()">
<option value="">全部会员</option>
<option value="普通会员">普通会员</option>
<option value="银卡会员">银卡会员</option>
<option value="金卡会员">金卡会员</option>
<option value="钻石会员">钻石会员</option>
</select>
<button class="btn btn-primary" onclick="openCustomerModal()">+ 新增客户</button>
</div>
<table>
<thead>
<tr>
<th>姓名</th>
<th>性别</th>
<th>联系电话</th>
<th>身份证号</th>
<th>会员等级</th>
<th>累计消费</th>
<th>偏好标签</th>
<th>操作</th>
</tr>
</thead>
<tbody id="customerList"></tbody>
</table>
</div>
</div>
<!-- 预定管理 -->
<div id="reserve" class="module hidden">
<div class="card">
<h3>📅 预定管理</h3>
<div class="toolbar">
<input type="text" id="orderSearch" placeholder="搜索客户/房间..." oninput="renderOrders()">
<select id="orderStatusFilter" onchange="renderOrders()">
<option value="">全部状态</option>
<option value="待确认">待确认</option>
<option value="已确认">已确认</option>
<option value="已入住">已入住</option>
<option value="已退房">已退房</option>
<option value="已取消">已取消</option>
</select>
<button class="btn btn-primary" onclick="openOrderModal()">+ 新增预定</button>
</div>
<table>
<thead>
<tr>
<th>预定单号</th>
<th>客户姓名</th>
<th>房间号</th>
<th>房型</th>
<th>入住日期</th>
<th>离店日期</th>
<th>天数</th>
<th>总价</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody id="orderList"></tbody>
</table>
</div>
</div>
<!-- 入住记录 -->
<div id="checkin" class="module hidden">
<div class="stats">
<div class="stat-card">
<div class="number" id="checkinTotal">35</div>
<div class="label">本月入住次数</div>
</div>
<div class="stat-card">
<div class="number" id="checkoutTotal">31</div>
<div class="label">本月退房次数</div>
</div>
<div class="stat-card">
<div class="number" id="avgStay">2.3</div>
<div class="label">平均入住天数</div>
</div>
<div class="stat-card">
<div class="number" id="totalRevenue">¥86,752</div>
<div class="label">本月总收入</div>
</div>
</div>
<div class="card">
<h3>✅ 入住/退房记录</h3>
<div class="toolbar">
<input type="text" id="checkinSearch" placeholder="搜索客户/房间..." oninput="renderCheckins()">
<select id="checkinStatusFilter" onchange="renderCheckins()">
<option value="">全部状态</option>
<option value="在住">在住</option>
<option value="已退房">已退房</option>
</select>
<select id="checkinMonthFilter" onchange="renderCheckins()">
<option value="">全部月份</option>
<option value="2024-01">2024年1月</option>
<option value="2023-12">2023年12月</option>
<option value="2023-11">2023年11月</option>
</select>
<button class="btn btn-success" onclick="exportCheckins()">📥 导出记录</button>
</div>
<table>
<thead>
<tr>
<th>记录编号</th>
<th>客户姓名</th>
<th>联系电话</th>
<th>房间号</th>
<th>房型</th>
<th>入住时间</th>
<th>退房时间</th>
<th>天数</th>
<th>实付金额</th>
<th>支付方式</th>
<th>状态</th>
<th>备注</th>
</tr>
</thead>
<tbody id="checkinList"></tbody>
</table>
</div>
</div>
<!-- 统计报表 -->
<div id="report" class="module hidden">
<div class="report-grid">
<div class="report-card" style="background:linear-gradient(135deg,#667eea,#764ba2)">
<div class="number" id="reportOccupancy">68.5%</div>
<div class="label">本月入住率</div>
<div class="trend">↑ 较上月提升 5.2%</div>
</div>
<div class="report-card" style="background:linear-gradient(135deg,#f093fb,#f5576c)">
<div class="number" id="reportAvgPrice">¥486</div>
<div class="label">平均房价</div>
<div class="trend">↑ 较上月提升 ¥28</div>
</div>
<div class="report-card" style="background:linear-gradient(135deg,#4facfe,#00f2fe)">
<div class="number" id="reportRevenue">¥86,752</div>
<div class="label">本月总营收</div>
<div class="trend">↑ 较上月增长 12.8%</div>
</div>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:24px">
<div class="card">
<h3>📊 各房型入住率</h3>
<div id="roomTypeChart"></div>
</div>
<div class="card">
<h3>💳 支付方式分布</h3>
<div id="paymentChart"></div>
</div>
</div>
<div class="card">
<h3>📈 月度营收趋势</h3>
<div id="monthlyChart"></div>
</div>
<div class="card">
<h3>📋 各房型详细统计</h3>
<table>
<thead>
<tr>
<th>房型</th>
<th>房间数</th>
<th>本月入住次数</th>
<th>总入住天数</th>
<th>营收</th>
<th>入住率</th>
<th>平均房价</th>
</tr>
</thead>
<tbody id="reportList"></tbody>
</table>
</div>
<div class="card">
<h3>🏆 客户消费排行榜本月TOP10</h3>
<table>
<thead>
<tr>
<th>排名</th>
<th>客户姓名</th>
<th>会员等级</th>
<th>入住次数</th>
<th>入住天数</th>
<th>本月消费</th>
</tr>
</thead>
<tbody id="customerRankList"></tbody>
</table>
</div>
</div>
</div>
</div>
<div id="modalContainer"></div>
<script>
// ==================== 数据定义 ====================
var rooms = [
{ id: "R001", roomNo: "3101", type: "经济单人间", floor: 3, direction: "北", area: 18, price: 168, status: "空闲" },
{ id: "R002", roomNo: "3102", type: "经济单人间", floor: 3, direction: "北", area: 18, price: 168, status: "已入住" },
{ id: "R003", roomNo: "3103", type: "标准单人间", floor: 3, direction: "南", area: 22, price: 218, status: "空闲" },
{ id: "R004", roomNo: "3105", type: "标准双人间", floor: 3, direction: "南", area: 28, price: 288, status: "已预定" },
{ id: "R005", roomNo: "5201", type: "标准双人间", floor: 5, direction: "东", area: 28, price: 298, status: "空闲" },
{ id: "R006", roomNo: "5202", type: "标准双人间", floor: 5, direction: "南", area: 28, price: 308, status: "已入住" },
{ id: "R007", roomNo: "5203", type: "豪华双人间", floor: 5, direction: "南", area: 35, price: 388, status: "清洁中" },
{ id: "R008", roomNo: "5205", type: "豪华双人间", floor: 5, direction: "东", area: 35, price: 398, status: "空闲" },
{ id: "R009", roomNo: "6301", type: "商务大床房", floor: 6, direction: "南", area: 38, price: 458, status: "已入住" },
{ id: "R010", roomNo: "6302", type: "商务大床房", floor: 6, direction: "南", area: 38, price: 458, status: "空闲" },
{ id: "R011", roomNo: "6303", type: "家庭亲子房", floor: 6, direction: "东", area: 45, price: 528, status: "已预定" },
{ id: "R012", roomNo: "6305", type: "家庭亲子房", floor: 6, direction: "南", area: 45, price: 538, status: "空闲" },
{ id: "R013", roomNo: "8801", type: "豪华套房", floor: 8, direction: "南", area: 65, price: 888, status: "空闲" },
{ id: "R014", roomNo: "8802", type: "豪华套房", floor: 8, direction: "东", area: 65, price: 888, status: "已入住" },
{ id: "R015", roomNo: "10001", type: "总统套房", floor: 10, direction: "南", area: 120, price: 1888, status: "空闲" },
{ id: "R016", roomNo: "12001", type: "总统套房", floor: 12, direction: "南", area: 120, price: 2088, status: "已预定" }
];
var customers = [
{ id: "C001", name: "张伟", gender: "男", phone: "13812345678", idCard: "110101199503156789", vip: "金卡会员", totalSpent: 12680, tags: ["南向", "高楼层", "安静"] },
{ id: "C002", name: "王芳", gender: "女", phone: "13923456789", idCard: "310104199208234567", vip: "钻石会员", totalSpent: 35600, tags: ["套房", "江景", "无烟"] },
{ id: "C003", name: "李强", gender: "男", phone: "15834567890", idCard: "440106199012123456", vip: "银卡会员", totalSpent: 5680, tags: ["电梯房", "靠窗"] },
{ id: "C004", name: "刘洋", gender: "男", phone: "13745678901", idCard: "320102198811056789", vip: "普通会员", totalSpent: 1280, tags: ["经济型"] },
{ id: "C005", name: "陈静", gender: "女", phone: "18656789012", idCard: "330106199306189012", vip: "金卡会员", totalSpent: 18900, tags: ["大床房", "浴缸"] },
{ id: "C006", name: "杨光", gender: "男", phone: "13567890123", idCard: "420102199107223456", vip: "普通会员", totalSpent: 856, tags: ["安静"] },
{ id: "C007", name: "赵雪", gender: "女", phone: "15878901234", idCard: "510104199505124567", vip: "银卡会员", totalSpent: 6800, tags: ["南向", "早餐"] },
{ id: "C008", name: "黄海", gender: "男", phone: "13789012345", idCard: "610103198908087890", vip: "钻石会员", totalSpent: 52800, tags: ["套房", "行政楼层"] },
{ id: "C009", name: "周婷", gender: "女", phone: "18890123456", idCard: "210102199204156789", vip: "金卡会员", totalSpent: 15600, tags: ["亲子房", "加床"] },
{ id: "C010", name: "吴明", gender: "男", phone: "13501234567", idCard: "120101199609234567", vip: "普通会员", totalSpent: 680, tags: ["靠近电梯"] },
{ id: "C011", name: "徐丽", gender: "女", phone: "15612345678", idCard: "370102199311123890", vip: "银卡会员", totalSpent: 8900, tags: ["无烟房", "南向"] },
{ id: "C012", name: "孙鹏", gender: "男", phone: "13823456789", idCard: "430102198712056123", vip: "金卡会员", totalSpent: 22800, tags: ["商务房", "办公桌"] },
{ id: "C013", name: "马云飞", gender: "男", phone: "18934567890", idCard: "340102199008189234", vip: "普通会员", totalSpent: 1560, tags: ["经济型", "安静"] },
{ id: "C014", name: "朱红", gender: "女", phone: "13645678901", idCard: "350102199406223456", vip: "银卡会员", totalSpent: 7200, tags: ["双床房"] },
{ id: "C015", name: "胡建国", gender: "男", phone: "15756789012", idCard: "410102197503124567", vip: "钻石会员", totalSpent: 68900, tags: ["总统套房", "接机"] },
{ id: "C016", name: "林小燕", gender: "女", phone: "13867890123", idCard: "450102199207056789", vip: "金卡会员", totalSpent: 16800, tags: ["靠窗", "高楼层"] },
{ id: "C017", name: "郭志远", gender: "男", phone: "18978901234", idCard: "500102199109187890", vip: "普通会员", totalSpent: 960, tags: ["临时住宿"] },
{ id: "C018", name: "何晓峰", gender: "男", phone: "13089012345", idCard: "530102198806123901", vip: "银卡会员", totalSpent: 5200, tags: ["安静", "南向"] },
{ id: "C019", name: "高圆圆", gender: "女", phone: "15190123456", idCard: "620102199404056234", vip: "金卡会员", totalSpent: 19800, tags: ["豪华房", "浴缸"] },
{ id: "C020", name: "郑成功", gender: "男", phone: "13201234567", idCard: "230102198211189567", vip: "钻石会员", totalSpent: 45600, tags: ["行政套房", "会议室"] },
{ id: "C021", name: "梁思思", gender: "女", phone: "18312345678", idCard: "360102199603223890", vip: "普通会员", totalSpent: 728, tags: ["标准间"] },
{ id: "C022", name: "谢天华", gender: "男", phone: "15423456789", idCard: "640102199001124123", vip: "银卡会员", totalSpent: 6100, tags: ["电梯房"] },
{ id: "C023", name: "宋佳", gender: "女", phone: "13534567890", idCard: "650102199708056456", vip: "普通会员", totalSpent: 580, tags: ["经济型"] },
{ id: "C024", name: "唐俊杰", gender: "男", phone: "18645678901", idCard: "140102198504187789", vip: "金卡会员", totalSpent: 21600, tags: ["商务房", "快速退房"] },
{ id: "C025", name: "许文强", gender: "男", phone: "13756789012", idCard: "150102197908124012", vip: "钻石会员", totalSpent: 88900, tags: ["贵宾服务", "专属管家"] },
{ id: "C026", name: "冯晓琳", gender: "女", phone: "15867890123", idCard: "220102199210053345", vip: "银卡会员", totalSpent: 7800, tags: ["亲子房", "加床"] }
];
var orders = [
{ id: "ORD20240115001", customerName: "张伟", roomNo: "3102", roomType: "经济单人间", checkIn: "2024-01-15", checkOut: "2024-01-17", days: 2, price: 336, status: "已入住" },
{ id: "ORD20240115002", customerName: "王芳", roomNo: "8802", roomType: "豪华套房", checkIn: "2024-01-14", checkOut: "2024-01-18", days: 4, price: 3552, status: "已入住" },
{ id: "ORD20240116001", customerName: "陈静", roomNo: "6301", roomType: "商务大床房", checkIn: "2024-01-16", checkOut: "2024-01-19", days: 3, price: 1374, status: "已入住" },
{ id: "ORD20240116002", customerName: "黄海", roomNo: "5202", roomType: "标准双人间", checkIn: "2024-01-16", checkOut: "2024-01-17", days: 1, price: 308, status: "已入住" },
{ id: "ORD20240117001", customerName: "李强", roomNo: "3105", roomType: "标准双人间", checkIn: "2024-01-18", checkOut: "2024-01-20", days: 2, price: 576, status: "已确认" },
{ id: "ORD20240117002", customerName: "徐丽", roomNo: "6303", roomType: "家庭亲子房", checkIn: "2024-01-19", checkOut: "2024-01-22", days: 3, price: 1584, status: "已确认" },
{ id: "ORD20240117003", customerName: "胡建国", roomNo: "12001", roomType: "总统套房", checkIn: "2024-01-20", checkOut: "2024-01-25", days: 5, price: 10440, status: "已确认" },
{ id: "ORD20240117004", customerName: "郑成功", roomNo: "8801", roomType: "豪华套房", checkIn: "2024-01-18", checkOut: "2024-01-21", days: 3, price: 2664, status: "待确认" },
{ id: "ORD20240117005", customerName: "周婷", roomNo: "6305", roomType: "家庭亲子房", checkIn: "2024-01-19", checkOut: "2024-01-21", days: 2, price: 1076, status: "待确认" },
{ id: "ORD20240110001", customerName: "刘洋", roomNo: "3101", roomType: "经济单人间", checkIn: "2024-01-10", checkOut: "2024-01-12", days: 2, price: 336, status: "已退房" },
{ id: "ORD20240108001", customerName: "赵雪", roomNo: "5201", roomType: "标准双人间", checkIn: "2024-01-08", checkOut: "2024-01-10", days: 2, price: 596, status: "已退房" },
{ id: "ORD20240105001", customerName: "孙鹏", roomNo: "6302", roomType: "商务大床房", checkIn: "2024-01-05", checkOut: "2024-01-08", days: 3, price: 1374, status: "已退房" },
{ id: "ORD20240103001", customerName: "高圆圆", roomNo: "5203", roomType: "豪华双人间", checkIn: "2024-01-03", checkOut: "2024-01-06", days: 3, price: 1164, status: "已退房" },
{ id: "ORD20240102001", customerName: "许文强", roomNo: "10001", roomType: "总统套房", checkIn: "2024-01-02", checkOut: "2024-01-05", days: 3, price: 5664, status: "已退房" },
{ id: "ORD20240101001", customerName: "林小燕", roomNo: "5205", roomType: "豪华双人间", checkIn: "2024-01-01", checkOut: "2024-01-03", days: 2, price: 796, status: "已退房" },
{ id: "ORD20240115003", customerName: "杨光", roomNo: "3103", roomType: "标准单人间", checkIn: "2024-01-15", checkOut: "2024-01-16", days: 1, price: 218, status: "已取消" }
];
// 扩展的入住记录数据
var checkins = [
// 2024年1月 - 在住
{ id: "CHK20240116004", customerName: "张伟", phone: "13812345678", roomNo: "3102", roomType: "经济单人间", checkInTime: "2024-01-15 15:23", checkOutTime: "-", days: 2, amount: 336, payMethod: "待结算", status: "在住", remark: "金卡会员,赠送早餐" },
{ id: "CHK20240116003", customerName: "王芳", phone: "13923456789", roomNo: "8802", roomType: "豪华套房", checkInTime: "2024-01-14 14:05", checkOutTime: "-", days: 4, amount: 3552, payMethod: "待结算", status: "在住", remark: "钻石会员,升级房型" },
{ id: "CHK20240116002", customerName: "陈静", phone: "18656789012", roomNo: "6301", roomType: "商务大床房", checkInTime: "2024-01-16 16:42", checkOutTime: "-", days: 3, amount: 1374, payMethod: "待结算", status: "在住", remark: "需要发票" },
{ id: "CHK20240116001", customerName: "黄海", phone: "13789012345", roomNo: "5202", roomType: "标准双人间", checkInTime: "2024-01-16 20:15", checkOutTime: "-", days: 1, amount: 308, payMethod: "待结算", status: "在住", remark: "商务出差" },
// 2024年1月 - 已退房
{ id: "CHK20240114001", customerName: "唐俊杰", phone: "18645678901", roomNo: "6302", roomType: "商务大床房", checkInTime: "2024-01-12 14:30", checkOutTime: "2024-01-14 11:20", days: 2, amount: 916, payMethod: "信用卡", status: "已退房", remark: "公司报销" },
{ id: "CHK20240113001", customerName: "马云飞", phone: "18934567890", roomNo: "3101", roomType: "经济单人间", checkInTime: "2024-01-11 18:45", checkOutTime: "2024-01-13 10:30", days: 2, amount: 336, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20240112001", customerName: "刘洋", phone: "13745678901", roomNo: "3101", roomType: "经济单人间", checkInTime: "2024-01-10 14:32", checkOutTime: "2024-01-12 11:05", days: 2, amount: 336, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20240111001", customerName: "朱红", phone: "13645678901", roomNo: "5201", roomType: "标准双人间", checkInTime: "2024-01-09 15:20", checkOutTime: "2024-01-11 10:45", days: 2, amount: 596, payMethod: "支付宝", status: "已退房", remark: "正常退房" },
{ id: "CHK20240110001", customerName: "赵雪", phone: "15878901234", roomNo: "5201", roomType: "标准双人间", checkInTime: "2024-01-08 15:20", checkOutTime: "2024-01-10 10:30", days: 2, amount: 596, payMethod: "支付宝", status: "已退房", remark: "正常退房" },
{ id: "CHK20240109001", customerName: "谢天华", phone: "15423456789", roomNo: "3103", roomType: "标准单人间", checkInTime: "2024-01-07 16:00", checkOutTime: "2024-01-09 09:30", days: 2, amount: 436, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20240108001", customerName: "孙鹏", phone: "13823456789", roomNo: "6302", roomType: "商务大床房", checkInTime: "2024-01-05 16:45", checkOutTime: "2024-01-08 12:00", days: 3, amount: 1374, payMethod: "信用卡", status: "已退房", remark: "公司报销" },
{ id: "CHK20240107001", customerName: "冯晓琳", phone: "15867890123", roomNo: "6303", roomType: "家庭亲子房", checkInTime: "2024-01-04 14:20", checkOutTime: "2024-01-07 11:00", days: 3, amount: 1584, payMethod: "支付宝", status: "已退房", remark: "带小孩入住" },
{ id: "CHK20240106001", customerName: "高圆圆", phone: "15190123456", roomNo: "5203", roomType: "豪华双人间", checkInTime: "2024-01-03 14:00", checkOutTime: "2024-01-06 11:20", days: 3, amount: 1164, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20240105001", customerName: "许文强", phone: "13756789012", roomNo: "10001", roomType: "总统套房", checkInTime: "2024-01-02 12:00", checkOutTime: "2024-01-05 14:00", days: 3, amount: 5664, payMethod: "现金", status: "已退房", remark: "VIP客户延迟退房" },
{ id: "CHK20240104001", customerName: "何晓峰", phone: "13089012345", roomNo: "5205", roomType: "豪华双人间", checkInTime: "2024-01-02 15:30", checkOutTime: "2024-01-04 10:15", days: 2, amount: 796, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20240103001", customerName: "林小燕", phone: "13867890123", roomNo: "5205", roomType: "豪华双人间", checkInTime: "2024-01-01 18:30", checkOutTime: "2024-01-03 10:00", days: 2, amount: 796, payMethod: "支付宝", status: "已退房", remark: "新年入住" },
{ id: "CHK20240103002", customerName: "郑成功", phone: "13201234567", roomNo: "8801", roomType: "豪华套房", checkInTime: "2024-01-01 14:00", checkOutTime: "2024-01-03 12:00", days: 2, amount: 1776, payMethod: "信用卡", status: "已退房", remark: "商务会议" },
// 2023年12月
{ id: "CHK20231231001", customerName: "周婷", phone: "18890123456", roomNo: "6305", roomType: "家庭亲子房", checkInTime: "2023-12-29 14:00", checkOutTime: "2023-12-31 11:00", days: 2, amount: 1076, payMethod: "支付宝", status: "已退房", remark: "跨年入住" },
{ id: "CHK20231230001", customerName: "吴明", phone: "13501234567", roomNo: "3101", roomType: "经济单人间", checkInTime: "2023-12-28 16:30", checkOutTime: "2023-12-30 10:00", days: 2, amount: 336, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20231229001", customerName: "李强", phone: "15834567890", roomNo: "5201", roomType: "标准双人间", checkInTime: "2023-12-26 15:00", checkOutTime: "2023-12-29 11:30", days: 3, amount: 894, payMethod: "支付宝", status: "已退房", remark: "正常退房" },
{ id: "CHK20231228001", customerName: "徐丽", phone: "15612345678", roomNo: "3103", roomType: "标准单人间", checkInTime: "2023-12-25 14:20", checkOutTime: "2023-12-28 10:45", days: 3, amount: 654, payMethod: "微信支付", status: "已退房", remark: "圣诞入住" },
{ id: "CHK20231227001", customerName: "胡建国", phone: "15756789012", roomNo: "12001", roomType: "总统套房", checkInTime: "2023-12-22 10:00", checkOutTime: "2023-12-27 14:00", days: 5, amount: 10440, payMethod: "银行转账", status: "已退房", remark: "VIP客户接机送机" },
{ id: "CHK20231225001", customerName: "张伟", phone: "13812345678", roomNo: "3102", roomType: "经济单人间", checkInTime: "2023-12-23 15:30", checkOutTime: "2023-12-25 11:00", days: 2, amount: 336, payMethod: "会员积分", status: "已退房", remark: "积分兑换" },
{ id: "CHK20231224001", customerName: "王芳", phone: "13923456789", roomNo: "8802", roomType: "豪华套房", checkInTime: "2023-12-20 14:00", checkOutTime: "2023-12-24 12:00", days: 4, amount: 3552, payMethod: "信用卡", status: "已退房", remark: "圣诞假期" },
{ id: "CHK20231222001", customerName: "陈静", phone: "18656789012", roomNo: "6301", roomType: "商务大床房", checkInTime: "2023-12-19 16:00", checkOutTime: "2023-12-22 11:30", days: 3, amount: 1374, payMethod: "微信支付", status: "已退房", remark: "商务出差" },
{ id: "CHK20231220001", customerName: "黄海", phone: "13789012345", roomNo: "8801", roomType: "豪华套房", checkInTime: "2023-12-17 14:30", checkOutTime: "2023-12-20 10:00", days: 3, amount: 2664, payMethod: "信用卡", status: "已退房", remark: "公司年会" },
{ id: "CHK20231218001", customerName: "杨光", phone: "13567890123", roomNo: "3101", roomType: "经济单人间", checkInTime: "2023-12-16 18:00", checkOutTime: "2023-12-18 09:30", days: 2, amount: 336, payMethod: "现金", status: "已退房", remark: "正常退房" },
{ id: "CHK20231215001", customerName: "宋佳", phone: "13534567890", roomNo: "3103", roomType: "标准单人间", checkInTime: "2023-12-13 15:45", checkOutTime: "2023-12-15 10:20", days: 2, amount: 436, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20231212001", customerName: "梁思思", phone: "18312345678", roomNo: "5202", roomType: "标准双人间", checkInTime: "2023-12-10 14:00", checkOutTime: "2023-12-12 11:00", days: 2, amount: 616, payMethod: "支付宝", status: "已退房", remark: "正常退房" },
{ id: "CHK20231210001", customerName: "郭志远", phone: "18978901234", roomNo: "3101", roomType: "经济单人间", checkInTime: "2023-12-08 17:30", checkOutTime: "2023-12-10 10:00", days: 2, amount: 336, payMethod: "微信支付", status: "已退房", remark: "临时住宿" },
// 2023年11月
{ id: "CHK20231130001", customerName: "许文强", phone: "13756789012", roomNo: "10001", roomType: "总统套房", checkInTime: "2023-11-26 11:00", checkOutTime: "2023-11-30 15:00", days: 4, amount: 7552, payMethod: "银行转账", status: "已退房", remark: "VIP客户" },
{ id: "CHK20231128001", customerName: "孙鹏", phone: "13823456789", roomNo: "6302", roomType: "商务大床房", checkInTime: "2023-11-25 14:30", checkOutTime: "2023-11-28 11:00", days: 3, amount: 1374, payMethod: "信用卡", status: "已退房", remark: "商务出差" },
{ id: "CHK20231125001", customerName: "高圆圆", phone: "15190123456", roomNo: "5203", roomType: "豪华双人间", checkInTime: "2023-11-22 15:00", checkOutTime: "2023-11-25 10:30", days: 3, amount: 1164, payMethod: "微信支付", status: "已退房", remark: "正常退房" },
{ id: "CHK20231122001", customerName: "唐俊杰", phone: "18645678901", roomNo: "6301", roomType: "商务大床房", checkInTime: "2023-11-19 16:20", checkOutTime: "2023-11-22 12:00", days: 3, amount: 1374, payMethod: "信用卡", status: "已退房", remark: "公司报销" },
{ id: "CHK20231120001", customerName: "周婷", phone: "18890123456", roomNo: "6303", roomType: "家庭亲子房", checkInTime: "2023-11-17 14:00", checkOutTime: "2023-11-20 11:00", days: 3, amount: 1584, payMethod: "支付宝", status: "已退房", remark: "周末家庭游" }
];
var roomTypes = [
{ name: "经济单人间", basePrice: 168 },
{ name: "标准单人间", basePrice: 218 },
{ name: "标准双人间", basePrice: 288 },
{ name: "豪华双人间", basePrice: 388 },
{ name: "商务大床房", basePrice: 458 },
{ name: "家庭亲子房", basePrice: 528 },
{ name: "豪华套房", basePrice: 888 },
{ name: "总统套房", basePrice: 1888 }
];
// 月度营收数据
var monthlyRevenue = [
{ month: "2023-07", revenue: 52680, orders: 28 },
{ month: "2023-08", revenue: 68450, orders: 35 },
{ month: "2023-09", revenue: 58920, orders: 31 },
{ month: "2023-10", revenue: 72350, orders: 38 },
{ month: "2023-11", revenue: 65800, orders: 33 },
{ month: "2023-12", revenue: 76920, orders: 42 },
{ month: "2024-01", revenue: 86752, orders: 35 }
];
// 客户消费排行
var customerRanking = [
{ name: "许文强", vip: "钻石会员", times: 3, days: 10, spent: 18880 },
{ name: "胡建国", vip: "钻石会员", times: 2, days: 10, spent: 20880 },
{ name: "王芳", vip: "钻石会员", times: 2, days: 8, spent: 7104 },
{ name: "黄海", vip: "钻石会员", times: 2, days: 4, spent: 2972 },
{ name: "孙鹏", vip: "金卡会员", times: 3, days: 9, spent: 4122 },
{ name: "陈静", vip: "金卡会员", times: 2, days: 6, spent: 2748 },
{ name: "唐俊杰", vip: "金卡会员", times: 2, days: 5, spent: 2290 },
{ name: "郑成功", vip: "钻石会员", times: 1, days: 2, spent: 1776 },
{ name: "周婷", vip: "金卡会员", times: 2, days: 5, spent: 2660 },
{ name: "高圆圆", vip: "金卡会员", times: 2, days: 6, spent: 2328 }
];
// ==================== 登录和导航 ====================
function login() {
document.getElementById("login").classList.add("hidden");
document.getElementById("main").classList.remove("hidden");
render();
}
function logout() {
if(confirm("确定要退出系统吗?")) {
location.reload();
}
}
function show(id, el) {
var modules = document.querySelectorAll(".module");
for(var i = 0; i < modules.length; i++) {
modules[i].classList.add("hidden");
}
document.getElementById(id).classList.remove("hidden");
var items = document.querySelectorAll(".sidebar li");
for(var j = 0; j < items.length; j++) {
items[j].classList.remove("active");
}
el.classList.add("active");
}
// ==================== 渲染函数 ====================
function render() {
renderRooms();
renderCustomers();
renderOrders();
renderCheckins();
renderReport();
renderHomeCharts();
}
function renderHomeCharts() {
var freeCount = 0, bookedCount = 0, checkinCount = 0, cleaningCount = 0;
for(var i = 0; i < rooms.length; i++) {
if(rooms[i].status === "空闲") freeCount++;
else if(rooms[i].status === "已预定") bookedCount++;
else if(rooms[i].status === "已入住") checkinCount++;
else if(rooms[i].status === "清洁中") cleaningCount++;
}
document.getElementById("roomStatusChart").innerHTML =
'<div style="display:flex;gap:30px">' +
'<div style="text-align:center"><div style="font-size:28px;font-weight:700;color:#4caf50">' + freeCount + '</div><div style="font-size:12px;color:#666">空闲</div></div>' +
'<div style="text-align:center"><div style="font-size:28px;font-weight:700;color:#ff9800">' + bookedCount + '</div><div style="font-size:12px;color:#666">已预定</div></div>' +
'<div style="text-align:center"><div style="font-size:28px;font-weight:700;color:#2196f3">' + checkinCount + '</div><div style="font-size:12px;color:#666">已入住</div></div>' +
'<div style="text-align:center"><div style="font-size:28px;font-weight:700;color:#e91e63">' + cleaningCount + '</div><div style="font-size:12px;color:#666">清洁中</div></div>' +
'</div>';
var recentHtml = '';
var count = 0;
for(var j = 0; j < orders.length && count < 4; j++) {
if(orders[j].status === "待确认" || orders[j].status === "已确认") {
recentHtml += '<div style="display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid #eee">' +
'<span>' + orders[j].customerName + ' - ' + orders[j].roomNo + '</span>' +
'<span class="status status-booked">' + orders[j].status + '</span></div>';
count++;
}
}
document.getElementById("recentOrders").innerHTML = recentHtml || '<div style="color:#999">暂无近期预定</div>';
// 今日收入
document.getElementById("todayIncome").innerHTML =
'<div style="display:flex;justify-content:space-between;margin-bottom:12px">' +
'<span>今日入住收入</span><span style="color:#4caf50;font-weight:600">¥5,570</span></div>' +
'<div style="display:flex;justify-content:space-between;margin-bottom:12px">' +
'<span>今日退房结算</span><span style="color:#2196f3;font-weight:600">¥2,328</span></div>' +
'<div style="display:flex;justify-content:space-between;font-weight:600;border-top:1px solid #ddd;padding-top:12px">' +
'<span>今日总收入</span><span style="color:#ff9800">¥7,898</span></div>';
// 待办事项
document.getElementById("todoList").innerHTML =
'<div style="display:flex;align-items:center;padding:8px 0;border-bottom:1px solid #eee">' +
'<span style="background:#ff9800;color:#fff;padding:2px 8px;border-radius:10px;font-size:11px;margin-right:10px">待确认</span>' +
'<span>2条预定待确认</span></div>' +
'<div style="display:flex;align-items:center;padding:8px 0;border-bottom:1px solid #eee">' +
'<span style="background:#e91e63;color:#fff;padding:2px 8px;border-radius:10px;font-size:11px;margin-right:10px">清洁</span>' +
'<span>5203房间待清洁</span></div>' +
'<div style="display:flex;align-items:center;padding:8px 0">' +
'<span style="background:#2196f3;color:#fff;padding:2px 8px;border-radius:10px;font-size:11px;margin-right:10px">退房</span>' +
'<span>4间房间今日预计退房</span></div>';
}
function renderRooms() {
var search = document.getElementById("roomSearch") ? document.getElementById("roomSearch").value.toLowerCase() : "";
var statusFilter = document.getElementById("roomStatusFilter") ? document.getElementById("roomStatusFilter").value : "";
var html = '';
for(var i = 0; i < rooms.length; i++) {
var r = rooms[i];
var matchSearch = r.roomNo.toLowerCase().indexOf(search) >= 0 || r.type.toLowerCase().indexOf(search) >= 0;
var matchStatus = !statusFilter || r.status === statusFilter;
if(matchSearch && matchStatus) {
html += '<tr>' +
'<td><strong>' + r.roomNo + '</strong></td>' +
'<td>' + r.type + '</td>' +
'<td>' + r.floor + '楼</td>' +
'<td>' + r.direction + '向</td>' +
'<td>' + r.area + '㎡</td>' +
'<td style="color:#ff9800"><strong>¥' + r.price + '</strong></td>' +
'<td><span class="status status-' + getStatusClass(r.status) + '">' + r.status + '</span></td>' +
'<td class="actions">' +
'<button class="btn btn-primary btn-sm" onclick="editRoom(\'' + r.id + '\')">编辑</button> ' +
'<button class="btn btn-danger btn-sm" onclick="deleteRoom(\'' + r.id + '\')">删除</button>' +
'</td></tr>';
}
}
document.getElementById("roomList").innerHTML = html;
}
function renderCustomers() {
var search = document.getElementById("customerSearch") ? document.getElementById("customerSearch").value.toLowerCase() : "";
var vipFilter = document.getElementById("customerVipFilter") ? document.getElementById("customerVipFilter").value : "";
var html = '';
for(var i = 0; i < customers.length; i++) {
var c = customers[i];
var matchSearch = c.name.indexOf(search) >= 0 || c.phone.indexOf(search) >= 0;
var matchVip = !vipFilter || c.vip === vipFilter;
if(matchSearch && matchVip) {
var tagsHtml = '';
for(var j = 0; j < c.tags.length; j++) {
tagsHtml += '<span class="tag">' + c.tags[j] + '</span>';
}
html += '<tr>' +
'<td><strong>' + c.name + '</strong></td>' +
'<td>' + c.gender + '</td>' +
'<td class="mono">' + c.phone + '</td>' +
'<td class="mono">' + maskIdCard(c.idCard) + '</td>' +
'<td><span class="tag" style="background:' + getVipColor(c.vip) + ';color:#fff">' + c.vip + '</span></td>' +
'<td style="color:#4caf50"><strong>¥' + c.totalSpent.toLocaleString() + '</strong></td>' +
'<td>' + tagsHtml + '</td>' +
'<td class="actions">' +
'<button class="btn btn-primary btn-sm" onclick="editCustomer(\'' + c.id + '\')">编辑</button> ' +
'<button class="btn btn-danger btn-sm" onclick="deleteCustomer(\'' + c.id + '\')">删除</button>' +
'</td></tr>';
}
}
document.getElementById("customerList").innerHTML = html;
}
function renderOrders() {
var search = document.getElementById("orderSearch") ? document.getElementById("orderSearch").value.toLowerCase() : "";
var statusFilter = document.getElementById("orderStatusFilter") ? document.getElementById("orderStatusFilter").value : "";
var html = '';
for(var i = 0; i < orders.length; i++) {
var o = orders[i];
var matchSearch = o.customerName.indexOf(search) >= 0 || o.roomNo.indexOf(search) >= 0;
var matchStatus = !statusFilter || o.status === statusFilter;
if(matchSearch && matchStatus) {
var actionsHtml = '';
if(o.status === '待确认') actionsHtml += '<button class="btn btn-success btn-sm" onclick="confirmOrder(\'' + o.id + '\')">确认</button> ';
if(o.status === '已确认') actionsHtml += '<button class="btn btn-primary btn-sm" onclick="checkinOrder(\'' + o.id + '\')">入住</button> ';
if(o.status === '已入住') actionsHtml += '<button class="btn btn-warning btn-sm" onclick="checkoutOrder(\'' + o.id + '\')">退房</button> ';
if(o.status !== '已退房' && o.status !== '已取消') actionsHtml += '<button class="btn btn-danger btn-sm" onclick="cancelOrder(\'' + o.id + '\')">取消</button>';
html += '<tr>' +
'<td class="mono" style="font-size:12px">' + o.id + '</td>' +
'<td><strong>' + o.customerName + '</strong></td>' +
'<td>' + o.roomNo + '</td>' +
'<td>' + o.roomType + '</td>' +
'<td>' + o.checkIn + '</td>' +
'<td>' + o.checkOut + '</td>' +
'<td>' + o.days + '晚</td>' +
'<td style="color:#ff9800"><strong>¥' + o.price + '</strong></td>' +
'<td><span class="status status-' + getOrderStatusClass(o.status) + '">' + o.status + '</span></td>' +
'<td class="actions">' + actionsHtml + '</td></tr>';
}
}
document.getElementById("orderList").innerHTML = html;
}
function renderCheckins() {
var search = document.getElementById("checkinSearch") ? document.getElementById("checkinSearch").value.toLowerCase() : "";
var statusFilter = document.getElementById("checkinStatusFilter") ? document.getElementById("checkinStatusFilter").value : "";
var monthFilter = document.getElementById("checkinMonthFilter") ? document.getElementById("checkinMonthFilter").value : "";
var html = '';
var totalAmount = 0;
var inCount = 0;
var outCount = 0;
var totalDays = 0;
for(var i = 0; i < checkins.length; i++) {
var c = checkins[i];
var matchSearch = c.customerName.indexOf(search) >= 0 || c.roomNo.indexOf(search) >= 0;
var matchStatus = !statusFilter || c.status === statusFilter;
var matchMonth = !monthFilter || c.checkInTime.indexOf(monthFilter) >= 0;
// 统计数据
if(c.checkInTime.indexOf("2024-01") >= 0) {
if(c.status === "在住") inCount++;
else outCount++;
totalAmount += c.amount;
totalDays += c.days;
}
if(matchSearch && matchStatus && matchMonth) {
var statusClass = c.status === "在住" ? "checkin" : "checkout";
html += '<tr>' +
'<td class="mono" style="font-size:12px">' + c.id + '</td>' +
'<td><strong>' + c.customerName + '</strong></td>' +
'<td class="mono">' + c.phone + '</td>' +
'<td>' + c.roomNo + '</td>' +
'<td>' + c.roomType + '</td>' +
'<td class="mono">' + c.checkInTime + '</td>' +
'<td class="mono">' + c.checkOutTime + '</td>' +
'<td>' + c.days + '晚</td>' +
'<td style="color:#ff9800"><strong>¥' + c.amount.toLocaleString() + '</strong></td>' +
'<td>' + c.payMethod + '</td>' +
'<td><span class="status status-' + statusClass + '">' + c.status + '</span></td>' +
'<td class="muted">' + c.remark + '</td></tr>';
}
}
document.getElementById("checkinList").innerHTML = html;
// 更新统计
document.getElementById("checkinTotal").textContent = inCount + outCount;
document.getElementById("checkoutTotal").textContent = outCount;
document.getElementById("avgStay").textContent = (totalDays / (inCount + outCount)).toFixed(1);
document.getElementById("totalRevenue").textContent = "¥" + totalAmount.toLocaleString();
}
function renderReport() {
// 房型入住率图表
var roomTypeHtml = '';
var typeData = [
{ name: "经济单人间", rate: 72, color: "#4caf50" },
{ name: "标准单人间", rate: 65, color: "#2196f3" },
{ name: "标准双人间", rate: 78, color: "#ff9800" },
{ name: "豪华双人间", rate: 58, color: "#9c27b0" },
{ name: "商务大床房", rate: 82, color: "#f44336" },
{ name: "家庭亲子房", rate: 55, color: "#00bcd4" },
{ name: "豪华套房", rate: 45, color: "#795548" },
{ name: "总统套房", rate: 35, color: "#607d8b" }
];
for(var t = 0; t < typeData.length; t++) {
roomTypeHtml += '<div class="chart-bar">' +
'<div class="chart-bar-label">' + typeData[t].name.substring(0, 4) + '</div>' +
'<div class="chart-bar-track"><div class="chart-bar-fill" style="width:' + typeData[t].rate + '%;background:' + typeData[t].color + '">' + typeData[t].rate + '%</div></div>' +
'</div>';
}
document.getElementById("roomTypeChart").innerHTML = roomTypeHtml;
// 支付方式分布
var paymentData = [
{ name: "微信支付", percent: 42, color: "#4caf50" },
{ name: "支付宝", percent: 28, color: "#2196f3" },
{ name: "信用卡", percent: 18, color: "#ff9800" },
{ name: "现金", percent: 8, color: "#9c27b0" },
{ name: "其他", percent: 4, color: "#607d8b" }
];
var paymentHtml = '';
for(var p = 0; p < paymentData.length; p++) {
paymentHtml += '<div class="chart-bar">' +
'<div class="chart-bar-label">' + paymentData[p].name + '</div>' +
'<div class="chart-bar-track"><div class="chart-bar-fill" style="width:' + paymentData[p].percent + '%;background:' + paymentData[p].color + '">' + paymentData[p].percent + '%</div></div>' +
'</div>';
}
document.getElementById("paymentChart").innerHTML = paymentHtml;
// 月度营收趋势
var maxRevenue = 100000;
var monthlyHtml = '<div style="display:flex;align-items:flex-end;height:200px;gap:20px;padding:20px 0">';
for(var m = 0; m < monthlyRevenue.length; m++) {
var mr = monthlyRevenue[m];
var height = (mr.revenue / maxRevenue) * 160;
var isCurrentMonth = mr.month === "2024-01";
monthlyHtml += '<div style="flex:1;text-align:center">' +
'<div style="height:' + height + 'px;background:' + (isCurrentMonth ? 'linear-gradient(180deg,#667eea,#764ba2)' : '#e0e0e0') + ';border-radius:8px 8px 0 0;margin-bottom:8px;display:flex;align-items:flex-start;justify-content:center;padding-top:8px">' +
'<span style="color:' + (isCurrentMonth ? '#fff' : '#666') + ';font-size:11px;font-weight:600">¥' + (mr.revenue/10000).toFixed(1) + 'w</span></div>' +
'<div style="font-size:12px;color:#666">' + mr.month.substring(5) + '月</div>' +
'</div>';
}
monthlyHtml += '</div>';
document.getElementById("monthlyChart").innerHTML = monthlyHtml;
// 房型详细统计表格
var reportHtml = '';
var reportData = [
{ name: "经济单人间", count: 2, orders: 8, days: 16, revenue: 2688, rate: 72, avgPrice: 168 },
{ name: "标准单人间", count: 1, orders: 4, days: 9, revenue: 1962, rate: 65, avgPrice: 218 },
{ name: "标准双人间", count: 3, orders: 12, days: 26, revenue: 7748, rate: 78, avgPrice: 298 },
{ name: "豪华双人间", count: 2, orders: 6, days: 14, revenue: 5432, rate: 58, avgPrice: 388 },
{ name: "商务大床房", count: 2, orders: 8, days: 22, revenue: 10076, rate: 82, avgPrice: 458 },
{ name: "家庭亲子房", count: 2, orders: 5, days: 13, revenue: 6868, rate: 55, avgPrice: 528 },
{ name: "豪华套房", count: 2, orders: 4, days: 11, revenue: 9768, rate: 45, avgPrice: 888 },
{ name: "总统套房", count: 2, orders: 3, days: 12, revenue: 23656, rate: 35, avgPrice: 1972 }
];
for(var r = 0; r < reportData.length; r++) {
var rd = reportData[r];
reportHtml += '<tr>' +
'<td><strong>' + rd.name + '</strong></td>' +
'<td>' + rd.count + '间</td>' +
'<td>' + rd.orders + '次</td>' +
'<td>' + rd.days + '天</td>' +
'<td style="color:#ff9800"><strong>¥' + rd.revenue.toLocaleString() + '</strong></td>' +
'<td><div style="display:flex;align-items:center;gap:8px">' +
'<div style="background:#e0e0e0;border-radius:10px;height:8px;width:80px">' +
'<div style="background:#4caf50;border-radius:10px;height:8px;width:' + rd.rate + '%"></div>' +
'</div>' +
'<span>' + rd.rate + '%</span>' +
'</div></td>' +
'<td>¥' + rd.avgPrice + '</td></tr>';
}
document.getElementById("reportList").innerHTML = reportHtml;
// 客户消费排行
var rankHtml = '';
for(var k = 0; k < customerRanking.length; k++) {
var cr = customerRanking[k];
var rankBadge = '';
if(k === 0) rankBadge = '<span style="background:#ffd700;color:#fff;padding:2px 8px;border-radius:10px">🥇</span>';
else if(k === 1) rankBadge = '<span style="background:#c0c0c0;color:#fff;padding:2px 8px;border-radius:10px">🥈</span>';
else if(k === 2) rankBadge = '<span style="background:#cd7f32;color:#fff;padding:2px 8px;border-radius:10px">🥉</span>';
else rankBadge = '<span style="background:#e0e0e0;padding:2px 10px;border-radius:10px">' + (k+1) + '</span>';
rankHtml += '<tr>' +
'<td>' + rankBadge + '</td>' +
'<td><strong>' + cr.name + '</strong></td>' +
'<td><span class="tag" style="background:' + getVipColor(cr.vip) + ';color:#fff">' + cr.vip + '</span></td>' +
'<td>' + cr.times + '次</td>' +
'<td>' + cr.days + '天</td>' +
'<td style="color:#ff9800"><strong>¥' + cr.spent.toLocaleString() + '</strong></td></tr>';
}
document.getElementById("customerRankList").innerHTML = rankHtml;
}
// ==================== 辅助函数 ====================
function getStatusClass(status) {
if(status === "空闲") return "free";
if(status === "已预定") return "booked";
if(status === "已入住") return "checkin";
if(status === "清洁中") return "cleaning";
return "free";
}
function getOrderStatusClass(status) {
if(status === "待确认") return "booked";
if(status === "已确认") return "checkin";
if(status === "已入住") return "checkin";
if(status === "已退房") return "free";
if(status === "已取消") return "cleaning";
return "free";
}
function getVipColor(vip) {
if(vip === "普通会员") return "#9e9e9e";
if(vip === "银卡会员") return "#78909c";
if(vip === "金卡会员") return "#ffa000";
if(vip === "钻石会员") return "#7c4dff";
return "#9e9e9e";
}
function maskIdCard(id) {
return id.substring(0, 6) + "********" + id.substring(14);
}
function exportCheckins() {
alert("入住记录已导出为Excel文件前端演示");
}
// ==================== 模态框 ====================
function openRoomModal() {
document.getElementById("modalContainer").innerHTML =
'<div class="modal" onclick="closeModal(event)">' +
'<div class="modal-content" onclick="event.stopPropagation()">' +
'<h3>添加房间</h3>' +
'<div class="form-group"><label>房间号</label><input placeholder="如3101"></div>' +
'<div class="form-group"><label>房型</label><select>' +
'<option>经济单人间</option><option>标准单人间</option><option>标准双人间</option>' +
'<option>豪华双人间</option><option>商务大床房</option><option>家庭亲子房</option>' +
'<option>豪华套房</option><option>总统套房</option></select></div>' +
'<div class="form-group"><label>楼层</label><input type="number" placeholder="如3"></div>' +
'<div class="form-group"><label>价格(元/晚)</label><input type="number" placeholder="如288"></div>' +
'<div class="form-actions">' +
'<button class="btn" onclick="closeModal()">取消</button>' +
'<button class="btn btn-primary" onclick="saveRoom()">保存</button>' +
'</div>' +
'</div>' +
'</div>';
}
function openCustomerModal() {
document.getElementById("modalContainer").innerHTML =
'<div class="modal" onclick="closeModal(event)">' +
'<div class="modal-content" onclick="event.stopPropagation()">' +
'<h3>新增客户</h3>' +
'<div class="form-group"><label>姓名</label><input placeholder="请输入姓名"></div>' +
'<div class="form-group"><label>性别</label><select><option>男</option><option>女</option></select></div>' +
'<div class="form-group"><label>手机号</label><input placeholder="请输入手机号"></div>' +
'<div class="form-group"><label>身份证号</label><input placeholder="请输入身份证号"></div>' +
'<div class="form-actions">' +
'<button class="btn" onclick="closeModal()">取消</button>' +
'<button class="btn btn-primary" onclick="saveCustomer()">保存</button>' +
'</div>' +
'</div>' +
'</div>';
}
function openOrderModal() {
var customerOptions = '';
for(var i = 0; i < customers.length; i++) {
customerOptions += '<option>' + customers[i].name + ' (' + customers[i].phone + ')</option>';
}
var roomOptions = '';
for(var j = 0; j < rooms.length; j++) {
if(rooms[j].status === "空闲") {
roomOptions += '<option>' + rooms[j].roomNo + ' - ' + rooms[j].type + ' (¥' + rooms[j].price + '/晚)</option>';
}
}
document.getElementById("modalContainer").innerHTML =
'<div class="modal" onclick="closeModal(event)">' +
'<div class="modal-content" onclick="event.stopPropagation()">' +
'<h3>新增预定</h3>' +
'<div class="form-group"><label>选择客户</label><select>' + customerOptions + '</select></div>' +
'<div class="form-group"><label>选择房间</label><select>' + roomOptions + '</select></div>' +
'<div class="form-group"><label>入住日期</label><input type="date"></div>' +
'<div class="form-group"><label>离店日期</label><input type="date"></div>' +
'<div class="form-actions">' +
'<button class="btn" onclick="closeModal()">取消</button>' +
'<button class="btn btn-primary" onclick="saveOrder()">保存</button>' +
'</div>' +
'</div>' +
'</div>';
}
function closeModal(event) {
if(!event || event.target.className === 'modal') {
document.getElementById("modalContainer").innerHTML = "";
}
}
// ==================== 操作函数 ====================
function saveRoom() { alert("房间信息已保存!(前端演示)"); closeModal(); }
function saveCustomer() { alert("客户信息已保存!(前端演示)"); closeModal(); }
function saveOrder() { alert("预定已创建!(前端演示)"); closeModal(); }
function editRoom(id) { alert("编辑房间:" + id + "(前端演示)"); }
function deleteRoom(id) { if(confirm("确定删除?")) alert("已删除(前端演示)"); }
function editCustomer(id) { alert("编辑客户:" + id + "(前端演示)"); }
function deleteCustomer(id) { if(confirm("确定删除?")) alert("已删除(前端演示)"); }
function confirmOrder(id) { alert("预定已确认!(前端演示)"); }
function checkinOrder(id) { alert("已办理入住!(前端演示)"); }
function checkoutOrder(id) { alert("已办理退房!(前端演示)"); }
function cancelOrder(id) { if(confirm("确定取消?")) alert("已取消(前端演示)"); }
</script>
</body>
</html>