Files
DFJ/01_文档/原型设计/03_加入房间列表.html
2025-09-11 13:17:27 +08:00

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>