|
|
|
@ -5,7 +5,7 @@ |
|
|
|
<view class="nav-title">星球擂台</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<scroll-view scroll-y class="page" :style="{paddingTop: (navHeight + 10) + 'px'}" @scrolltolower="loadMoreHotRooms"> |
|
|
|
<scroll-view scroll-y class="page" :style="{paddingTop: (navHeight + 10) + 'px'}" @scrolltolower="loadMoreActive"> |
|
|
|
<view class="hero"> |
|
|
|
<view class="hero-kicker">CAMPUS ARENA</view> |
|
|
|
<view class="hero-title">同一关卡,拼手速和决策</view> |
|
|
|
@ -13,30 +13,52 @@ |
|
|
|
<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 class="arena-tabs"> |
|
|
|
<view class="arena-tab" :class="{active: activeTab === 'hotRooms'}" @tap="switchTab('hotRooms')">热门房间</view> |
|
|
|
<view class="arena-tab" :class="{active: activeTab === 'myRooms'}" @tap="switchTab('myRooms')">我的房间</view> |
|
|
|
<view class="arena-tab" :class="{active: activeTab === 'myRecords'}" @tap="switchTab('myRecords')">我的战绩</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="section hot-section" v-if="activeTab === 'myRooms'"> |
|
|
|
<view class="section-head"> |
|
|
|
<text>我的房间</text> |
|
|
|
<text @tap="loadMyRooms(true)">刷新</text> |
|
|
|
</view> |
|
|
|
<view class="room-card" v-for="room in myRooms" :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}} 券 · {{room._statusText}}</view> |
|
|
|
</view> |
|
|
|
<view class="room-pool"> |
|
|
|
<text>{{room.poolTickets || 0}}</text> |
|
|
|
<text>奖池</text> |
|
|
|
</view> |
|
|
|
<view class="empty small" v-if="!myRooms.length">暂无房间</view> |
|
|
|
<button class="share-mini" open-type="share" @tap.stop="setShareRoom(room)">分享</button> |
|
|
|
</view> |
|
|
|
<view class="empty" v-if="!myRooms.length && !myRoomsLoading">暂无房间,先开一间等同学来挑战</view> |
|
|
|
<view class="load-more" v-if="myRooms.length">{{myRoomsLoadText}}</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="section hot-section" v-if="activeTab === 'myRecords'"> |
|
|
|
<view class="section-head"> |
|
|
|
<text>我的战绩</text> |
|
|
|
<text @tap="loadMyRecords(true)">刷新</text> |
|
|
|
</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 class="record-card" v-for="record in myRecords" :key="record._key"> |
|
|
|
<view class="record-main"> |
|
|
|
<view class="record-title">{{record._title}}</view> |
|
|
|
<view class="record-meta">{{record._meta}}</view> |
|
|
|
</view> |
|
|
|
<view class="empty small" v-if="!myRecords.length">暂无战绩</view> |
|
|
|
<view class="record-badge" :class="record._class">{{record._result}}</view> |
|
|
|
</view> |
|
|
|
<view class="empty" v-if="!myRecords.length && !myRecordsLoading">暂无战绩,去擂台打一局</view> |
|
|
|
<view class="load-more" v-if="myRecords.length">{{myRecordsLoadText}}</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="section hot-section"> |
|
|
|
<view class="section hot-section" v-if="activeTab === 'hotRooms'"> |
|
|
|
<view class="section-head"> |
|
|
|
<text>热门房间</text> |
|
|
|
<text @tap="loadHall">刷新</text> |
|
|
|
<text @tap="loadHotRooms(true)">刷新</text> |
|
|
|
</view> |
|
|
|
<view class="room-card" v-for="room in hotRooms" :key="room._key" @tap="joinRoom(room)"> |
|
|
|
<view class="room-main"> |
|
|
|
@ -49,7 +71,7 @@ |
|
|
|
</view> |
|
|
|
<button class="share-mini" open-type="share" @tap.stop="setShareRoom(room)">邀请</button> |
|
|
|
</view> |
|
|
|
<view class="empty" v-if="!hotRooms.length">还没有公开擂台,先开一间等同学来挑战</view> |
|
|
|
<view class="empty" v-if="!hotRooms.length && !hotLoading">还没有公开擂台,先开一间等同学来挑战</view> |
|
|
|
<view class="load-more" v-if="hotRooms.length">{{hotLoadText}}</view> |
|
|
|
</view> |
|
|
|
</scroll-view> |
|
|
|
@ -81,6 +103,7 @@ |
|
|
|
nickname: '', |
|
|
|
avatar: '', |
|
|
|
college: '', |
|
|
|
activeTab: 'hotRooms', |
|
|
|
hotRooms: [], |
|
|
|
myRooms: [], |
|
|
|
myRecords: [], |
|
|
|
@ -88,12 +111,20 @@ |
|
|
|
hotPageSize: 10, |
|
|
|
hotTotalPages: 1, |
|
|
|
hotLoading: false, |
|
|
|
myRoomsPageNum: 1, |
|
|
|
myRoomsPageSize: 10, |
|
|
|
myRoomsTotalPages: 1, |
|
|
|
myRoomsLoading: false, |
|
|
|
myRecordsPageNum: 1, |
|
|
|
myRecordsPageSize: 10, |
|
|
|
myRecordsTotalPages: 1, |
|
|
|
myRecordsLoading: false, |
|
|
|
showCreate: false, |
|
|
|
shareRoom: null, |
|
|
|
form: { |
|
|
|
roomName: '今晚冲榜局', |
|
|
|
maxPlayers: 2, |
|
|
|
tickets: 1, |
|
|
|
maxPlayers: '', |
|
|
|
tickets: '', |
|
|
|
password: '' |
|
|
|
} |
|
|
|
} |
|
|
|
@ -103,6 +134,16 @@ |
|
|
|
if (this.hotLoading) return '正在加载更多房间...' |
|
|
|
if (this.hotPageNum >= this.hotTotalPages) return '没有更多擂台了' |
|
|
|
return '上滑加载更多擂台' |
|
|
|
}, |
|
|
|
myRoomsLoadText() { |
|
|
|
if (this.myRoomsLoading) return '正在加载我的房间...' |
|
|
|
if (this.myRoomsPageNum >= this.myRoomsTotalPages) return '没有更多房间了' |
|
|
|
return '上滑加载更多房间' |
|
|
|
}, |
|
|
|
myRecordsLoadText() { |
|
|
|
if (this.myRecordsLoading) return '正在加载我的战绩...' |
|
|
|
if (this.myRecordsPageNum >= this.myRecordsTotalPages) return '没有更多战绩了' |
|
|
|
return '上滑加载更多战绩' |
|
|
|
} |
|
|
|
}, |
|
|
|
onLoad(options) { |
|
|
|
@ -126,7 +167,11 @@ |
|
|
|
if (area) this.regionId = JSON.parse(area).id || '' |
|
|
|
} catch (e) {} |
|
|
|
this.college = uni.getStorageSync('planetCollege_' + this.regionId) || '' |
|
|
|
if (this.regionId) this.loadHall() |
|
|
|
if (this.regionId) { |
|
|
|
this.loadMyRooms(true) |
|
|
|
this.loadMyRecords(true) |
|
|
|
this.loadHotRooms(true) |
|
|
|
} |
|
|
|
if (options.roomId) { |
|
|
|
this.joinRoom({ id: options.roomId }) |
|
|
|
} |
|
|
|
@ -150,54 +195,93 @@ |
|
|
|
} 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') |
|
|
|
} |
|
|
|
}) |
|
|
|
switchTab(tab) { |
|
|
|
this.activeTab = tab |
|
|
|
if (tab === 'myRooms' && !this.myRooms.length) this.loadMyRooms(true) |
|
|
|
if (tab === 'myRecords' && !this.myRecords.length) this.loadMyRecords(true) |
|
|
|
if (tab === 'hotRooms' && !this.hotRooms.length) this.loadHotRooms(true) |
|
|
|
}, |
|
|
|
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', { |
|
|
|
loadPageList(type, reset) { |
|
|
|
const config = { |
|
|
|
myRooms: { |
|
|
|
url: '/app/planet/adventure/pk/myRooms', |
|
|
|
listKey: 'myRooms', |
|
|
|
pageKey: 'myRoomsPageNum', |
|
|
|
sizeKey: 'myRoomsPageSize', |
|
|
|
totalKey: 'myRoomsTotalPages', |
|
|
|
loadingKey: 'myRoomsLoading', |
|
|
|
prefix: 'mine' |
|
|
|
}, |
|
|
|
myRecords: { |
|
|
|
url: '/app/planet/adventure/pk/myRecords', |
|
|
|
listKey: 'myRecords', |
|
|
|
pageKey: 'myRecordsPageNum', |
|
|
|
sizeKey: 'myRecordsPageSize', |
|
|
|
totalKey: 'myRecordsTotalPages', |
|
|
|
loadingKey: 'myRecordsLoading', |
|
|
|
prefix: 'record' |
|
|
|
}, |
|
|
|
hotRooms: { |
|
|
|
url: '/app/planet/adventure/pk/hotRooms', |
|
|
|
listKey: 'hotRooms', |
|
|
|
pageKey: 'hotPageNum', |
|
|
|
sizeKey: 'hotPageSize', |
|
|
|
totalKey: 'hotTotalPages', |
|
|
|
loadingKey: 'hotLoading', |
|
|
|
prefix: 'hot' |
|
|
|
} |
|
|
|
}[type] |
|
|
|
if (!config || this[config.loadingKey]) return |
|
|
|
if (!reset && this[config.pageKey] >= this[config.totalKey]) return |
|
|
|
const nextPage = reset ? 1 : this[config.pageKey] + 1 |
|
|
|
if (reset) { |
|
|
|
this[config.pageKey] = 1 |
|
|
|
this[config.totalKey] = 1 |
|
|
|
this[config.listKey] = [] |
|
|
|
} |
|
|
|
this[config.loadingKey] = true |
|
|
|
this.tui.request(config.url, 'POST', { |
|
|
|
userId: this.userId, |
|
|
|
regionId: this.regionId, |
|
|
|
pageNumber: nextPage, |
|
|
|
pageSize: this.hotPageSize |
|
|
|
pageSize: this[config.sizeKey] |
|
|
|
}, false, false, true).then(res => { |
|
|
|
this.hotLoading = false |
|
|
|
this[config.loadingKey] = 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)) |
|
|
|
const records = this.withKeys(res.result.records || [], config.prefix + '_' + nextPage) |
|
|
|
this[config.listKey] = reset ? records : this[config.listKey].concat(records) |
|
|
|
this[config.pageKey] = Number(res.result.current || nextPage) |
|
|
|
this[config.totalKey] = Math.max(1, Number(res.result.pages || 1)) |
|
|
|
} |
|
|
|
}).catch(() => { |
|
|
|
this.hotLoading = false |
|
|
|
this[config.loadingKey] = false |
|
|
|
}) |
|
|
|
}, |
|
|
|
loadMoreHotRooms() { |
|
|
|
this.loadHotRooms(false) |
|
|
|
loadMyRooms(reset) { |
|
|
|
this.loadPageList('myRooms', reset) |
|
|
|
}, |
|
|
|
loadMyRecords(reset) { |
|
|
|
this.loadPageList('myRecords', reset) |
|
|
|
}, |
|
|
|
loadHotRooms(reset) { |
|
|
|
this.loadPageList('hotRooms', reset) |
|
|
|
}, |
|
|
|
loadMoreActive() { |
|
|
|
if (this.activeTab === 'myRooms') this.loadMyRooms(false) |
|
|
|
else if (this.activeTab === 'myRecords') this.loadMyRecords(false) |
|
|
|
else this.loadHotRooms(false) |
|
|
|
}, |
|
|
|
withKeys(list, prefix) { |
|
|
|
return list.map((item, index) => { |
|
|
|
item.password = '' |
|
|
|
item._key = item.id || (prefix + '_' + index) |
|
|
|
item._statusText = this.roomStatus(item.status) |
|
|
|
if (prefix.indexOf('record') === 0) { |
|
|
|
item._title = this.recordTitle(item) |
|
|
|
item._meta = this.recordMeta(item) |
|
|
|
item._result = this.recordResult(item) |
|
|
|
item._class = this.recordClass(item) |
|
|
|
} |
|
|
|
return item |
|
|
|
}) |
|
|
|
}, |
|
|
|
@ -222,7 +306,9 @@ |
|
|
|
return |
|
|
|
} |
|
|
|
this.showCreate = false |
|
|
|
this.loadHall() |
|
|
|
this.activeTab = 'myRooms' |
|
|
|
this.loadMyRooms(true) |
|
|
|
this.loadHotRooms(true) |
|
|
|
this.joinRoom(res.result) |
|
|
|
}) |
|
|
|
}, |
|
|
|
@ -251,6 +337,29 @@ |
|
|
|
if (status === 3) return '已取消' |
|
|
|
return '等待中' |
|
|
|
}, |
|
|
|
recordTitle(record) { |
|
|
|
if (record.cleared === 1) return (record.durationSeconds || 0) + '秒通关' |
|
|
|
return '挑战失败' |
|
|
|
}, |
|
|
|
recordMeta(record) { |
|
|
|
const ticketText = '入场 ' + (record.entryTickets || 0) + ' 券' |
|
|
|
if (record.rewardTickets > 0) return ticketText + ' · 奖励 +' + record.rewardTickets |
|
|
|
return ticketText + ' · ' + (record.finishTime || record.createTime || '') |
|
|
|
}, |
|
|
|
recordResult(record) { |
|
|
|
if (record.status === 1 || record.status === 0) return '待结算' |
|
|
|
if (record.rewardTickets > 0) return '胜利' |
|
|
|
if (record.status === 2 && record.cleared === 1 && record.rankNo === 1) return '胜利' |
|
|
|
if ((record.status === 2 || record.status === 3 || record.status === 4) && record.rewardTickets === record.entryTickets && (!record.rankNo || record.rankNo === 0)) return '无人通关' |
|
|
|
return '失败' |
|
|
|
}, |
|
|
|
recordClass(record) { |
|
|
|
const result = this.recordResult(record) |
|
|
|
if (result === '胜利') return 'win' |
|
|
|
if (result === '无人通关') return 'refund' |
|
|
|
if (result === '待结算') return 'pending' |
|
|
|
return 'lose' |
|
|
|
}, |
|
|
|
goBack() { |
|
|
|
const pages = getCurrentPages ? getCurrentPages() : [] |
|
|
|
if (pages.length > 1) { |
|
|
|
@ -277,6 +386,9 @@ |
|
|
|
.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); } |
|
|
|
.arena-tabs { margin-bottom: 24rpx; padding: 8rpx; border-radius: 999rpx; background: rgba(255,255,255,.72); border: 2rpx solid rgba(255,255,255,.9); display: flex; gap: 8rpx; box-shadow: 0 14rpx 34rpx rgba(124,58,237,.08); } |
|
|
|
.arena-tab { flex: 1; height: 66rpx; line-height: 66rpx; border-radius: 999rpx; text-align: center; color: #667085; font-size: 24rpx; font-weight: 900; } |
|
|
|
.arena-tab.active { color: #fff; background: linear-gradient(135deg, #7C3AED, #38BDF8); box-shadow: 0 12rpx 26rpx 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); } |
|
|
|
@ -293,6 +405,15 @@ |
|
|
|
.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; } |
|
|
|
.record-card { margin-top: 16rpx; padding: 24rpx; border-radius: 30rpx; background: linear-gradient(135deg, rgba(255,255,255,.94), rgba(247,250,255,.84)); display: flex; align-items: center; justify-content: space-between; border: 2rpx solid rgba(124,58,237,.10); } |
|
|
|
.record-main { flex: 1; min-width: 0; } |
|
|
|
.record-title { color: #172033; font-size: 29rpx; font-weight: 900; } |
|
|
|
.record-meta { margin-top: 8rpx; color: #667085; font-size: 22rpx; } |
|
|
|
.record-badge { margin-left: 18rpx; min-width: 110rpx; height: 58rpx; line-height: 58rpx; border-radius: 999rpx; text-align: center; font-size: 23rpx; font-weight: 900; background: #EEF2FF; color: #7C3AED; } |
|
|
|
.record-badge.win { background: linear-gradient(135deg, #FFB84D, #FF7A59); color: #fff; box-shadow: 0 12rpx 24rpx rgba(255,122,89,.18); } |
|
|
|
.record-badge.lose { background: #FEE2E2; color: #EF4444; } |
|
|
|
.record-badge.refund { background: #E0F2FE; color: #0284C7; } |
|
|
|
.record-badge.pending { background: #F4F3FF; color: #7C3AED; } |
|
|
|
.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; } |
|
|
|
|