998 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			998 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Vue
		
	
	
	
<template>
 | 
						||
  <view>
 | 
						||
    <!-- 直推人数排行榜弹窗 -->
 | 
						||
    <u-popup
 | 
						||
      class="ranking-popup"
 | 
						||
      mode="center"
 | 
						||
      :show="showPeopleRanking"
 | 
						||
      :closeOnClickOverlay="false"
 | 
						||
      border-radius="20"
 | 
						||
    >
 | 
						||
      <view style="width: 90vw; height: 85vh" class="popup-container">
 | 
						||
        <!-- 弹窗头部 -->
 | 
						||
        <view class="popup-header">
 | 
						||
          <view class="header-title">直推人数排行榜</view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 前三名特殊展示区域 -->
 | 
						||
        <view class="top-three-section">
 | 
						||
          <view class="podium-container">
 | 
						||
            <!-- 第二名 -->
 | 
						||
            <view class="podium-item second-place" v-if="peopleTopThree[1]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-2.svg" alt="" />
 | 
						||
                </view>
 | 
						||
                <!-- <view class="member-code">{{
 | 
						||
                  peopleTopThree[1].memberCode
 | 
						||
                }}</view> -->
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: peopleTopThree[1].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ peopleTopThree[1].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
 | 
						||
                <view class="score">{{ peopleTopThree[1].count }}人</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
 | 
						||
            <!-- 第一名 -->
 | 
						||
            <view class="podium-item first-place" v-if="peopleTopThree[0]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-1.svg" alt="" />
 | 
						||
                </view>
 | 
						||
 | 
						||
                <!-- <view class="member-code">
 | 
						||
                  {{ peopleTopThree[0].memberCode }}
 | 
						||
                </view> -->
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: peopleTopThree[0].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ peopleTopThree[0].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
                <view class="score">{{ peopleTopThree[0].count }}人</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
 | 
						||
            <!-- 第三名 -->
 | 
						||
            <view class="podium-item third-place" v-if="peopleTopThree[2]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-3.svg" alt="" />
 | 
						||
                </view>
 | 
						||
                <!-- <view class="member-code">{{
 | 
						||
                  peopleTopThree[2].memberCode
 | 
						||
                }}</view> -->
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: peopleTopThree[2].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ peopleTopThree[2].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
 | 
						||
                <view class="score">{{ peopleTopThree[2].count }}人</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 4-30名滚动列表 -->
 | 
						||
        <view class="ranking-list">
 | 
						||
          <scroll-view
 | 
						||
            class="scroll-container"
 | 
						||
            scroll-y="true"
 | 
						||
            :show-scrollbar="false"
 | 
						||
          >
 | 
						||
            <view
 | 
						||
              class="list-item"
 | 
						||
              v-for="(item, index) in peopleRemainingList"
 | 
						||
              :key="index"
 | 
						||
            >
 | 
						||
              <view class="item-rank">{{ index + 4 }}</view>
 | 
						||
              <view class="item-info">
 | 
						||
                <!-- <view class="item-code">{{ item.memberCode }}</view> -->
 | 
						||
                <view
 | 
						||
                  class="item-name"
 | 
						||
                  :class="{ highlight: item.isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ item.memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
              </view>
 | 
						||
              <view class="item-score">
 | 
						||
                <span>{{ item.count }}</span>
 | 
						||
                <span>人</span>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
            <view class="list-footer" v-if="peopleRemainingList.length === 0">
 | 
						||
              <text class="empty-text">暂无更多数据</text>
 | 
						||
            </view>
 | 
						||
          </scroll-view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 底部关闭按钮 -->
 | 
						||
        <view class="popup-footer">
 | 
						||
          <view class="close-text-btn" @click="closePeopleRanking">
 | 
						||
            关 闭
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </u-popup>
 | 
						||
 | 
						||
    <!-- 直推金额排行榜弹窗 -->
 | 
						||
    <u-popup
 | 
						||
      class="ranking-popup"
 | 
						||
      width="85%"
 | 
						||
      height="85%"
 | 
						||
      mode="center"
 | 
						||
      :show="showAmountRanking"
 | 
						||
      :closeOnClickOverlay="false"
 | 
						||
      border-radius="20"
 | 
						||
    >
 | 
						||
      <view style="width: 90vw; height: 85vh" class="popup-container">
 | 
						||
        <!-- 弹窗头部 -->
 | 
						||
        <view class="popup-header">
 | 
						||
          <view class="header-title">直推金额排行榜</view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 前三名特殊展示区域 -->
 | 
						||
        <view class="top-three-section">
 | 
						||
          <view class="podium-container">
 | 
						||
            <!-- 第二名 -->
 | 
						||
            <view class="podium-item second-place" v-if="amountTopThree[1]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-2.svg" alt="" />
 | 
						||
                </view>
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: amountTopThree[1].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ amountTopThree[1].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
                <!-- <view class="member-code">{{
 | 
						||
                  amountTopThree[1].memberCode
 | 
						||
                }}</view> -->
 | 
						||
                <view class="score">{{
 | 
						||
                  formatAmount(amountTopThree[1].amount)
 | 
						||
                }}</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
 | 
						||
            <!-- 第一名 -->
 | 
						||
            <view class="podium-item first-place" v-if="amountTopThree[0]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-1.svg" alt="" />
 | 
						||
                </view>
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: amountTopThree[0].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ amountTopThree[0].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
                <!-- <view class="member-code">{{
 | 
						||
                  amountTopThree[0].memberCode
 | 
						||
                }}</view> -->
 | 
						||
                <view class="score">{{
 | 
						||
                  formatAmount(amountTopThree[0].amount)
 | 
						||
                }}</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
 | 
						||
            <!-- 第三名 -->
 | 
						||
            <view class="podium-item third-place" v-if="amountTopThree[2]">
 | 
						||
              <view class="player-area">
 | 
						||
                <view class="rank-number">
 | 
						||
                  <img src="@/static/images/rank-3.svg" alt="" />
 | 
						||
                </view>
 | 
						||
                <view
 | 
						||
                  class="member-name"
 | 
						||
                  :class="{ highlight: amountTopThree[2].isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ amountTopThree[2].memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
                <!-- <view class="member-code">{{
 | 
						||
                  amountTopThree[2].memberCode
 | 
						||
                }}</view> -->
 | 
						||
                <view class="score">{{
 | 
						||
                  formatAmount(amountTopThree[2].amount)
 | 
						||
                }}</view>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 4-30名滚动列表 -->
 | 
						||
        <view class="ranking-list">
 | 
						||
          <!-- <view class="list-header">
 | 
						||
            <text class="list-title">完整排行榜</text>
 | 
						||
          </view> -->
 | 
						||
          <scroll-view
 | 
						||
            class="scroll-container"
 | 
						||
            scroll-y="true"
 | 
						||
            :show-scrollbar="false"
 | 
						||
          >
 | 
						||
            <view
 | 
						||
              class="list-item"
 | 
						||
              v-for="(item, index) in amountRemainingList"
 | 
						||
              :key="index"
 | 
						||
            >
 | 
						||
              <view class="item-rank">{{ index + 4 }}</view>
 | 
						||
              <view class="item-info">
 | 
						||
                <!-- <view class="item-code">{{ item.memberCode }}</view> -->
 | 
						||
                <view
 | 
						||
                  class="item-name"
 | 
						||
                  :class="{ highlight: item.isLoginMember == 1 }"
 | 
						||
                >
 | 
						||
                  {{ item.memberName | formatMemberName }}
 | 
						||
                </view>
 | 
						||
              </view>
 | 
						||
              <view class="item-score">
 | 
						||
                <span>{{ item.amount }}</span>
 | 
						||
              </view>
 | 
						||
            </view>
 | 
						||
            <view class="list-footer" v-if="amountRemainingList.length === 0">
 | 
						||
              <text class="empty-text">暂无更多数据</text>
 | 
						||
            </view>
 | 
						||
          </scroll-view>
 | 
						||
        </view>
 | 
						||
 | 
						||
        <!-- 底部关闭按钮 -->
 | 
						||
        <view class="popup-footer">
 | 
						||
          <view class="close-text-btn" @click="closeAmountRanking">
 | 
						||
            关 闭
 | 
						||
          </view>
 | 
						||
        </view>
 | 
						||
      </view>
 | 
						||
    </u-popup>
 | 
						||
 | 
						||
    <!-- 加载状态 -->
 | 
						||
    <u-loading-page
 | 
						||
      :loading="loading"
 | 
						||
      loading-text="加载中..."
 | 
						||
    ></u-loading-page>
 | 
						||
  </view>
 | 
						||
</template>
 | 
						||
 | 
						||
<script>
 | 
						||
import * as api from '@/config/index.js'
 | 
						||
 | 
						||
export default {
 | 
						||
  name: 'RankingPopup',
 | 
						||
  data() {
 | 
						||
    return {
 | 
						||
      // 控制弹窗显示
 | 
						||
      showPeopleRanking: false,
 | 
						||
      showAmountRanking: false,
 | 
						||
      loading: false,
 | 
						||
 | 
						||
      // 人数排行数据
 | 
						||
      peopleRankingList: [],
 | 
						||
      peopleTopThree: [],
 | 
						||
      peopleRemainingList: [],
 | 
						||
 | 
						||
      // 金额排行数据
 | 
						||
      amountRankingList: [],
 | 
						||
      amountTopThree: [],
 | 
						||
      amountRemainingList: [],
 | 
						||
 | 
						||
      // 用户信息
 | 
						||
      userInfo: uni.getStorageSync('User') || {},
 | 
						||
    }
 | 
						||
  },
 | 
						||
  filters: {
 | 
						||
    formatMemberName(val) {
 | 
						||
      return val?.slice(0, 8) || ''
 | 
						||
    },
 | 
						||
  },
 | 
						||
  methods: {
 | 
						||
    // 显示排行榜弹窗(先显示人数排行)
 | 
						||
    async showRankingPopups() {
 | 
						||
      this.loading = true
 | 
						||
      try {
 | 
						||
        // 并行加载两个排行榜数据
 | 
						||
        await Promise.all([this.loadPeopleRanking(), this.loadAmountRanking()])
 | 
						||
        // 先显示人数排行榜
 | 
						||
        if (this.peopleTopThree.length > 0) {
 | 
						||
          this.showPeopleRanking = true
 | 
						||
        } else if (this.amountTopThree.length > 0) {
 | 
						||
          this.showAmountRanking = true
 | 
						||
        } else {
 | 
						||
          this.$emit('onRankingComplete')
 | 
						||
        }
 | 
						||
      } catch (error) {
 | 
						||
        console.error('加载排行榜数据失败:', error)
 | 
						||
        uni.showToast({
 | 
						||
          title: '加载失败',
 | 
						||
          icon: 'error',
 | 
						||
        })
 | 
						||
      } finally {
 | 
						||
        this.loading = false
 | 
						||
      }
 | 
						||
    },
 | 
						||
 | 
						||
    // 获取当前年月参数
 | 
						||
    getCurrentYearMonth() {
 | 
						||
      const now = new Date()
 | 
						||
      const year = now.getFullYear()
 | 
						||
      const month = String(now.getMonth() + 1).padStart(2, '0') // 月份补0
 | 
						||
      return { year, month }
 | 
						||
    },
 | 
						||
 | 
						||
    // 加载人数排行榜数据
 | 
						||
    async loadPeopleRanking() {
 | 
						||
      try {
 | 
						||
        const { year, month } = this.getCurrentYearMonth()
 | 
						||
        const params = {
 | 
						||
          year,
 | 
						||
          month,
 | 
						||
          faker: true,
 | 
						||
        }
 | 
						||
        const res = await api.getTopPeople(params)
 | 
						||
        console.log(res.data)
 | 
						||
        if (res.code === 200 && res.data) {
 | 
						||
          // 数据字段映射
 | 
						||
          const mappedData = res.data.map(item => ({
 | 
						||
            ...item,
 | 
						||
            memberName: item.memberName,
 | 
						||
            memberCode: item.memberCode,
 | 
						||
            count: item.numberOfPeople, // 人数字段映射
 | 
						||
            isLoginMember: item.memberId === this.userInfo.memberId ? 1 : 0, // 判断是否为当前用户
 | 
						||
          }))
 | 
						||
          this.peopleRankingList = mappedData.slice(0, 30) // 取前30名
 | 
						||
          this.peopleTopThree = this.peopleRankingList.slice(0, 3)
 | 
						||
          this.peopleRemainingList = this.peopleRankingList.slice(3)
 | 
						||
        }
 | 
						||
      } catch (error) {
 | 
						||
        console.error('加载人数排行榜失败:', error)
 | 
						||
        throw error
 | 
						||
      }
 | 
						||
    },
 | 
						||
 | 
						||
    // 加载金额排行榜数据
 | 
						||
    async loadAmountRanking() {
 | 
						||
      try {
 | 
						||
        const { year, month } = this.getCurrentYearMonth()
 | 
						||
        const params = {
 | 
						||
          year,
 | 
						||
          month,
 | 
						||
          faker: true,
 | 
						||
        }
 | 
						||
        const res = await api.getTopAmount(params)
 | 
						||
        if (res.code === 200 && res.data) {
 | 
						||
          // 数据字段映射
 | 
						||
          const mappedData = res.data.map(item => ({
 | 
						||
            ...item,
 | 
						||
            memberName: item.memberName,
 | 
						||
            memberCode: item.memberCode,
 | 
						||
            amount: item.numberOfAmount, // 金额字段映射
 | 
						||
            isLoginMember: item.memberId === this.userInfo.memberId ? 1 : 0, // 判断是否为当前用户
 | 
						||
          }))
 | 
						||
          this.amountRankingList = mappedData.slice(0, 30) // 取前30名
 | 
						||
          this.amountTopThree = this.amountRankingList.slice(0, 3)
 | 
						||
          this.amountRemainingList = this.amountRankingList.slice(3)
 | 
						||
        }
 | 
						||
      } catch (error) {
 | 
						||
        console.error('加载金额排行榜失败:', error)
 | 
						||
        throw error
 | 
						||
      }
 | 
						||
    },
 | 
						||
 | 
						||
    // 关闭人数排行榜,显示金额排行榜
 | 
						||
    closePeopleRanking() {
 | 
						||
      this.showPeopleRanking = false
 | 
						||
      if (this.amountTopThree.length > 0) {
 | 
						||
        setTimeout(() => {
 | 
						||
          this.showAmountRanking = true
 | 
						||
        }, 300)
 | 
						||
      } else {
 | 
						||
        this.$emit('onRankingComplete')
 | 
						||
      }
 | 
						||
    },
 | 
						||
 | 
						||
    // 关闭金额排行榜
 | 
						||
    closeAmountRanking() {
 | 
						||
      this.showAmountRanking = false
 | 
						||
      // 触发完成事件
 | 
						||
      this.$emit('onRankingComplete')
 | 
						||
    },
 | 
						||
 | 
						||
    // 格式化金额显示
 | 
						||
    formatAmount(amount) {
 | 
						||
      return amount
 | 
						||
    },
 | 
						||
  },
 | 
						||
}
 | 
						||
</script>
 | 
						||
 | 
						||
<style lang="scss" scoped>
 | 
						||
::v-deep .u-popup__content {
 | 
						||
  background-color: rgba(0, 0, 0, 0);
 | 
						||
}
 | 
						||
 | 
						||
.popup-container {
 | 
						||
  width: 100%;
 | 
						||
  height: 100%;
 | 
						||
  background: linear-gradient(
 | 
						||
    135deg,
 | 
						||
    #003d7a 0%,
 | 
						||
    #005bac 30%,
 | 
						||
    #0077cc 70%,
 | 
						||
    #4a90e2 100%
 | 
						||
  );
 | 
						||
  border-radius: 20rpx;
 | 
						||
  display: flex;
 | 
						||
  flex-direction: column;
 | 
						||
  overflow: hidden;
 | 
						||
  position: relative;
 | 
						||
 | 
						||
  // 添加微妙的光效
 | 
						||
  &::before {
 | 
						||
    content: '';
 | 
						||
    position: absolute;
 | 
						||
    top: 0;
 | 
						||
    left: 0;
 | 
						||
    right: 0;
 | 
						||
    bottom: 0;
 | 
						||
    background: radial-gradient(
 | 
						||
      ellipse at 30% 20%,
 | 
						||
      rgba(255, 255, 255, 0.1) 0%,
 | 
						||
      transparent 50%
 | 
						||
    );
 | 
						||
    pointer-events: none;
 | 
						||
    z-index: 1;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes sparkle {
 | 
						||
  0% {
 | 
						||
    transform: translateY(0);
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    transform: translateY(-100rpx);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.popup-header {
 | 
						||
  padding: 30rpx 40rpx 20rpx;
 | 
						||
  flex-shrink: 0;
 | 
						||
  position: relative;
 | 
						||
  z-index: 2;
 | 
						||
 | 
						||
  .header-title {
 | 
						||
    font-size: 38rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    color: #ffffff;
 | 
						||
    text-shadow:
 | 
						||
      0 2rpx 8rpx rgba(0, 0, 0, 0.6),
 | 
						||
      0 0 15rpx rgba(74, 144, 226, 0.8),
 | 
						||
      0 0 25rpx rgba(255, 255, 255, 0.4);
 | 
						||
    text-align: center;
 | 
						||
    position: relative;
 | 
						||
    animation: title-bling 2s ease-in-out infinite alternate;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.top-three-section {
 | 
						||
  padding: 20rpx 20rpx 40rpx;
 | 
						||
  flex-shrink: 0;
 | 
						||
  position: relative;
 | 
						||
  z-index: 2;
 | 
						||
}
 | 
						||
 | 
						||
.podium-container {
 | 
						||
  display: flex;
 | 
						||
  justify-content: center;
 | 
						||
  align-items: flex-end;
 | 
						||
  position: relative;
 | 
						||
  margin: 0 10rpx;
 | 
						||
  height: 290rpx;
 | 
						||
 | 
						||
  // 添加领奖台基座
 | 
						||
  // &::after {
 | 
						||
  //   content: '';
 | 
						||
  //   position: absolute;
 | 
						||
  //   bottom: 0;
 | 
						||
  //   left: 50%;
 | 
						||
  //   transform: translateX(-50%);
 | 
						||
  //   width: 85%;
 | 
						||
  //   height: 30rpx;
 | 
						||
  //   background: linear-gradient(135deg, #424242 0%, #616161 50%, #424242 100%);
 | 
						||
  //   border-radius: 15rpx 15rpx 0 0;
 | 
						||
  //   box-shadow: 0 -6rpx 20rpx rgba(0, 0, 0, 0.3);
 | 
						||
  // }
 | 
						||
}
 | 
						||
 | 
						||
.podium-item {
 | 
						||
  display: flex;
 | 
						||
  flex-direction: column;
 | 
						||
  align-items: center;
 | 
						||
  position: relative;
 | 
						||
  margin: 0 8rpx;
 | 
						||
 | 
						||
  .player-area {
 | 
						||
    border-radius: 20rpx;
 | 
						||
    min-width: 140rpx;
 | 
						||
    text-align: center;
 | 
						||
    transition: all 0.3s ease;
 | 
						||
    display: flex;
 | 
						||
    flex-direction: column;
 | 
						||
    align-items: center;
 | 
						||
    justify-content: flex-end;
 | 
						||
    position: relative;
 | 
						||
    z-index: 3;
 | 
						||
  }
 | 
						||
 | 
						||
  // 创建领奖台台阶
 | 
						||
  // &::after {
 | 
						||
  //   content: '';
 | 
						||
  //   position: absolute;
 | 
						||
  //   bottom: 0;
 | 
						||
  //   left: 50%;
 | 
						||
  //   transform: translateX(-50%);
 | 
						||
  //   border-radius: 12rpx 12rpx 0 0;
 | 
						||
  //   box-shadow:
 | 
						||
  //     0 -6rpx 15rpx rgba(0, 0, 0, 0.25),
 | 
						||
  //     inset 0 3rpx 6rpx rgba(255, 255, 255, 0.15);
 | 
						||
  // }
 | 
						||
 | 
						||
  .rank-number {
 | 
						||
    border-radius: 50%;
 | 
						||
    display: flex;
 | 
						||
    align-items: center;
 | 
						||
    justify-content: center;
 | 
						||
    font-size: 26rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    color: #fff;
 | 
						||
    margin-bottom: 15rpx;
 | 
						||
    position: relative;
 | 
						||
 | 
						||
    img {
 | 
						||
      filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3));
 | 
						||
      transition: all 0.3s ease;
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .member-name {
 | 
						||
    font-size: 24rpx;
 | 
						||
    color: #fff;
 | 
						||
    text-align: center;
 | 
						||
    margin-bottom: 8rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    max-width: 110rpx;
 | 
						||
    overflow: hidden;
 | 
						||
    text-overflow: ellipsis;
 | 
						||
    white-space: nowrap;
 | 
						||
 | 
						||
    padding: 6rpx 10rpx;
 | 
						||
    border-radius: 15rpx;
 | 
						||
  }
 | 
						||
 | 
						||
  .member-code {
 | 
						||
    color: #fff;
 | 
						||
    text-align: center;
 | 
						||
    margin-top: 8rpx;
 | 
						||
    font-size: 24rpx;
 | 
						||
    font-weight: 600;
 | 
						||
    overflow: hidden;
 | 
						||
    text-overflow: ellipsis;
 | 
						||
    white-space: nowrap;
 | 
						||
 | 
						||
    padding: 4rpx 8rpx;
 | 
						||
    border-radius: 12rpx;
 | 
						||
 | 
						||
    backdrop-filter: blur(5rpx);
 | 
						||
  }
 | 
						||
 | 
						||
  .score {
 | 
						||
    font-size: 22rpx;
 | 
						||
    color: #fff;
 | 
						||
    font-weight: bold;
 | 
						||
    min-width: 60rpx;
 | 
						||
    text-align: center;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
// 第二名台阶
 | 
						||
.second-place {
 | 
						||
  .player-area {
 | 
						||
    transform: translateY(10rpx);
 | 
						||
  }
 | 
						||
  &::after {
 | 
						||
    width: 130rpx;
 | 
						||
    height: 100rpx;
 | 
						||
    background: linear-gradient(135deg, #c0c0c0 0%, #e8e8e8 50%, #c0c0c0 100%);
 | 
						||
  }
 | 
						||
 | 
						||
  // .member-name {
 | 
						||
  //   font-size: 26rpx;
 | 
						||
  // }
 | 
						||
 | 
						||
  // .member-code {
 | 
						||
  //   font-size: 26rpx;
 | 
						||
  // }
 | 
						||
 | 
						||
  // .score {
 | 
						||
  //   font-size: 26rpx;
 | 
						||
  // }
 | 
						||
 | 
						||
  .rank-number img {
 | 
						||
    height: 70rpx;
 | 
						||
    width: 70rpx;
 | 
						||
    animation: silver-glow 2s ease-in-out infinite alternate;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
// 第一名台阶 - 最高
 | 
						||
.first-place {
 | 
						||
  .player-area {
 | 
						||
    transform: translateY(-40rpx);
 | 
						||
  }
 | 
						||
 | 
						||
  &::after {
 | 
						||
    width: 150rpx;
 | 
						||
    height: 140rpx;
 | 
						||
    background: linear-gradient(135deg, #ffd700 0%, #ffed4e 50%, #ffd700 100%);
 | 
						||
    box-shadow:
 | 
						||
      0 -8rpx 20rpx rgba(0, 0, 0, 0.3),
 | 
						||
      inset 0 3rpx 6rpx rgba(255, 255, 255, 0.3),
 | 
						||
      0 0 25rpx rgba(255, 215, 0, 0.4);
 | 
						||
  }
 | 
						||
 | 
						||
  .rank-number img {
 | 
						||
    height: 80rpx;
 | 
						||
    width: 80rpx;
 | 
						||
    animation: champion-glow 2s ease-in-out infinite alternate;
 | 
						||
  }
 | 
						||
 | 
						||
  .member-name {
 | 
						||
    font-size: 28rpx;
 | 
						||
    color: #ffd700;
 | 
						||
    animation: champion-text-glow 2s ease-in-out infinite alternate;
 | 
						||
  }
 | 
						||
 | 
						||
  .member-code {
 | 
						||
    font-size: 28rpx;
 | 
						||
    color: #ffd700;
 | 
						||
    font-weight: 600;
 | 
						||
  }
 | 
						||
 | 
						||
  .score {
 | 
						||
    color: #ffd700;
 | 
						||
    font-size: 28rpx;
 | 
						||
    font-weight: 900;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
// 第三名台阶
 | 
						||
.third-place {
 | 
						||
  .player-area {
 | 
						||
    transform: translateY(10rpx);
 | 
						||
  }
 | 
						||
 | 
						||
  .rank-number img {
 | 
						||
    height: 65rpx;
 | 
						||
    width: 65rpx;
 | 
						||
    animation: bronze-glow 2s ease-in-out infinite alternate;
 | 
						||
  }
 | 
						||
  // .member-name {
 | 
						||
  //   font-size: 22rpx;
 | 
						||
  // }
 | 
						||
 | 
						||
  // .member-code {
 | 
						||
  //   font-size: 22rpx;
 | 
						||
  // }
 | 
						||
 | 
						||
  // .score {
 | 
						||
  //   font-size: 22rpx;
 | 
						||
  // }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes title-bling {
 | 
						||
  0% {
 | 
						||
    text-shadow:
 | 
						||
      0 2rpx 8rpx rgba(0, 0, 0, 0.6),
 | 
						||
      0 0 15rpx rgba(74, 144, 226, 0.8),
 | 
						||
      0 0 25rpx rgba(255, 255, 255, 0.4);
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    text-shadow:
 | 
						||
      0 2rpx 8rpx rgba(0, 0, 0, 0.6),
 | 
						||
      0 0 25rpx rgba(74, 144, 226, 1),
 | 
						||
      0 0 35rpx rgba(255, 255, 255, 0.7),
 | 
						||
      0 0 45rpx rgba(0, 119, 204, 0.5);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes golden-pulse {
 | 
						||
  0% {
 | 
						||
    background: radial-gradient(
 | 
						||
      ellipse at center,
 | 
						||
      rgba(255, 215, 0, 0.2) 0%,
 | 
						||
      transparent 70%
 | 
						||
    );
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    background: radial-gradient(
 | 
						||
      ellipse at center,
 | 
						||
      rgba(255, 215, 0, 0.4) 0%,
 | 
						||
      transparent 70%
 | 
						||
    );
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes champion-glow {
 | 
						||
  0% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 10rpx rgba(255, 215, 0, 0.3));
 | 
						||
    transform: scale(1);
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 20rpx rgba(255, 215, 0, 0.6));
 | 
						||
    transform: scale(1.05);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes champion-text-glow {
 | 
						||
  0% {
 | 
						||
    text-shadow: 0 2rpx 8rpx rgba(255, 215, 0, 0.8);
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    text-shadow:
 | 
						||
      0 2rpx 8rpx rgba(255, 215, 0, 0.8),
 | 
						||
      0 0 15rpx rgba(255, 215, 0, 0.5);
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes silver-glow {
 | 
						||
  0% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 8rpx rgba(192, 192, 192, 0.3));
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 15rpx rgba(192, 192, 192, 0.5));
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
@keyframes bronze-glow {
 | 
						||
  0% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 8rpx rgba(205, 127, 50, 0.3));
 | 
						||
  }
 | 
						||
  100% {
 | 
						||
    filter: drop-shadow(0 4rpx 8rpx rgba(0, 0, 0, 0.3))
 | 
						||
      drop-shadow(0 0 15rpx rgba(205, 127, 50, 0.5));
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.ranking-list {
 | 
						||
  flex: 1;
 | 
						||
  background: linear-gradient(
 | 
						||
    135deg,
 | 
						||
    rgba(255, 255, 255, 0.98) 0%,
 | 
						||
    rgba(248, 250, 252, 0.95) 100%
 | 
						||
  );
 | 
						||
  margin: 20rpx 20rpx 0 20rpx;
 | 
						||
  border-radius: 25rpx 25rpx 0 0;
 | 
						||
  overflow: hidden;
 | 
						||
  backdrop-filter: blur(15rpx);
 | 
						||
  display: flex;
 | 
						||
  flex-direction: column;
 | 
						||
  position: relative;
 | 
						||
  z-index: 2;
 | 
						||
  box-shadow:
 | 
						||
    0 -8rpx 25rpx rgba(0, 0, 0, 0.1),
 | 
						||
    inset 0 1rpx 0 rgba(255, 255, 255, 0.8);
 | 
						||
}
 | 
						||
 | 
						||
.list-header {
 | 
						||
  padding: 30rpx 40rpx 20rpx;
 | 
						||
  border-bottom: 2rpx solid rgba(139, 69, 19, 0.1);
 | 
						||
  flex-shrink: 0;
 | 
						||
  background: linear-gradient(
 | 
						||
    135deg,
 | 
						||
    rgba(255, 255, 255, 0.9) 0%,
 | 
						||
    rgba(248, 250, 252, 0.8) 100%
 | 
						||
  );
 | 
						||
 | 
						||
  .list-title {
 | 
						||
    font-size: 28rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    color: #2d3748;
 | 
						||
    position: relative;
 | 
						||
    text-align: center;
 | 
						||
 | 
						||
    &::after {
 | 
						||
      content: '';
 | 
						||
      position: absolute;
 | 
						||
      bottom: -8rpx;
 | 
						||
      left: 50%;
 | 
						||
      transform: translateX(-50%);
 | 
						||
      width: 60rpx;
 | 
						||
      height: 3rpx;
 | 
						||
      background: linear-gradient(90deg, transparent, #9c27b0, transparent);
 | 
						||
      border-radius: 2rpx;
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.scroll-container {
 | 
						||
  flex: 1;
 | 
						||
  height: 0; /* 关键:在flex布局中,scroll-view需要明确高度 */
 | 
						||
}
 | 
						||
 | 
						||
.list-item {
 | 
						||
  display: flex;
 | 
						||
  align-items: center;
 | 
						||
  padding: 24rpx 30rpx;
 | 
						||
  border-bottom: 1rpx solid rgba(226, 232, 240, 0.8);
 | 
						||
  position: relative;
 | 
						||
  transition: all 0.3s ease;
 | 
						||
 | 
						||
  &:last-child {
 | 
						||
    border-bottom: none;
 | 
						||
  }
 | 
						||
 | 
						||
  &:hover {
 | 
						||
    background: linear-gradient(
 | 
						||
      135deg,
 | 
						||
      rgba(159, 122, 234, 0.05) 0%,
 | 
						||
      rgba(139, 92, 246, 0.03) 100%
 | 
						||
    );
 | 
						||
    transform: translateX(5rpx);
 | 
						||
  }
 | 
						||
 | 
						||
  .item-rank {
 | 
						||
    font-size: 24rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    color: #64748b;
 | 
						||
    text-align: center;
 | 
						||
    margin-right: 20rpx;
 | 
						||
    background: linear-gradient(135deg, #f1f5f9 0%, #e2e8f0 100%);
 | 
						||
    border-radius: 50%;
 | 
						||
    width: 40rpx;
 | 
						||
    height: 40rpx;
 | 
						||
    display: flex;
 | 
						||
    align-items: center;
 | 
						||
    justify-content: center;
 | 
						||
    box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
 | 
						||
  }
 | 
						||
 | 
						||
  .item-info {
 | 
						||
    flex: 2;
 | 
						||
    display: flex;
 | 
						||
    align-items: center;
 | 
						||
    justify-content: space-between;
 | 
						||
  }
 | 
						||
 | 
						||
  .item-name {
 | 
						||
    font-size: 28rpx;
 | 
						||
    color: #1e293b;
 | 
						||
    overflow: hidden;
 | 
						||
    text-overflow: ellipsis;
 | 
						||
    white-space: nowrap;
 | 
						||
    font-weight: 600;
 | 
						||
 | 
						||
    &.highlight {
 | 
						||
      color: #7c3aed;
 | 
						||
      font-weight: bold;
 | 
						||
      background: linear-gradient(135deg, #7c3aed, #a855f7);
 | 
						||
      background-clip: text;
 | 
						||
      -webkit-background-clip: text;
 | 
						||
      -webkit-text-fill-color: transparent;
 | 
						||
      position: relative;
 | 
						||
 | 
						||
      &::before {
 | 
						||
        content: '';
 | 
						||
        position: absolute;
 | 
						||
        left: -8rpx;
 | 
						||
        top: 50%;
 | 
						||
        transform: translateY(-50%);
 | 
						||
        width: 4rpx;
 | 
						||
        height: 20rpx;
 | 
						||
        background: linear-gradient(135deg, #7c3aed, #a855f7);
 | 
						||
        border-radius: 2rpx;
 | 
						||
      }
 | 
						||
    }
 | 
						||
  }
 | 
						||
 | 
						||
  .item-code {
 | 
						||
    font-size: 22rpx;
 | 
						||
    color: #64748b;
 | 
						||
    white-space: nowrap;
 | 
						||
  }
 | 
						||
 | 
						||
  .item-score {
 | 
						||
    flex: 1;
 | 
						||
    font-size: 24rpx;
 | 
						||
    color: #374151;
 | 
						||
    font-weight: bold;
 | 
						||
    min-width: 100rpx;
 | 
						||
    text-align: center;
 | 
						||
    border-radius: 20rpx;
 | 
						||
    display: flex;
 | 
						||
    justify-content: flex-end;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.list-footer {
 | 
						||
  padding: 40rpx;
 | 
						||
  text-align: center;
 | 
						||
 | 
						||
  .empty-text {
 | 
						||
    font-size: 26rpx;
 | 
						||
    color: #64748b;
 | 
						||
    font-style: italic;
 | 
						||
  }
 | 
						||
}
 | 
						||
 | 
						||
.popup-footer {
 | 
						||
  padding: 20rpx;
 | 
						||
  flex-shrink: 0;
 | 
						||
  position: relative;
 | 
						||
  z-index: 2;
 | 
						||
 | 
						||
  .close-text-btn {
 | 
						||
    background: linear-gradient(
 | 
						||
      135deg,
 | 
						||
      rgba(255, 255, 255, 0.95) 0%,
 | 
						||
      rgba(248, 250, 252, 0.9) 100%
 | 
						||
    );
 | 
						||
    color: #005bac;
 | 
						||
    text-align: center;
 | 
						||
    padding: 20rpx 50rpx;
 | 
						||
    border-radius: 50rpx;
 | 
						||
    font-size: 30rpx;
 | 
						||
    font-weight: bold;
 | 
						||
    box-shadow:
 | 
						||
      0 8rpx 25rpx rgba(0, 0, 0, 0.15),
 | 
						||
      inset 0 1rpx 0 rgba(255, 255, 255, 0.8),
 | 
						||
      0 0 0 1rpx rgba(0, 91, 172, 0.3);
 | 
						||
    transition: all 0.3s ease;
 | 
						||
    position: relative;
 | 
						||
    overflow: hidden;
 | 
						||
 | 
						||
    &::before {
 | 
						||
      content: '';
 | 
						||
      position: absolute;
 | 
						||
      top: 0;
 | 
						||
      left: -100%;
 | 
						||
      width: 100%;
 | 
						||
      height: 100%;
 | 
						||
      background: linear-gradient(
 | 
						||
        90deg,
 | 
						||
        transparent,
 | 
						||
        rgba(255, 255, 255, 0.4),
 | 
						||
        transparent
 | 
						||
      );
 | 
						||
      transition: left 0.5s ease;
 | 
						||
    }
 | 
						||
 | 
						||
    &:active {
 | 
						||
      transform: scale(0.98);
 | 
						||
      background: linear-gradient(
 | 
						||
        135deg,
 | 
						||
        rgba(248, 250, 252, 0.9) 0%,
 | 
						||
        rgba(241, 245, 249, 0.85) 100%
 | 
						||
      );
 | 
						||
      box-shadow:
 | 
						||
        0 4rpx 15rpx rgba(0, 0, 0, 0.1),
 | 
						||
        inset 0 2rpx 4rpx rgba(0, 0, 0, 0.1);
 | 
						||
 | 
						||
      &::before {
 | 
						||
        left: 100%;
 | 
						||
      }
 | 
						||
    }
 | 
						||
 | 
						||
    &:hover::before {
 | 
						||
      left: 100%;
 | 
						||
    }
 | 
						||
  }
 | 
						||
}
 | 
						||
</style>
 |