|
@@ -1,48 +1,583 @@
|
|
|
<template>
|
|
|
- <view class="history-page">
|
|
|
- <view class="title">历史记录</view>
|
|
|
- <nut-empty description="正在开发中..." image="empty" />
|
|
|
+ <view class="history-page">
|
|
|
+ <view class="tab-container">
|
|
|
+ <nut-tabs v-model="activeTab">
|
|
|
+ <nut-tab-pane title="最近游戏" pane-key="0">
|
|
|
+ <nut-skeleton v-if="isLoading" animated :rows="3" />
|
|
|
+
|
|
|
+ <block v-else>
|
|
|
+ <!-- 进行中的房间 -->
|
|
|
+ <view class="game-section" v-if="activeRooms.length > 0">
|
|
|
+ <view class="section-title">进行中的房间</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="room in activeRooms"
|
|
|
+ :key="room.id"
|
|
|
+ class="room-item active"
|
|
|
+ @click="joinActiveRoom(room.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="room.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="room.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ room.name }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ room.gameTitle }}</text>
|
|
|
+ <text class="room-time">房间号: {{ room.id }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag playing" v-if="room.status === 'playing'">进行中</view>
|
|
|
+ <view class="status-tag waiting" v-else>等待中</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 已结束的游戏 -->
|
|
|
+ <view class="game-section" v-if="endedGames.length > 0">
|
|
|
+ <view class="section-title">已结束的游戏</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="game in endedGames"
|
|
|
+ :key="game.id"
|
|
|
+ class="room-item ended"
|
|
|
+ @click="viewGameDetails(game.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="game.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="game.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ game.roomName }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ game.gameTitle }}</text>
|
|
|
+ <text class="room-time">{{ formatTime(game.endTime) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="game-duration">游戏时长: {{ game.duration }}分钟</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag ended">已结束</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <nut-empty
|
|
|
+ v-if="activeRooms.length === 0 && endedGames.length === 0"
|
|
|
+ description="暂无游戏记录"
|
|
|
+ image="empty"
|
|
|
+ />
|
|
|
+ </block>
|
|
|
+
|
|
|
+ <view class="load-more" v-if="activeRooms.length > 0 || endedGames.length > 0">
|
|
|
+ <nut-divider>{{ isLoading ? '加载中...' : '没有更多了' }}</nut-divider>
|
|
|
+ </view>
|
|
|
+ </nut-tab-pane>
|
|
|
+
|
|
|
+ <nut-tab-pane title="我创建的" pane-key="1">
|
|
|
+ <nut-skeleton v-if="isLoading" animated :rows="3" />
|
|
|
+
|
|
|
+ <block v-else>
|
|
|
+ <!-- 进行中的房间 -->
|
|
|
+ <view class="game-section" v-if="activeRooms.length > 0">
|
|
|
+ <view class="section-title">进行中的房间</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="room in activeRooms"
|
|
|
+ :key="room.id"
|
|
|
+ class="room-item active"
|
|
|
+ @click="joinActiveRoom(room.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="room.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="room.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ room.name }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ room.gameTitle }}</text>
|
|
|
+ <text class="room-time">房间号: {{ room.id }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag playing" v-if="room.status === 'playing'">进行中</view>
|
|
|
+ <view class="status-tag waiting" v-else>等待中</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 已结束的游戏 -->
|
|
|
+ <view class="game-section" v-if="endedGames.length > 0">
|
|
|
+ <view class="section-title">已结束的游戏</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="game in endedGames"
|
|
|
+ :key="game.id"
|
|
|
+ class="room-item ended"
|
|
|
+ @click="viewGameDetails(game.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="game.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="game.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ game.roomName }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ game.gameTitle }}</text>
|
|
|
+ <text class="room-time">{{ formatTime(game.endTime) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="game-duration">游戏时长: {{ game.duration }}分钟</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag ended">已结束</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <nut-empty
|
|
|
+ v-if="activeRooms.length === 0 && endedGames.length === 0"
|
|
|
+ description="暂无创建的游戏"
|
|
|
+ image="empty"
|
|
|
+ />
|
|
|
+ </block>
|
|
|
+
|
|
|
+ <view class="load-more" v-if="activeRooms.length > 0 || endedGames.length > 0">
|
|
|
+ <nut-divider>{{ isLoading ? '加载中...' : '没有更多了' }}</nut-divider>
|
|
|
+ </view>
|
|
|
+ </nut-tab-pane>
|
|
|
+
|
|
|
+ <nut-tab-pane title="我参与的" pane-key="2">
|
|
|
+ <nut-skeleton v-if="isLoading" animated :rows="3" />
|
|
|
+
|
|
|
+ <block v-else>
|
|
|
+ <!-- 进行中的房间 -->
|
|
|
+ <view class="game-section" v-if="activeRooms.length > 0">
|
|
|
+ <view class="section-title">进行中的房间</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="room in activeRooms"
|
|
|
+ :key="room.id"
|
|
|
+ class="room-item active"
|
|
|
+ @click="joinActiveRoom(room.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="room.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="room.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ room.name }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ room.gameTitle }}</text>
|
|
|
+ <text class="room-time">房间号: {{ room.id }}</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag playing" v-if="room.status === 'playing'">进行中</view>
|
|
|
+ <view class="status-tag waiting" v-else>等待中</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 已结束的游戏 -->
|
|
|
+ <view class="game-section" v-if="endedGames.length > 0">
|
|
|
+ <view class="section-title">已结束的游戏</view>
|
|
|
+
|
|
|
+ <view class="room-list">
|
|
|
+ <view
|
|
|
+ v-for="game in endedGames"
|
|
|
+ :key="game.id"
|
|
|
+ class="room-item ended"
|
|
|
+ @click="viewGameDetails(game.id)"
|
|
|
+ >
|
|
|
+ <view class="game-icon">
|
|
|
+ <view v-if="game.gameId === '1'" class="game-icon-inner duck"></view>
|
|
|
+ <view v-else-if="game.gameId === '2'" class="game-icon-inner detective"></view>
|
|
|
+ <view v-else class="game-icon-inner default"></view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="room-info">
|
|
|
+ <view class="room-name">{{ game.roomName }}</view>
|
|
|
+ <view class="room-details">
|
|
|
+ <text class="game-type">{{ game.gameTitle }}</text>
|
|
|
+ <text class="room-time">{{ formatTime(game.endTime) }}</text>
|
|
|
+ </view>
|
|
|
+ <view class="game-duration">游戏时长: {{ game.duration }}分钟</view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <view class="status-tag ended">已结束</view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 空状态 -->
|
|
|
+ <nut-empty
|
|
|
+ v-if="activeRooms.length === 0 && endedGames.length === 0"
|
|
|
+ description="暂无参与的游戏"
|
|
|
+ image="empty"
|
|
|
+ />
|
|
|
+ </block>
|
|
|
+
|
|
|
+ <view class="load-more" v-if="activeRooms.length > 0 || endedGames.length > 0">
|
|
|
+ <nut-divider>{{ isLoading ? '加载中...' : '没有更多了' }}</nut-divider>
|
|
|
+ </view>
|
|
|
+ </nut-tab-pane>
|
|
|
+ </nut-tabs>
|
|
|
</view>
|
|
|
- <Tabbar></Tabbar>
|
|
|
- </template>
|
|
|
+ </view>
|
|
|
+ <Tabbar></Tabbar>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts">
|
|
|
+import { ref, onMounted, computed, watch } from 'vue'
|
|
|
+import Tabbar from '@/components/Tabbar.vue'
|
|
|
+import Taro from '@tarojs/taro'
|
|
|
+import { useRoomStore } from '@/stores/room'
|
|
|
+import { useUserStore } from '@/stores/user'
|
|
|
+
|
|
|
+export default {
|
|
|
+ components: {
|
|
|
+ Tabbar
|
|
|
+ },
|
|
|
|
|
|
- <script lang="ts">
|
|
|
- import Tabbar from '@/components/Tabbar.vue'
|
|
|
- import Taro from '@tarojs/taro'
|
|
|
+ // 页面显示时的生命周期钩子
|
|
|
+ onShow() {
|
|
|
+ // 隐藏返回首页按钮
|
|
|
+ Taro.hideHomeButton()
|
|
|
+
|
|
|
+ // 刷新数据
|
|
|
+ this.refreshHistory()
|
|
|
+ },
|
|
|
|
|
|
- // 历史记录页逻辑
|
|
|
- export default {
|
|
|
- components: {
|
|
|
- Tabbar
|
|
|
- },
|
|
|
-
|
|
|
- // 页面显示时的生命周期钩子
|
|
|
- onShow() {
|
|
|
- // 隐藏返回首页按钮
|
|
|
- Taro.hideHomeButton()
|
|
|
- console.log('已隐藏返回首页按钮')
|
|
|
- },
|
|
|
-
|
|
|
- // setup函数用于Composition API
|
|
|
- setup() {
|
|
|
- // 这里可以添加其他响应式数据和方法
|
|
|
+ // setup函数用于Composition API
|
|
|
+ setup() {
|
|
|
+ const roomStore = useRoomStore()
|
|
|
+ const userStore = useUserStore()
|
|
|
+
|
|
|
+ // 修改为字符串类型与pane-key匹配
|
|
|
+ const activeTab = ref('0')
|
|
|
+
|
|
|
+ // 计算属性获取historyState中的数据
|
|
|
+ const activeRooms = computed(() => roomStore.historyState.activeRooms)
|
|
|
+ const endedGames = computed(() => roomStore.historyState.endedGames)
|
|
|
+ const isLoading = computed(() => roomStore.historyState.isLoading)
|
|
|
+
|
|
|
+ // 监听标签变化
|
|
|
+ watch(activeTab, (newVal) => {
|
|
|
+ loadHistoryByTab(newVal)
|
|
|
+ })
|
|
|
+
|
|
|
+ // 加载历史记录
|
|
|
+ const loadHistory = async () => {
|
|
|
+ await loadHistoryByTab(activeTab.value)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 根据标签加载数据
|
|
|
+ const loadHistoryByTab = async (tabIndex: string) => {
|
|
|
+ // 将字符串转换为数字
|
|
|
+ const tabIndexNum = parseInt(tabIndex)
|
|
|
+
|
|
|
+ // 确保用户已登录
|
|
|
+ if (!userStore.openid) {
|
|
|
+ console.warn('用户未登录,无法加载历史记录')
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- return {
|
|
|
- // 返回需要在模板中使用的数据和方法
|
|
|
+ await roomStore.loadHistoryByTab(tabIndexNum)
|
|
|
+
|
|
|
+ // 同步更新最近房间列表
|
|
|
+ if (tabIndexNum === 0) {
|
|
|
+ await roomStore.loadRecentRooms()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 刷新历史记录
|
|
|
+ const refreshHistory = () => {
|
|
|
+ loadHistory()
|
|
|
+ }
|
|
|
+
|
|
|
+ // 格式化时间显示
|
|
|
+ const formatTime = (timestamp) => {
|
|
|
+ const date = new Date(timestamp)
|
|
|
+ const now = new Date()
|
|
|
+
|
|
|
+ // 今天内
|
|
|
+ if (date.toDateString() === now.toDateString()) {
|
|
|
+ return `今天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
|
|
}
|
|
|
+
|
|
|
+ // 昨天
|
|
|
+ const yesterday = new Date()
|
|
|
+ yesterday.setDate(now.getDate() - 1)
|
|
|
+ if (date.toDateString() === yesterday.toDateString()) {
|
|
|
+ return `昨天 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他日期
|
|
|
+ return `${date.getMonth() + 1}月${date.getDate()}日 ${date.getHours().toString().padStart(2, '0')}:${date.getMinutes().toString().padStart(2, '0')}`
|
|
|
+ }
|
|
|
+
|
|
|
+ // 加入进行中的房间
|
|
|
+ const joinActiveRoom = async (roomId: string) => {
|
|
|
+ try {
|
|
|
+ Taro.showLoading({ title: '加入房间中...' })
|
|
|
+
|
|
|
+ // 使用Store中的统一方法加入房间
|
|
|
+ const result = await roomStore.joinRoomById(roomId)
|
|
|
+
|
|
|
+ if (result.success) {
|
|
|
+ roomStore.navigateToRoomPage(roomId)
|
|
|
+ } else {
|
|
|
+ if (result.needPassword) {
|
|
|
+ // 如果需要密码,跳转到join页面
|
|
|
+ Taro.navigateTo({
|
|
|
+ url: `/pages/room/join/index?roomId=${roomId}&needPassword=true`
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ Taro.showToast({
|
|
|
+ title: result.message || '加入房间失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('加入房间失败:', error)
|
|
|
+ Taro.showToast({
|
|
|
+ title: error.message || '加入房间失败',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ } finally {
|
|
|
+ Taro.hideLoading()
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查看游戏详情
|
|
|
+ const viewGameDetails = (gameId) => {
|
|
|
+ Taro.showToast({
|
|
|
+ title: '游戏回顾功能开发中',
|
|
|
+ icon: 'none'
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 初始加载
|
|
|
+ onMounted(() => {
|
|
|
+ loadHistory()
|
|
|
+ })
|
|
|
+
|
|
|
+ return {
|
|
|
+ activeTab,
|
|
|
+ activeRooms,
|
|
|
+ endedGames,
|
|
|
+ isLoading,
|
|
|
+ loadHistoryByTab, // 导出新函数
|
|
|
+ refreshHistory,
|
|
|
+ formatTime,
|
|
|
+ joinActiveRoom,
|
|
|
+ viewGameDetails
|
|
|
}
|
|
|
}
|
|
|
- </script>
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss">
|
|
|
+.history-page {
|
|
|
+ padding: $spacing-base;
|
|
|
+ background-color: $background-color-base;
|
|
|
+ min-height: 100vh;
|
|
|
+ padding-bottom: $spacing-large * 4; // 为底部tabbar留出空间
|
|
|
+ scroll-behavior: smooth;
|
|
|
|
|
|
- <style lang="scss">
|
|
|
- .history-page {
|
|
|
- padding: 20px;
|
|
|
+ .tab-container {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
|
|
|
- .title {
|
|
|
- font-size: 20px;
|
|
|
- font-weight: bold;
|
|
|
- margin-bottom: 20px;
|
|
|
- text-align: center;
|
|
|
+ .nut-tabs__content {
|
|
|
+ transition: all 0.3s ease;
|
|
|
}
|
|
|
}
|
|
|
- </style>
|
|
|
+
|
|
|
+ .game-section {
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ padding: $spacing-base;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+
|
|
|
+ .section-title {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ font-weight: $font-weight-bold;
|
|
|
+ color: $text-color-primary;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+ padding-left: $spacing-small;
|
|
|
+ border-left: 3px solid $primary-color;
|
|
|
+ }
|
|
|
+
|
|
|
+ .room-list {
|
|
|
+ .room-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: $spacing-base;
|
|
|
+ border-bottom: 1px solid $border-color-light;
|
|
|
+ position: relative;
|
|
|
+ transition: transform 0.2s, background-color 0.2s;
|
|
|
+
|
|
|
+ &:last-child {
|
|
|
+ border-bottom: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.active {
|
|
|
+ background-color: rgba(60, 146, 251, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ended {
|
|
|
+ background-color: rgba(153, 153, 153, 0.05);
|
|
|
+ }
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ transform: scale(0.98);
|
|
|
+ background-color: rgba(0, 0, 0, 0.02);
|
|
|
+ }
|
|
|
+
|
|
|
+ .game-icon {
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+ border-radius: 8px;
|
|
|
+ margin-right: $spacing-base;
|
|
|
+ overflow: hidden;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ background-color: $background-color-blue;
|
|
|
+
|
|
|
+ .game-icon-inner {
|
|
|
+ width: 36px;
|
|
|
+ height: 36px;
|
|
|
+
|
|
|
+ &.duck {
|
|
|
+ background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%23FFCC00" d="M12,3C7.58,3 4,5.58 4,10C4,14.42 7.58,17 12,17C16.42,17 20,14.42 20,10C20,5.58 16.42,3 12,3M12,5C13.93,5 15.5,6.57 15.5,8.5C15.5,10.43 13.93,12 12,12C10.07,12 8.5,10.43 8.5,8.5C8.5,6.57 10.07,5 12,5M5,20V23H19V20H5Z"/></svg>');
|
|
|
+ background-size: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.detective {
|
|
|
+ background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%233C92FB" d="M9.5,3A6.5,6.5 0 0,1 16,9.5C16,11.11 15.41,12.59 14.44,13.73L14.71,14H15.5L20.5,19L19,20.5L14,15.5V14.71L13.73,14.44C12.59,15.41 11.11,16 9.5,16A6.5,6.5 0 0,1 3,9.5A6.5,6.5 0 0,1 9.5,3M9.5,5C7,5 5,7 5,9.5C5,12 7,14 9.5,14C12,14 14,12 14,9.5C14,7 12,5 9.5,5Z"/></svg>');
|
|
|
+ background-size: cover;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.default {
|
|
|
+ background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="%23999999" d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,10.5A1.5,1.5 0 0,1 13.5,12A1.5,1.5 0 0,1 12,13.5A1.5,1.5 0 0,1 10.5,12A1.5,1.5 0 0,1 12,10.5M7.5,10.5A1.5,1.5 0 0,1 9,12A1.5,1.5 0 0,1 7.5,13.5A1.5,1.5 0 0,1 6,12A1.5,1.5 0 0,1 7.5,10.5M16.5,10.5A1.5,1.5 0 0,1 18,12A1.5,1.5 0 0,1 16.5,13.5A1.5,1.5 0 0,1 15,12A1.5,1.5 0 0,1 16.5,10.5Z"/></svg>');
|
|
|
+ background-size: cover;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .room-info {
|
|
|
+ flex: 1;
|
|
|
+
|
|
|
+ .room-name {
|
|
|
+ font-size: $font-size-medium;
|
|
|
+ color: $text-color-primary;
|
|
|
+ font-weight: $font-weight-medium;
|
|
|
+ margin-bottom: $spacing-mini;
|
|
|
+ }
|
|
|
+
|
|
|
+ .room-details {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: $spacing-mini;
|
|
|
+
|
|
|
+ .game-type {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $primary-color;
|
|
|
+ background-color: $background-color-blue;
|
|
|
+ padding: $spacing-mini $spacing-small;
|
|
|
+ border-radius: $border-radius-mini;
|
|
|
+ margin-right: $spacing-base;
|
|
|
+ }
|
|
|
+
|
|
|
+ .room-time {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .game-duration {
|
|
|
+ font-size: $font-size-small;
|
|
|
+ color: $text-color-secondary;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .status-tag {
|
|
|
+ position: absolute;
|
|
|
+ top: $spacing-base;
|
|
|
+ right: $spacing-base;
|
|
|
+ padding: $spacing-mini $spacing-small;
|
|
|
+ border-radius: $border-radius-mini;
|
|
|
+ font-size: $font-size-small;
|
|
|
+ animation: pulse 2s infinite;
|
|
|
+
|
|
|
+ &.playing {
|
|
|
+ background-color: $success-color;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.waiting {
|
|
|
+ background-color: $warning-color;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+
|
|
|
+ &.ended {
|
|
|
+ background-color: $text-color-disabled;
|
|
|
+ color: white;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @keyframes pulse {
|
|
|
+ 0% { opacity: 0.8; }
|
|
|
+ 50% { opacity: 1; }
|
|
|
+ 100% { opacity: 0.8; }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .load-more {
|
|
|
+ margin: $spacing-large 0;
|
|
|
+ text-align: center;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.nut-empty {
|
|
|
+ margin: $spacing-large 0;
|
|
|
+
|
|
|
+ &__description {
|
|
|
+ color: $text-color-secondary;
|
|
|
+ font-size: $font-size-base;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.nut-skeleton {
|
|
|
+ padding: $spacing-base;
|
|
|
+ background-color: $background-color-light;
|
|
|
+ border-radius: $border-radius-base;
|
|
|
+ box-shadow: $shadow-light;
|
|
|
+ margin-bottom: $spacing-base;
|
|
|
+}
|
|
|
+</style>
|