643 lines
20 KiB
HTML
643 lines
20 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
|
|
<title>加入房间 - 打飞机对战</title>
|
|
|
|
<!-- 引入通用样式 -->
|
|
<link rel="stylesheet" href="common-styles.css">
|
|
|
|
<style>
|
|
/* 加入房间列表页面特定样式 */
|
|
.safe-area {
|
|
padding-left: env(safe-area-inset-left);
|
|
padding-right: env(safe-area-inset-right);
|
|
padding-top: env(safe-area-inset-top);
|
|
padding-bottom: env(safe-area-inset-bottom);
|
|
}
|
|
|
|
.placeholder {
|
|
width: 40px;
|
|
}
|
|
|
|
/* 搜索区域 */
|
|
.search-section {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.search-container {
|
|
display: flex;
|
|
gap: 12px;
|
|
align-items: center;
|
|
}
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
height: var(--touch-target-min);
|
|
padding: 0 16px;
|
|
background: rgba(22, 33, 62, 0.8);
|
|
border: 1px solid rgba(64, 224, 208, 0.3);
|
|
border-radius: 12px;
|
|
color: var(--text-primary);
|
|
font-size: 16px;
|
|
backdrop-filter: blur(10px);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.search-input:focus {
|
|
outline: none;
|
|
border-color: var(--primary-color);
|
|
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
|
}
|
|
|
|
.search-input::placeholder {
|
|
color: var(--text-tertiary);
|
|
}
|
|
|
|
.search-btn {
|
|
min-width: 60px;
|
|
height: var(--touch-target-min);
|
|
border: none;
|
|
border-radius: 12px;
|
|
font-size: 14px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
|
|
color: white;
|
|
box-shadow: 0 4px 16px rgba(99, 102, 241, 0.3);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.search-btn:active {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
/* 房间列表 */
|
|
.rooms-section {
|
|
flex: 1;
|
|
}
|
|
|
|
.section-divider {
|
|
height: 1px;
|
|
background: linear-gradient(90deg, transparent, var(--border-primary), transparent);
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.room-item {
|
|
padding: 20px 0;
|
|
border-bottom: 1px solid rgba(64, 224, 208, 0.1);
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.room-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.room-item:active {
|
|
background: rgba(64, 224, 208, 0.05);
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
.room-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.room-number {
|
|
font-size: 18px;
|
|
font-weight: 700;
|
|
background: linear-gradient(135deg, var(--primary-color) 0%, var(--primary-light) 100%);
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
}
|
|
|
|
.room-status {
|
|
padding: 4px 12px;
|
|
border-radius: 8px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-waiting {
|
|
background: rgba(64, 224, 208, 0.2);
|
|
color: var(--secondary-color);
|
|
}
|
|
|
|
.status-playing {
|
|
background: rgba(245, 158, 11, 0.2);
|
|
color: var(--accent-color);
|
|
}
|
|
|
|
.status-full {
|
|
background: rgba(156, 163, 175, 0.2);
|
|
color: var(--text-tertiary);
|
|
}
|
|
|
|
.room-info {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.host-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8px;
|
|
color: var(--text-secondary);
|
|
font-size: 14px;
|
|
}
|
|
|
|
.host-avatar {
|
|
width: 24px;
|
|
height: 24px;
|
|
border-radius: 6px;
|
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-light));
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 12px;
|
|
color: white;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.host-stats {
|
|
display: flex;
|
|
gap: 12px;
|
|
}
|
|
|
|
.action-btn {
|
|
min-width: 60px;
|
|
height: 32px;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-size: 12px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.join-btn {
|
|
background: linear-gradient(135deg, var(--secondary-color), var(--secondary-light));
|
|
color: #1a1a2e;
|
|
}
|
|
|
|
.join-btn:active {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.watch-btn {
|
|
background: rgba(245, 158, 11, 0.15);
|
|
color: var(--accent-color);
|
|
border: 1px solid var(--accent-color);
|
|
}
|
|
|
|
.watch-btn:active {
|
|
background: rgba(245, 158, 11, 0.25);
|
|
}
|
|
|
|
.disabled-btn {
|
|
background: rgba(156, 163, 175, 0.15);
|
|
color: var(--text-disabled);
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* 刷新按钮 */
|
|
.refresh-section {
|
|
padding: 20px 0;
|
|
text-align: center;
|
|
}
|
|
|
|
.refresh-btn {
|
|
width: 100%;
|
|
min-height: var(--touch-target-min);
|
|
border: none;
|
|
border-radius: 12px;
|
|
font-size: 16px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
background: rgba(99, 102, 241, 0.15);
|
|
color: var(--primary-color);
|
|
border: 1px solid var(--primary-color);
|
|
backdrop-filter: blur(10px);
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.refresh-btn:active {
|
|
background: rgba(99, 102, 241, 0.25);
|
|
}
|
|
|
|
/* 空状态 */
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 60px 20px;
|
|
color: var(--text-tertiary);
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 48px;
|
|
margin-bottom: 16px;
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 16px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
/* 响应式适配 */
|
|
@media (max-width: 375px) {
|
|
.room-item {
|
|
padding: 16px 0;
|
|
}
|
|
|
|
.room-number {
|
|
font-size: 16px;
|
|
}
|
|
|
|
.host-info {
|
|
font-size: 13px;
|
|
}
|
|
}
|
|
|
|
@media (max-height: 640px) {
|
|
.app-container {
|
|
padding: 16px;
|
|
}
|
|
|
|
.header {
|
|
margin-bottom: 16px;
|
|
}
|
|
}
|
|
|
|
/* 加载状态 */
|
|
.loading {
|
|
text-align: center;
|
|
padding: 40px 0;
|
|
color: var(--text-tertiary);
|
|
}
|
|
|
|
.loading-spinner {
|
|
width: 32px;
|
|
height: 32px;
|
|
border: 3px solid rgba(99, 102, 241, 0.1);
|
|
border-top: 3px solid var(--primary-color);
|
|
border-radius: 50%;
|
|
animation: spin 1s linear infinite;
|
|
margin: 0 auto 16px;
|
|
}
|
|
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="safe-area">
|
|
<div class="app-container">
|
|
<!-- 头部导航 -->
|
|
<header class="header">
|
|
<button class="back-btn" onclick="goBack()">
|
|
←
|
|
</button>
|
|
<h1 class="page-title">可加入房间</h1>
|
|
<div class="placeholder"></div>
|
|
</header>
|
|
|
|
<!-- 搜索区域 -->
|
|
<section class="search-section">
|
|
<div class="search-container">
|
|
<input type="number" class="search-input" placeholder="房间号搜索" maxlength="6" id="roomSearch">
|
|
<button class="search-btn" onclick="searchRoom()">搜索</button>
|
|
</div>
|
|
</section>
|
|
|
|
<div class="section-divider"></div>
|
|
|
|
<!-- 房间列表 -->
|
|
<section class="rooms-section" id="roomsList">
|
|
<!-- 房间项示例 -->
|
|
<div class="room-item">
|
|
<div class="room-header">
|
|
<div class="room-number">房间 123456</div>
|
|
<div class="room-status status-waiting">等待中</div>
|
|
</div>
|
|
<div class="room-info">
|
|
<div class="host-info">
|
|
<div class="host-avatar">张</div>
|
|
<span>张三</span>
|
|
<div class="host-stats">
|
|
<span>156场</span>
|
|
<span>68%胜率</span>
|
|
</div>
|
|
</div>
|
|
<button class="action-btn join-btn" onclick="joinRoom('123456')">加入 →</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="room-item">
|
|
<div class="room-header">
|
|
<div class="room-number">房间 789012</div>
|
|
<div class="room-status status-waiting">等待中</div>
|
|
</div>
|
|
<div class="room-info">
|
|
<div class="host-info">
|
|
<div class="host-avatar">李</div>
|
|
<span>李四</span>
|
|
<div class="host-stats">
|
|
<span>89场</span>
|
|
<span>72%胜率</span>
|
|
</div>
|
|
</div>
|
|
<button class="action-btn join-btn" onclick="joinRoom('789012')">加入 →</button>
|
|
</div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
<!-- 刷新按钮 -->
|
|
<section class="refresh-section">
|
|
<button class="refresh-btn" onclick="refreshRoomList()">刷新列表</button>
|
|
</section>
|
|
</div>
|
|
|
|
<!-- 引入导航功能 -->
|
|
<script src="navigation.js"></script>
|
|
|
|
<script>
|
|
// 房间数据模拟
|
|
const mockRooms = [
|
|
{
|
|
id: '123456',
|
|
host: { name: '张三', avatar: '张', games: 156, winRate: 68 },
|
|
status: 'waiting'
|
|
},
|
|
{
|
|
id: '789012',
|
|
host: { name: '李四', avatar: '李', games: 89, winRate: 72 },
|
|
status: 'waiting'
|
|
},
|
|
{
|
|
id: '345678',
|
|
host: { name: '王五', avatar: '王', games: 234, winRate: 65 },
|
|
status: 'playing'
|
|
},
|
|
{
|
|
id: '567890',
|
|
host: { name: '赵六', avatar: '赵', games: 67, winRate: 71 },
|
|
status: 'full'
|
|
}
|
|
];
|
|
|
|
// 返回上一页
|
|
function goBack() {
|
|
console.log('返回上一页');
|
|
if (typeof window.vibrate === 'function') {
|
|
window.vibrate();
|
|
} else {
|
|
vibrate();
|
|
}
|
|
// 使用导航功能返回入口页面
|
|
if (typeof navigateTo === 'function') {
|
|
navigateTo('entry');
|
|
} else {
|
|
window.location.href = '01_入口页面.html';
|
|
}
|
|
}
|
|
|
|
// 搜索房间
|
|
function searchRoom() {
|
|
const roomNumber = document.getElementById('roomSearch').value.trim();
|
|
|
|
if (!roomNumber) {
|
|
showToast('请输入房间号');
|
|
return;
|
|
}
|
|
|
|
if (roomNumber.length !== 6) {
|
|
showToast('房间号应为6位数字');
|
|
return;
|
|
}
|
|
|
|
console.log('搜索房间:', roomNumber);
|
|
if (typeof window.vibrate === 'function') {
|
|
window.vibrate();
|
|
} else {
|
|
vibrate();
|
|
}
|
|
showLoading();
|
|
|
|
// 模拟搜索延迟
|
|
setTimeout(() => {
|
|
hideLoading();
|
|
const room = mockRooms.find(r => r.id === roomNumber);
|
|
if (room) {
|
|
renderRooms([room]);
|
|
} else {
|
|
showEmptyState('未找到房间 ' + roomNumber);
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
// 加入房间
|
|
function joinRoom(roomId) {
|
|
console.log('加入房间:', roomId);
|
|
if (typeof window.vibrate === 'function') {
|
|
window.vibrate();
|
|
} else {
|
|
vibrate();
|
|
}
|
|
|
|
showToast('正在加入房间...');
|
|
// 实际项目中这里应该调用加入房间的API
|
|
setTimeout(() => {
|
|
showToast('加入成功!');
|
|
// 跳转到房间等待页面
|
|
if (typeof navigateTo === 'function') {
|
|
navigateTo('roomWaiting');
|
|
} else {
|
|
window.location.href = '02_房间等待[房主].html';
|
|
}
|
|
}, 1500);
|
|
}
|
|
|
|
// 观战房间
|
|
function watchRoom(roomId) {
|
|
console.log('观战房间:', roomId);
|
|
vibrate();
|
|
|
|
showToast('正在进入观战模式...');
|
|
// 实际项目中这里应该跳转到观战页面
|
|
}
|
|
|
|
// 刷新房间列表
|
|
function refreshRoomList() {
|
|
console.log('刷新房间列表');
|
|
vibrate();
|
|
showLoading();
|
|
|
|
// 模拟刷新延迟
|
|
setTimeout(() => {
|
|
hideLoading();
|
|
renderRooms(mockRooms);
|
|
showToast('列表已更新');
|
|
}, 1000);
|
|
}
|
|
|
|
// 渲染房间列表
|
|
function renderRooms(rooms) {
|
|
const roomsList = document.getElementById('roomsList');
|
|
|
|
if (rooms.length === 0) {
|
|
showEmptyState('暂无可用房间');
|
|
return;
|
|
}
|
|
|
|
const html = rooms.map(room => {
|
|
const statusConfig = {
|
|
waiting: { class: 'status-waiting', text: '等待中' },
|
|
playing: { class: 'status-playing', text: '游戏中' },
|
|
full: { class: 'status-full', text: '房间满' }
|
|
};
|
|
|
|
const actionConfig = {
|
|
waiting: { class: 'join-btn', text: '加入 →', onclick: `joinRoom('${room.id}')` },
|
|
playing: { class: 'watch-btn', text: '观战 👁', onclick: `watchRoom('${room.id}')` },
|
|
full: { class: 'disabled-btn', text: '已满', onclick: '', disabled: true }
|
|
};
|
|
|
|
const status = statusConfig[room.status];
|
|
const action = actionConfig[room.status];
|
|
|
|
return `
|
|
<div class="room-item">
|
|
<div class="room-header">
|
|
<div class="room-number">房间 ${room.id}</div>
|
|
<div class="room-status ${status.class}">${status.text}</div>
|
|
</div>
|
|
<div class="room-info">
|
|
<div class="host-info">
|
|
<div class="host-avatar">${room.host.avatar}</div>
|
|
<span>${room.host.name}</span>
|
|
<div class="host-stats">
|
|
<span>${room.host.games}场</span>
|
|
<span>${room.host.winRate}%胜率</span>
|
|
</div>
|
|
</div>
|
|
<button class="action-btn ${action.class}"
|
|
onclick="${action.onclick}"
|
|
${action.disabled ? 'disabled' : ''}>${action.text}</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
|
|
roomsList.innerHTML = html;
|
|
}
|
|
|
|
// 显示加载状态
|
|
function showLoading() {
|
|
const roomsList = document.getElementById('roomsList');
|
|
roomsList.innerHTML = `
|
|
<div class="loading">
|
|
<div class="loading-spinner"></div>
|
|
<div>正在加载...</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// 隐藏加载状态
|
|
function hideLoading() {
|
|
// 由其他函数负责更新内容
|
|
}
|
|
|
|
// 显示空状态
|
|
function showEmptyState(message = '暂无房间数据') {
|
|
const roomsList = document.getElementById('roomsList');
|
|
roomsList.innerHTML = `
|
|
<div class="empty-state">
|
|
<div class="empty-icon">🏠</div>
|
|
<div class="empty-text">${message}</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
// 触觉反馈
|
|
function vibrate() {
|
|
if ('vibrate' in navigator) {
|
|
navigator.vibrate(10);
|
|
}
|
|
}
|
|
|
|
// 显示提示信息
|
|
function showToast(message) {
|
|
const toast = document.createElement('div');
|
|
toast.textContent = message;
|
|
toast.style.cssText = `
|
|
position: fixed;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
background: rgba(0, 0, 0, 0.8);
|
|
color: white;
|
|
padding: 12px 20px;
|
|
border-radius: 8px;
|
|
font-size: 14px;
|
|
z-index: 1000;
|
|
animation: fadeInOut 2s ease;
|
|
`;
|
|
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
@keyframes fadeInOut {
|
|
0% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
|
|
20%, 80% { opacity: 1; transform: translate(-50%, -50%) scale(1); }
|
|
100% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); }
|
|
}
|
|
`;
|
|
|
|
document.head.appendChild(style);
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
document.body.removeChild(toast);
|
|
document.head.removeChild(style);
|
|
}, 2000);
|
|
}
|
|
|
|
// 搜索框回车事件
|
|
document.getElementById('roomSearch').addEventListener('keypress', function(e) {
|
|
if (e.key === 'Enter') {
|
|
searchRoom();
|
|
}
|
|
});
|
|
|
|
// 搜索框数字限制
|
|
document.getElementById('roomSearch').addEventListener('input', function(e) {
|
|
let value = e.target.value.replace(/[^0-9]/g, '');
|
|
if (value.length > 6) {
|
|
value = value.slice(0, 6);
|
|
}
|
|
e.target.value = value;
|
|
});
|
|
|
|
// 页面加载完成后的初始化
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
console.log('加入房间列表页面已加载');
|
|
renderRooms(mockRooms);
|
|
});
|
|
|
|
// 防止页面缩放
|
|
document.addEventListener('gesturestart', function (e) {
|
|
e.preventDefault();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html> |