355 lines
8.2 KiB
Vue
355 lines
8.2 KiB
Vue
<template>
|
|
<view class="player-list">
|
|
<navbar title="代练列表" />
|
|
|
|
<view class="content">
|
|
<!-- 搜索和筛选 -->
|
|
<view class="search-section">
|
|
<view class="search-bar">
|
|
<text class="search-icon">🔍</text>
|
|
<input
|
|
class="search-input"
|
|
v-model="searchKeyword"
|
|
placeholder="搜索代练昵称或游戏"
|
|
placeholder-class="placeholder"
|
|
@confirm="handleSearch"
|
|
/>
|
|
</view>
|
|
|
|
<!-- 筛选项 -->
|
|
<view class="filter-bar">
|
|
<view class="filter-item" @click="showGameFilter = true">
|
|
<text class="filter-text">{{ selectedGame || '游戏' }}</text>
|
|
<text class="arrow">▼</text>
|
|
</view>
|
|
<view class="filter-item" @click="showSortFilter = true">
|
|
<text class="filter-text">{{ selectedSort }}</text>
|
|
<text class="arrow">▼</text>
|
|
</view>
|
|
<view class="filter-item" :class="{ active: onlineOnly }" @click="toggleOnline">
|
|
<text class="filter-text">仅在线</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 代练列表 -->
|
|
<scroll-view class="list-scroll" scroll-y @scrolltolower="loadMore">
|
|
<view class="player-list-content">
|
|
<player-card
|
|
v-for="player in filteredPlayers"
|
|
:key="player.id"
|
|
:player="player"
|
|
@click="goToPlayerDetail"
|
|
/>
|
|
|
|
<!-- 空状态 -->
|
|
<empty v-if="filteredPlayers.length === 0" icon="👤" text="暂无代练" description="没有找到符合条件的代练" />
|
|
|
|
<!-- 加载更多 -->
|
|
<view class="load-more" v-if="hasMore && filteredPlayers.length > 0">
|
|
<text>加载更多...</text>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</view>
|
|
|
|
<!-- 游戏筛选弹窗 -->
|
|
<view class="filter-modal" v-if="showGameFilter" @click="showGameFilter = false">
|
|
<view class="filter-content" @click.stop>
|
|
<view class="filter-title">选择游戏</view>
|
|
<view class="filter-options">
|
|
<view
|
|
class="filter-option"
|
|
:class="{ active: selectedGame === '' }"
|
|
@click="selectGame('')"
|
|
>
|
|
全部游戏
|
|
</view>
|
|
<view
|
|
class="filter-option"
|
|
v-for="game in games"
|
|
:key="game"
|
|
:class="{ active: selectedGame === game }"
|
|
@click="selectGame(game)"
|
|
>
|
|
{{ game }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
|
|
<!-- 排序筛选弹窗 -->
|
|
<view class="filter-modal" v-if="showSortFilter" @click="showSortFilter = false">
|
|
<view class="filter-content" @click.stop>
|
|
<view class="filter-title">排序方式</view>
|
|
<view class="filter-options">
|
|
<view
|
|
class="filter-option"
|
|
v-for="sort in sortOptions"
|
|
:key="sort.value"
|
|
:class="{ active: selectedSort === sort.label }"
|
|
@click="selectSort(sort)"
|
|
>
|
|
{{ sort.label }}
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref, computed, onMounted } from 'vue'
|
|
import { useServiceStore, usePlayerStore } from '@/store/modules/service'
|
|
import type { Player } from '@/types'
|
|
import Navbar from '@/components/navbar/index.vue'
|
|
import PlayerCard from '@/components/player-card/index.vue'
|
|
import Empty from '@/components/empty/index.vue'
|
|
|
|
const serviceStore = useServiceStore()
|
|
const playerStore = usePlayerStore()
|
|
|
|
const searchKeyword = ref('')
|
|
const selectedGame = ref('')
|
|
const selectedSort = ref('综合排序')
|
|
const onlineOnly = ref(false)
|
|
const hasMore = ref(false)
|
|
const showGameFilter = ref(false)
|
|
const showSortFilter = ref(false)
|
|
|
|
const players = ref<Player[]>([])
|
|
|
|
// 游戏列表
|
|
const games = ref(['王者荣耀', '英雄联盟', '和平精英', '原神', 'CF'])
|
|
|
|
// 排序选项
|
|
const sortOptions = ref([
|
|
{ label: '综合排序', value: 'default' },
|
|
{ label: '评分最高', value: 'rating' },
|
|
{ label: '接单最多', value: 'orders' },
|
|
{ label: '完成率最高', value: 'completeRate' }
|
|
])
|
|
|
|
// 过滤后的代练列表
|
|
const filteredPlayers = computed(() => {
|
|
let result = [...players.value]
|
|
|
|
// 搜索关键词过滤
|
|
if (searchKeyword.value) {
|
|
const keyword = searchKeyword.value.toLowerCase()
|
|
result = result.filter(
|
|
p => p.name.toLowerCase().includes(keyword) || p.gameName.toLowerCase().includes(keyword)
|
|
)
|
|
}
|
|
|
|
// 游戏过滤
|
|
if (selectedGame.value) {
|
|
result = result.filter(p => p.gameName === selectedGame.value)
|
|
}
|
|
|
|
// 仅在线过滤
|
|
if (onlineOnly.value) {
|
|
result = result.filter(p => p.isOnline)
|
|
}
|
|
|
|
// 排序
|
|
if (selectedSort.value === '评分最高') {
|
|
result.sort((a, b) => b.rating - a.rating)
|
|
} else if (selectedSort.value === '接单最多') {
|
|
result.sort((a, b) => b.orderCount - a.orderCount)
|
|
} else if (selectedSort.value === '完成率最高') {
|
|
result.sort((a, b) => b.completeRate - a.completeRate)
|
|
}
|
|
|
|
return result
|
|
})
|
|
|
|
// 搜索
|
|
const handleSearch = () => {
|
|
console.log('搜索:', searchKeyword.value)
|
|
}
|
|
|
|
// 选择游戏
|
|
const selectGame = (game: string) => {
|
|
selectedGame.value = game
|
|
showGameFilter.value = false
|
|
}
|
|
|
|
// 选择排序
|
|
const selectSort = (sort: { label: string; value: string }) => {
|
|
selectedSort.value = sort.label
|
|
showSortFilter.value = false
|
|
}
|
|
|
|
// 切换仅在线
|
|
const toggleOnline = () => {
|
|
onlineOnly.value = !onlineOnly.value
|
|
}
|
|
|
|
// 跳转到代练详情
|
|
const goToPlayerDetail = (player: Player) => {
|
|
uni.navigateTo({ url: `/pages-user/player/detail?id=${player.id}` })
|
|
}
|
|
|
|
// 加载更多
|
|
const loadMore = () => {
|
|
if (hasMore.value) {
|
|
console.log('加载更多代练...')
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
try {
|
|
players.value = await playerStore.getPlayerList()
|
|
} catch (error) {
|
|
uni.showToast({ title: '加载失败', icon: 'none' })
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
.player-list {
|
|
min-height: 100vh;
|
|
background: $uni-bg-color-grey;
|
|
}
|
|
|
|
.content {
|
|
height: calc(100vh - 88rpx);
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
// 搜索区域
|
|
.search-section {
|
|
background: #fff;
|
|
padding: 20rpx 24rpx;
|
|
border-bottom: 1rpx solid $uni-border-color-light;
|
|
}
|
|
|
|
.search-bar {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 16rpx;
|
|
padding: 16rpx 24rpx;
|
|
background: $uni-bg-color-grey;
|
|
border-radius: 48rpx;
|
|
margin-bottom: 20rpx;
|
|
|
|
.search-icon {
|
|
font-size: 32rpx;
|
|
}
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
font-size: 28rpx;
|
|
color: $uni-text-color;
|
|
}
|
|
|
|
.placeholder {
|
|
color: $uni-text-color-placeholder;
|
|
}
|
|
}
|
|
|
|
.filter-bar {
|
|
display: flex;
|
|
gap: 16rpx;
|
|
}
|
|
|
|
.filter-item {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 8rpx;
|
|
padding: 12rpx 24rpx;
|
|
background: $uni-bg-color-grey;
|
|
border-radius: 32rpx;
|
|
font-size: 24rpx;
|
|
|
|
.filter-text {
|
|
color: $uni-text-color-grey;
|
|
}
|
|
|
|
.arrow {
|
|
font-size: 20rpx;
|
|
color: $uni-text-color-placeholder;
|
|
}
|
|
|
|
&.active {
|
|
background: rgba(102, 126, 234, 0.1);
|
|
|
|
.filter-text {
|
|
color: $uni-color-primary;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 列表区域
|
|
.list-scroll {
|
|
flex: 1;
|
|
padding: 24rpx;
|
|
}
|
|
|
|
.player-list-content {
|
|
min-height: 100%;
|
|
}
|
|
|
|
// 加载更多
|
|
.load-more {
|
|
padding: 32rpx;
|
|
text-align: center;
|
|
font-size: 24rpx;
|
|
color: $uni-text-color-placeholder;
|
|
}
|
|
|
|
// 筛选弹窗
|
|
.filter-modal {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
align-items: flex-end;
|
|
z-index: 9999;
|
|
}
|
|
|
|
.filter-content {
|
|
width: 100%;
|
|
max-height: 70vh;
|
|
background: #fff;
|
|
border-radius: 24rpx 24rpx 0 0;
|
|
padding: 32rpx;
|
|
padding-bottom: calc(32rpx + env(safe-area-inset-bottom));
|
|
}
|
|
|
|
.filter-title {
|
|
font-size: 32rpx;
|
|
font-weight: bold;
|
|
color: $uni-text-color;
|
|
margin-bottom: 32rpx;
|
|
text-align: center;
|
|
}
|
|
|
|
.filter-options {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8rpx;
|
|
}
|
|
|
|
.filter-option {
|
|
padding: 24rpx;
|
|
background: $uni-bg-color-grey;
|
|
border-radius: $uni-border-radius-base;
|
|
font-size: 28rpx;
|
|
color: $uni-text-color-grey;
|
|
text-align: center;
|
|
|
|
&.active {
|
|
background: rgba(102, 126, 234, 0.1);
|
|
color: $uni-color-primary;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
</style>
|