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.

307 lines
14 KiB

2 days ago
<template>
<view class="arena">
<view class="nav" :style="{height: navHeight + 'px', paddingTop: statusBarHeight + 'px'}">
<view class="nav-back" @tap="goBack"><text></text></view>
<view class="nav-title">星球擂台</view>
</view>
<scroll-view scroll-y class="page" :style="{paddingTop: (navHeight + 10) + 'px'}" @scrolltolower="loadMoreHotRooms">
<view class="hero">
<view class="hero-kicker">CAMPUS ARENA</view>
<view class="hero-title">同一关卡拼手速和决策</view>
<view class="hero-sub">独立于每日助推赛房间内所有人使用同一个 seed每人一次机会第一名通吃奖池</view>
<view class="create-btn" @tap="showCreate = true">创建房间</view>
</view>
<view class="section duo">
<view class="panel">
<view class="section-head"><text>我的房间</text></view>
<view class="mini-row" v-for="room in myRooms" :key="room._key" @tap="joinRoom(room)">
<text>{{room.roomName || '星球擂台'}}</text>
<text>{{roomStatus(room.status)}}</text>
<button class="mini-share" open-type="share" @tap.stop="setShareRoom(room)">分享</button>
</view>
<view class="empty small" v-if="!myRooms.length">暂无房间</view>
</view>
<view class="panel">
<view class="section-head"><text>我的战绩</text></view>
<view class="mini-row" v-for="record in myRecords" :key="record._key">
<text>{{record.cleared ? (record.durationSeconds + '秒通关') : '挑战失败'}}</text>
<text>{{record.rankNo ? ('第' + record.rankNo) : '待结算'}}</text>
</view>
<view class="empty small" v-if="!myRecords.length">暂无战绩</view>
</view>
</view>
<view class="section hot-section">
<view class="section-head">
<text>热门房间</text>
<text @tap="loadHall">刷新</text>
</view>
<view class="room-card" v-for="room in hotRooms" :key="room._key" @tap="joinRoom(room)">
<view class="room-main">
<view class="room-name">{{room.roomName || '星球擂台'}}</view>
<view class="room-meta">{{room.playerCount || 0}}/{{room.maxPlayers || 2}} · 入场 {{room.entryTickets || 1}} </view>
</view>
<view class="room-pool">
<text>{{room.poolTickets || 0}}</text>
<text>奖池</text>
</view>
<button class="share-mini" open-type="share" @tap.stop="setShareRoom(room)">邀请</button>
</view>
<view class="empty" v-if="!hotRooms.length">还没有公开擂台先开一间等同学来挑战</view>
<view class="load-more" v-if="hotRooms.length">{{hotLoadText}}</view>
</view>
</scroll-view>
<view class="modal" v-if="showCreate">
<view class="modal-card">
<view class="modal-title">创建星球擂台</view>
<input class="field" v-model="form.roomName" placeholder="房间名称" />
<input class="field" v-model.number="form.maxPlayers" type="number" placeholder="人数 2-5" />
<input class="field" v-model.number="form.tickets" type="number" placeholder="入场券数量" />
<input class="field" v-model="form.password" placeholder="私密房密码,不填则公开" />
<view class="modal-actions">
<view class="sub-btn" @tap="showCreate = false">取消</view>
<view class="main-btn" @tap="createRoom">创建</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
statusBarHeight: 20,
navHeight: 64,
userId: '',
regionId: '',
nickname: '',
avatar: '',
college: '',
hotRooms: [],
myRooms: [],
myRecords: [],
hotPageNum: 1,
hotPageSize: 10,
hotTotalPages: 1,
hotLoading: false,
showCreate: false,
shareRoom: null,
form: {
roomName: '今晚冲榜局',
maxPlayers: 2,
tickets: 1,
password: ''
}
}
},
computed: {
hotLoadText() {
if (this.hotLoading) return '正在加载更多房间...'
if (this.hotPageNum >= this.hotTotalPages) return '没有更多擂台了'
return '上滑加载更多擂台'
}
},
onLoad(options) {
const sys = uni.getSystemInfoSync()
this.statusBarHeight = sys.statusBarHeight || 20
this.initNavHeight()
options = options || {}
if (!uni.getStorageSync('id')) {
const path = options.roomId ? ('/package1/planet/pkHall?roomId=' + options.roomId) : '/package1/planet/pkHall'
uni.setStorageSync('planetPendingSharePath', path)
uni.redirectTo({
url: '/package2/login/login?redirect=planetPendingSharePath'
})
return
}
this.userId = uni.getStorageSync('id') || ''
this.nickname = uni.getStorageSync('nickName') || uni.getStorageSync('nickname') || ''
this.avatar = uni.getStorageSync('avatarUrl') || uni.getStorageSync('avatar') || ''
try {
const area = uni.getStorageSync('area')
if (area) this.regionId = JSON.parse(area).id || ''
} catch (e) {}
this.college = uni.getStorageSync('planetCollege_' + this.regionId) || ''
if (this.regionId) this.loadHall()
if (options.roomId) {
this.joinRoom({ id: options.roomId })
}
},
onShareAppMessage() {
const room = this.shareRoom || {}
const roomId = room.id || ''
return {
title: `星球擂台开战:${room.roomName || '同一关卡来PK'}`,
path: '/package1/planet/adventure?mode=pk&roomId=' + roomId
}
},
methods: {
initNavHeight() {
try {
const menu = uni.getMenuButtonBoundingClientRect && uni.getMenuButtonBoundingClientRect()
if (menu && menu.top && menu.height) {
this.navHeight = menu.top + menu.height + 8
return
}
} catch (e) {}
this.navHeight = this.statusBarHeight + 44
},
loadHall() {
this.hotPageNum = 1
this.hotTotalPages = 1
this.hotRooms = []
this.tui.request('/app/planet/adventure/pk/hall', 'POST', {
userId: this.userId,
regionId: this.regionId,
pageNumber: 1,
pageSize: this.hotPageSize
}, false, false, true).then(res => {
if (res.code == 200 && res.result) {
this.hotRooms = this.withKeys(res.result.hotRooms || [], 'hot_1')
this.hotPageNum = Number(res.result.hotPageNumber || 1)
this.hotTotalPages = Math.max(1, Number(res.result.hotTotalPages || 1))
this.myRooms = this.withKeys(res.result.myRooms || [], 'mine')
this.myRecords = this.withKeys(res.result.myRecords || [], 'record')
}
})
},
loadHotRooms(reset) {
if (this.hotLoading) return
if (!reset && this.hotPageNum >= this.hotTotalPages) return
const nextPage = reset ? 1 : this.hotPageNum + 1
this.hotLoading = true
this.tui.request('/app/planet/adventure/pk/hall', 'POST', {
userId: this.userId,
regionId: this.regionId,
pageNumber: nextPage,
pageSize: this.hotPageSize
}, false, false, true).then(res => {
this.hotLoading = false
if (res.code == 200 && res.result) {
const list = this.withKeys(res.result.hotRooms || [], 'hot_' + nextPage)
this.hotRooms = reset ? list : [...this.hotRooms, ...list]
this.hotPageNum = Number(res.result.hotPageNumber || nextPage)
this.hotTotalPages = Math.max(1, Number(res.result.hotTotalPages || 1))
}
}).catch(() => {
this.hotLoading = false
})
},
loadMoreHotRooms() {
this.loadHotRooms(false)
},
withKeys(list, prefix) {
return list.map((item, index) => {
item.password = ''
item._key = item.id || (prefix + '_' + index)
return item
})
},
setShareRoom(room) {
this.shareRoom = room
},
createRoom() {
this.tui.request('/app/planet/adventure/pk/create', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomName: this.form.roomName,
maxPlayers: this.form.maxPlayers,
publicFlag: this.form.password ? 0 : 1,
password: this.form.password,
tickets: this.form.tickets
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
this.showCreate = false
this.loadHall()
this.joinRoom(res.result)
})
},
joinRoom(room) {
this.tui.request('/app/planet/adventure/pk/join', 'POST', {
userId: this.userId,
regionId: this.regionId,
nickname: this.nickname,
avatar: this.avatar,
college: this.college,
roomId: room.id,
password: room.password || ''
}).then(res => {
if (res.code != 200 || !res.result) {
this.tui.toast(res.message)
return
}
uni.navigateTo({
url: '/package1/planet/adventure?mode=pk&roomId=' + room.id + '&seed=' + encodeURIComponent(res.result.seed || '')
})
})
},
roomStatus(status) {
if (status === 2) return '已结算'
if (status === 1) return '进行中'
if (status === 3) return '已取消'
return '等待中'
},
goBack() {
const pages = getCurrentPages ? getCurrentPages() : []
if (pages.length > 1) {
uni.navigateBack({ delta: 1 })
return
}
uni.redirectTo({ url: '/package1/planet/index' })
}
}
}
</script>
<style lang="scss" scoped>
.arena { min-height: 100vh; background: linear-gradient(155deg, #F7F2FF 0%, #EAF8FF 46%, #FFF7DE 100%); color: #172033; }
.nav { position: fixed; top: 0; left: 0; right: 0; z-index: 20; box-sizing: border-box; display: flex; align-items: center; justify-content: center; background: rgba(247,242,255,.9); }
.nav-back { position: absolute; left: 24rpx; bottom: 12rpx; width: 56rpx; height: 56rpx; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.72); color: #172033; box-shadow: 0 8rpx 20rpx rgba(23,32,51,.08); }
.nav-back text { font-size: 42rpx; line-height: 1; transform: translateY(-2rpx); }
.nav-title { padding-bottom: 14rpx; font-size: 32rpx; font-weight: 900; }
.page { height: 100vh; box-sizing: border-box; padding-left: 24rpx; padding-right: 24rpx; }
.hero, .section, .panel { margin-bottom: 24rpx; border-radius: 42rpx; background: rgba(255,255,255,.84); padding: 30rpx; box-shadow: 0 18rpx 48rpx rgba(124,58,237,.10); }
.hot-section { margin-bottom: 46rpx; }
.hero { background: radial-gradient(circle at 90% 10%, rgba(124,58,237,.22), transparent 36%), linear-gradient(135deg, rgba(255,255,255,.96), rgba(232,246,255,.78)); }
.hero-kicker { color: #7C3AED; font-size: 22rpx; font-weight: 900; letter-spacing: 2rpx; }
.hero-title { margin-top: 10rpx; font-size: 42rpx; font-weight: 900; }
.hero-sub { margin-top: 14rpx; color: #667085; font-size: 24rpx; line-height: 1.55; }
.create-btn, .main-btn { margin-top: 22rpx; height: 76rpx; line-height: 76rpx; border-radius: 999rpx; text-align: center; color: #fff; font-size: 28rpx; font-weight: 900; background: linear-gradient(135deg, #7C3AED, #38BDF8); box-shadow: 0 16rpx 34rpx rgba(124,58,237,.18); }
.section-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 18rpx; color: #7C3AED; font-size: 23rpx; font-weight: 900; }
.section-head text:first-child { color: #172033; font-size: 31rpx; }
.room-card { margin-top: 16rpx; padding: 22rpx; border-radius: 30rpx; background: linear-gradient(135deg, rgba(255,255,255,.92), rgba(238,247,255,.82)); display: flex; align-items: center; justify-content: space-between; border: 2rpx solid rgba(124,58,237,.10); }
.room-main { flex: 1; min-width: 0; }
.room-name { font-size: 29rpx; font-weight: 900; }
.room-meta { margin-top: 8rpx; color: #667085; font-size: 22rpx; }
.room-pool { min-width: 108rpx; height: 88rpx; border-radius: 26rpx; background: #FFF3D7; color: #B7791F; display: flex; flex-direction: column; align-items: center; justify-content: center; font-weight: 900; }
.room-pool text:first-child { font-size: 32rpx; }
.room-pool text:last-child { font-size: 19rpx; margin-top: 4rpx; }
.share-mini { margin: 0 0 0 14rpx; padding: 0 18rpx; min-width: 0; height: 56rpx; line-height: 56rpx; border-radius: 999rpx; background: #EEF2FF; color: #7C3AED; font-size: 22rpx; font-weight: 900; }
.share-mini:after, .mini-share:after { border: 0; }
.duo { display: flex; gap: 18rpx; background: transparent; box-shadow: none; padding: 0; }
.panel { flex: 1; min-width: 0; margin-bottom: 0; padding: 22rpx; border-radius: 34rpx; }
.mini-row { margin-top: 14rpx; padding: 16rpx; border-radius: 22rpx; background: rgba(248,250,252,.9); display: flex; justify-content: space-between; gap: 12rpx; font-size: 22rpx; color: #667085; }
.mini-row text:first-child { color: #172033; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mini-share { margin: 0; padding: 0 14rpx; min-width: 0; height: 40rpx; line-height: 40rpx; border-radius: 999rpx; background: #F4F3FF; color: #7C3AED; font-size: 18rpx; font-weight: 900; }
.empty { margin-top: 20rpx; color: #8A94A6; font-size: 24rpx; }
.empty.small { font-size: 21rpx; }
.load-more { margin-top: 24rpx; height: 58rpx; line-height: 58rpx; text-align: center; border-radius: 999rpx; background: rgba(238,242,255,.76); color: #7C3AED; font-size: 23rpx; font-weight: 900; }
.modal { position: fixed; inset: 0; z-index: 99; background: rgba(23,32,51,.22); display: flex; align-items: center; justify-content: center; padding: 46rpx; }
.modal-card { width: 100%; border-radius: 42rpx; background: #fff; padding: 36rpx; }
.modal-title { text-align: center; font-size: 36rpx; font-weight: 900; margin-bottom: 22rpx; }
.field { height: 78rpx; margin-bottom: 16rpx; padding: 0 22rpx; border-radius: 22rpx; background: #F5F7FB; font-size: 25rpx; }
.modal-actions { display: flex; gap: 16rpx; margin-top: 10rpx; }
.sub-btn, .main-btn { flex: 1; margin-top: 0; height: 76rpx; line-height: 76rpx; border-radius: 999rpx; text-align: center; font-size: 27rpx; font-weight: 900; }
.sub-btn { background: #F2F4F7; color: #667085; }
</style>