hookehuyr

feat(排行榜): 添加助力榜功能并替换点击事件为tap

实现助力榜功能,包括mock数据、显示逻辑和格式化方法
将click事件统一替换为tap事件以兼容移动端
......@@ -8,10 +8,10 @@
<view class="overlay-body">
<view class="overlay-content">
<!-- 广告图片容器 - 支持滚动 -->
<scroll-view
class="ad-scroll-container"
<scroll-view
class="ad-scroll-container"
scroll-y
@click="handleAdClick"
@tap="handleAdClick"
>
<image
:src="adConfig.adImageUrl"
......@@ -22,7 +22,7 @@
</scroll-view>
<!-- 关闭按钮 -->
<view class="close-button" @click="handleClose">
<view class="close-button" @tap="handleClose">
<Close size="24" class="close-icon" />
</view>
</view>
......
<!--
* @Date: 2025-01-09 00:00:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-16 11:22:44
* @LastEditTime: 2025-09-18 16:45:21
* @FilePath: /lls_program/src/components/RankingCard.vue
* @Description: 排行榜卡片组件
-->
......@@ -52,13 +52,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-silver.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topRanks[1]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? (topRanks[1]?.logo || defaultAvatar) : (topRanks[1]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topRanks[1]?.name }}</view>
<view class="leader-name">大家长:{{ topRanks[1]?.created_by_nickname }}</view>
<view class="family-name">{{ activeTab === 'support' ? topRanks[1]?.name : topRanks[1]?.name }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topRanks[1]?.family_count}个家庭` : `大家长:${topRanks[1]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">2</view>
<view class="steps-in-rank">{{ formatSteps(topRanks[1]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[1]?.total_steps) : formatSteps(topRanks[1]?.step) }}</view>
</view>
</view>
......@@ -68,13 +68,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-gold.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topRanks[0]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? (topRanks[0]?.logo || defaultAvatar) : (topRanks[0]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topRanks[0]?.name }}</view>
<view class="leader-name">大家长:{{ topRanks[0]?.created_by_nickname }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topRanks[0]?.family_count}个家庭` : `大家长:${topRanks[0]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">1</view>
<view class="steps-in-rank">{{ formatSteps(topRanks[0]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[0]?.total_steps) : formatSteps(topRanks[0]?.step) }}</view>
</view>
</view>
......@@ -84,13 +84,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-bronze.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topRanks[2]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? (topRanks[2]?.logo || defaultAvatar) : (topRanks[2]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topRanks[2]?.name }}</view>
<view class="leader-name">大家长:{{ topRanks[2]?.created_by_nickname }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topRanks[2]?.family_count}个家庭` : `大家长:${topRanks[2]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">3</view>
<view class="steps-in-rank">{{ formatSteps(topRanks[2]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[2]?.total_steps) : formatSteps(topRanks[2]?.step) }}</view>
</view>
</view>
</view>
......@@ -112,7 +112,7 @@
</view>
</view>
<view class="my-rank-right">
<view class="my-steps">{{ formatStepsForList(myRank.step) }}</view>
<view class="my-steps">{{ activeTab === 'support' ? formatSupportSteps(myRank.step) : formatStepsForList(myRank.step) }}</view>
<view class="rank-status">{{ myRank.status }}</view>
</view>
</view>
......@@ -155,6 +155,63 @@ const isContentSwitching = ref(false)
// 排行榜数据
const leaderboardData = ref(null)
// 助力榜mock数据
const supportData = ref({
yesterday: '2024年1月15日',
kindergartens: [
{
id: 1,
name: '阳光幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 156,
total_steps: 430000
},
{
id: 2,
name: '彩虹幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 142,
total_steps: 380000
},
{
id: 3,
name: '小星星幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 128,
total_steps: 320000
},
{
id: 4,
name: '快乐幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 115,
total_steps: 280000
},
{
id: 5,
name: '智慧幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 98,
total_steps: 250000
},
{
id: 6,
name: '梦想幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 87,
total_steps: 220000
}
],
current_kindergarten: {
id: 7,
name: '我的幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 45,
total_steps: 120000,
rank: 8
}
})
// 加载状态
const loading = ref(false)
......@@ -168,10 +225,22 @@ const currentDate = ref('')
const switchTab = async (tab) => {
if (activeTab.value === tab) return
// 助力榜暂时没有数据,显示提示
// 助力榜使用mock数据
if (tab === 'support') {
// TODO: 助力榜功能待开发
console.log('助力榜功能待开发')
// 开始切换动画
isContentSwitching.value = true
// 延迟切换内容,让淡出动画先执行
setTimeout(() => {
activeTab.value = tab
// 设置助力榜的日期
currentDate.value = supportData.value.yesterday
// 内容切换后,结束切换状态,开始淡入动画
setTimeout(() => {
isContentSwitching.value = false
}, 50)
}, 200)
return
}
......@@ -288,6 +357,20 @@ const formatStepsForList = (steps) => {
}
/**
* 格式化助力榜步数显示(超过10000显示为万+格式)
* @param {number} steps - 步数
* @returns {string} 格式化后的步数
*/
const formatSupportSteps = (steps) => {
if (!steps) return '0'
if (steps >= 10000) {
const wan = Math.floor(steps / 10000)
return `${wan}万+`
}
return steps.toLocaleString()
}
/**
* 处理查看更多点击事件
*/
const handleViewMore = () => {
......@@ -300,6 +383,15 @@ const handleViewMore = () => {
// 计算前三名数据
const topRanks = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
return []
}
return supportData.value.kindergartens.slice(0, 3)
}
// 家庭排行榜数据
if (!leaderboardData.value || !leaderboardData.value.families) {
return []
}
......@@ -308,6 +400,25 @@ const topRanks = computed(() => {
// 计算我的排名信息
const myRank = computed(() => {
if (activeTab.value === 'support') {
// 助力榜我的幼儿园信息
if (!supportData.value || !supportData.value.current_kindergarten) {
return null
}
const currentKindergarten = supportData.value.current_kindergarten
return {
...currentKindergarten,
name: currentKindergarten.name,
avatar_url: currentKindergarten.logo,
step: currentKindergarten.total_steps,
created_by_nickname: `${currentKindergarten.family_count}个家庭`,
status: currentKindergarten.rank > 100 ? '未上榜' : '已上榜',
isNotRanked: !currentKindergarten.rank || currentKindergarten.rank === 0 || currentKindergarten.rank > 100
}
}
// 家庭排行榜我的排名信息
if (!leaderboardData.value || !leaderboardData.value.current_family) {
return null
}
......
<!--
* @Date: 2025-09-01 13:07:52
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-15 15:59:31
* @LastEditTime: 2025-09-18 16:56:23
* @FilePath: /lls_program/src/pages/FamilyRank/index.vue
* @Description: 文件描述
-->
......@@ -39,8 +39,9 @@
</view>
<!-- 排行榜日期 -->
<view v-if="!loading" class="rank-date">
<view v-if="!loading" class="rank-date relative">
{{ currentDate }}
<view v-if="activeTab === 'support'" class="absolute font-bold text-white" style="right: 95rpx;" @tap="joinOrganization">助力码</view>
</view>
<!-- 前三名展示 -->
......@@ -52,13 +53,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-silver.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topThreeData[1]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? topThreeData[1]?.logo : (topThreeData[1]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topThreeData[1]?.name }}</view>
<view class="leader-name">大家长:{{ topThreeData[1]?.created_by_nickname }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[1]?.family_count}个家庭` : `大家长:${topThreeData[1]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">2</view>
<view class="steps-in-rank">{{ formatSteps(topThreeData[1]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[1]?.total_steps) : formatSteps(topThreeData[1]?.step) }}</view>
</view>
</view>
......@@ -68,13 +69,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-gold.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topThreeData[0]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? topThreeData[0]?.logo : (topThreeData[0]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topThreeData[0]?.name }}</view>
<view class="leader-name">大家长:{{ topThreeData[0]?.created_by_nickname }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[0]?.family_count}个家庭` : `大家长:${topThreeData[0]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">1</view>
<view class="steps-in-rank">{{ formatSteps(topThreeData[0]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[0]?.total_steps) : formatSteps(topThreeData[0]?.step) }}</view>
</view>
</view>
......@@ -84,13 +85,13 @@
<image src="https://cdn.ipadbiz.cn/lls_prog/images/crow-bronze.png" class="w-5 h-5" mode="aspectFill" />
</view>
<view class="avatar">
<image :src="topThreeData[2]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? topThreeData[2]?.logo : (topThreeData[2]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</view>
<view class="family-name">{{ topThreeData[2]?.name }}</view>
<view class="leader-name">大家长:{{ topThreeData[2]?.created_by_nickname }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[2]?.family_count}个家庭` : `大家长:${topThreeData[2]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">3</view>
<view class="steps-in-rank">{{ formatSteps(topThreeData[2]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[2]?.total_steps) : formatSteps(topThreeData[2]?.step) }}</view>
</view>
</view>
</view>
......@@ -105,15 +106,15 @@
<view class="rank-info">
<view class="rank-num">{{ index + 4 }}</view>
<view class="avatar-small">
<image :src="item.avatar_url || defaultAvatar" class="avatar-small-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? item.logo : (item.avatar_url || defaultAvatar)" class="avatar-small-img" mode="aspectFill" />
</view>
<view class="family-info">
<view class="family-name-small">{{ item.name }}</view>
<view class="leader-name-small">大家长:{{ item.created_by_nickname }}</view>
<view class="leader-name-small">{{ activeTab === 'support' ? `${item.family_count}个家庭` : `大家长:${item.created_by_nickname}` }}</view>
</view>
</view>
<view class="steps-info">
<view class="steps">{{ formatStepsForList(item.step) }}</view>
<view class="steps">{{ activeTab === 'support' ? formatSupportSteps(item.total_steps) : formatStepsForList(item.step) }}</view>
</view>
</view>
</view>
......@@ -140,7 +141,7 @@
</view>
</view>
<view class="my-rank-right">
<view class="my-steps">{{ formatStepsForList(myRankInfo.step) }}</view>
<view class="my-steps">{{ activeTab === 'support' ? formatSupportSteps(myRankInfo.step) : formatStepsForList(myRankInfo.step) }}</view>
<view class="rank-status">{{ myRankInfo.isNotRanked ? '未上榜' : '已上榜' }}</view>
</view>
</view>
......@@ -153,6 +154,7 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import Taro from '@tarojs/taro'
import BackToTop from '@/components/BackToTop.vue'
// 默认头像
const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
......@@ -178,6 +180,83 @@ const isContentSwitching = ref(false)
// 排行榜数据
const leaderboardData = ref(null)
// 助力榜mock数据
const supportData = ref({
yesterday: '2024年1月15日',
kindergartens: [
{
id: 1,
name: '阳光幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 156,
total_steps: 430000
},
{
id: 2,
name: '彩虹幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 142,
total_steps: 380000
},
{
id: 3,
name: '小星星幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 128,
total_steps: 320000
},
{
id: 4,
name: '快乐幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 115,
total_steps: 280000
},
{
id: 5,
name: '智慧幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 98,
total_steps: 250000
},
{
id: 6,
name: '梦想幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 87,
total_steps: 220000
},
{
id: 7,
name: '未来幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 76,
total_steps: 190000
},
{
id: 8,
name: '希望幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 65,
total_steps: 160000
}
],
current_kindergarten: {
id: 9,
name: '我的幼儿园',
logo: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg',
family_count: 45,
total_steps: 120000,
rank: 10
}
})
const joinOrganization = () => {
Taro.navigateTo({
url: '/pages/JoinOrganization/index'
})
}
// 加载状态
const loading = ref(false)
......@@ -191,10 +270,22 @@ const currentDate = ref('')
const switchTab = async (tab) => {
if (activeTab.value === tab) return
// 助力榜暂时没有数据,显示提示
// 助力榜使用mock数据
if (tab === 'support') {
// TODO: 助力榜功能待开发
console.log('助力榜功能待开发')
// 开始切换动画
isContentSwitching.value = true
// 延迟切换内容,让淡出动画先执行
setTimeout(() => {
activeTab.value = tab
// 设置助力榜的日期
currentDate.value = supportData.value.yesterday
// 内容切换后,结束切换状态,开始淡入动画
setTimeout(() => {
isContentSwitching.value = false
}, 50)
}, 200)
return
}
......@@ -233,6 +324,20 @@ const formatStepsForList = (steps) => {
return steps ? steps.toLocaleString() : '0'
}
/**
* 格式化助力榜步数显示(超过10000显示为万+格式)
* @param {number} steps - 步数
* @returns {string} 格式化后的步数
*/
const formatSupportSteps = (steps) => {
if (!steps) return '0'
if (steps >= 10000) {
const wan = Math.floor(steps / 10000)
return `${wan}万+`
}
return steps.toLocaleString()
}
/**
......@@ -315,6 +420,15 @@ const getTabDisplayName = (region) => {
* 计算前三名数据
*/
const topThreeData = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
return []
}
return supportData.value.kindergartens.slice(0, 3)
}
// 家庭排行榜数据
if (!leaderboardData.value || !leaderboardData.value.families) {
return []
}
......@@ -325,6 +439,15 @@ const topThreeData = computed(() => {
* 计算其他排名数据
*/
const otherRankData = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
return []
}
return supportData.value.kindergartens.slice(3)
}
// 家庭排行榜数据
if (!leaderboardData.value || !leaderboardData.value.families) {
return []
}
......@@ -335,6 +458,24 @@ const otherRankData = computed(() => {
* 计算我的排名信息
*/
const myRankInfo = computed(() => {
if (activeTab.value === 'support') {
// 助力榜我的幼儿园信息
if (!supportData.value || !supportData.value.current_kindergarten) {
return null
}
const currentKindergarten = supportData.value.current_kindergarten
return {
...currentKindergarten,
family_name: currentKindergarten.name,
avatar_url: currentKindergarten.logo,
step: currentKindergarten.total_steps,
created_by_nickname: `${currentKindergarten.family_count}个家庭`,
isNotRanked: !currentKindergarten.rank || currentKindergarten.rank === 0 || currentKindergarten.rank > 100
}
}
// 家庭排行榜我的排名信息
if (!leaderboardData.value || !leaderboardData.value.current_family) {
return null
}
......