hookehuyr

feat(排行榜): 重构排行榜接口和组件以支持多类型数据

修改API接口参数从current_county变为type参数,支持上海家庭榜、区县家庭榜和单位助力榜
移除mock数据,统一使用接口返回数据
更新组件逻辑以适应新的数据结构
/*
* @Date: 2023-12-22 10:29:37
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-09 14:56:34
* @LastEditTime: 2025-09-18 17:23:51
* @FilePath: /lls_program/src/api/points.js
* @Description: 文件描述
*/
......@@ -51,24 +51,24 @@ export const getPointListAPI = (params) => fn(fetch.get(Api.POINT_LIST, params))
/**
* @description: 查询步数排行榜, 数据长度为10个, 不加上county参数查询的是上海数据, 数据长度是20个, 都是固定长度.
* @param {Object} params - 请求参数
* @param {string} params.current_county - 是否只查我的当前家庭所在区县的排行榜。1=是,0=否。默认为否
* @param {string} params.type - shanghai_family=上海家庭步数榜,county_family=和我同区县的家庭步数榜,institution=单位助力榜
* @returns {Object} response - 响应对象
* @returns {number} response.code - 响应状态码
* @returns {string} response.msg - 响应消息
* @returns {Object} response.data - 响应数据
* @returns {Array} response.data.yesterday - 昨天日期
* @returns {Array} response.data.families[] - 家庭列表
* @returns {string} response.data.families[].family_id - 家庭ID
* @returns {string} response.data.families[].name - 家庭名称
* @returns {string} response.data.families[].avatar_url - 头像URL
* @returns {string} response.data.families[].created_by_nickname - 创建人昵称
* @returns {Array} response.data.families[] - 家庭列表, 也可以是单位列表
* @returns {string} response.data.families[].family_id - 家庭ID, 也可以是单位ID
* @returns {string} response.data.families[].name - 家庭名称, 也可以是单位名称
* @returns {string} response.data.families[].avatar_url - 头像URL, 也可以是单位头像
* @returns {string} response.data.families[].created_by_nickname - 创建人昵称, 也可以是家庭数量
* @returns {number} response.data.families[].step - 步数
* @returns {number} response.data.families[].rank - 排名
* @returns {Array} response.data.current_family[] - 当前家庭列表
* @returns {string} response.data.current_family[].family_id - 家庭ID
* @returns {string} response.data.current_family[].name - 家庭名称
* @returns {string} response.data.current_family[].avatar_url - 头像URL
* @returns {string} response.data.current_family[].created_by_nickname - 创建人昵称
* @returns {string} response.data.current_family[].family_id - 家庭ID, 也可以是单位ID
* @returns {string} response.data.current_family[].name - 家庭名称, 也可以是单位名称
* @returns {string} response.data.current_family[].avatar_url - 头像URL, 也可以是单位头像
* @returns {string} response.data.current_family[].created_by_nickname - 创建人昵称, 也可以是家庭数量
* @returns {number} response.data.current_family[].step - 步数
* @returns {number} response.data.current_family[].rank - 排名
* @returns {number} response.data.current_family[].country - 区县
......
<!--
* @Date: 2025-01-09 00:00:00
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-18 17:09:27
* @LastEditTime: 2025-09-18 17:39:14
* @FilePath: /lls_program/src/components/RankingCard.vue
* @Description: 排行榜卡片组件
-->
......@@ -56,10 +56,10 @@
<image :src="activeTab === 'support' ? (topRanks[1]?.logo || defaultAvatar) : (topRanks[1]?.avatar_url || defaultAvatar)" class="avatar-img" mode="aspectFill" />
</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="leader-name">{{ activeTab === 'support' ? `${topRanks[1]?.created_by_nickname}个家庭` : `大家长:${topRanks[1]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">2</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[1]?.total_steps) : formatSteps(topRanks[1]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[1]?.step) : formatSteps(topRanks[1]?.step) }}</view>
</view>
</view>
......@@ -72,10 +72,10 @@
<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">{{ activeTab === 'support' ? `${topRanks[0]?.family_count}个家庭` : `大家长:${topRanks[0]?.created_by_nickname}` }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topRanks[0]?.created_by_nickname}个家庭` : `大家长:${topRanks[0]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">1</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[0]?.total_steps) : formatSteps(topRanks[0]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[0]?.step) : formatSteps(topRanks[0]?.step) }}</view>
</view>
</view>
......@@ -88,10 +88,10 @@
<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">{{ activeTab === 'support' ? `${topRanks[2]?.family_count}个家庭` : `大家长:${topRanks[2]?.created_by_nickname}` }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topRanks[2]?.created_by_nickname}个家庭` : `大家长:${topRanks[2]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">3</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[2]?.total_steps) : formatSteps(topRanks[2]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topRanks[2]?.step) : formatSteps(topRanks[2]?.step) }}</view>
</view>
</view>
</view>
......@@ -157,62 +157,8 @@ 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 supportData = ref(null)
const joinOrganization = () => {
Taro.navigateTo({
......@@ -226,6 +172,8 @@ const loading = ref(false)
// 排行榜日期
const currentDate = ref('')
/**
* 切换tab
* @param {string} tab - tab名称
......@@ -233,25 +181,6 @@ const currentDate = ref('')
const switchTab = async (tab) => {
if (activeTab.value === tab) return
// 助力榜使用mock数据
if (tab === 'support') {
// 开始切换动画
isContentSwitching.value = true
// 延迟切换内容,让淡出动画先执行
setTimeout(() => {
activeTab.value = tab
// 设置助力榜的日期
currentDate.value = supportData.value.yesterday
// 内容切换后,结束切换状态,开始淡入动画
setTimeout(() => {
isContentSwitching.value = false
}, 50)
}, 200)
return
}
// 开始切换动画
isContentSwitching.value = true
......@@ -278,13 +207,22 @@ const loadLeaderboardData = async (isInitialLoad = false) => {
loading.value = true
const params = {}
// 添加current_county参数:1=是,0=否,默认为否
// 根据activeTab动态设置:上海榜时为0,区域榜时为1
params.current_county = activeTab.value === 'shanghai' ? '0' : '1'
// 根据activeTab设置type参数
if (activeTab.value === 'shanghai') {
params.type = 'shanghai_family'
} else if (activeTab.value === 'support') {
params.type = 'institution'
} else {
params.type = 'county_family'
}
const response = await getStepLeaderboardAPI(params)
if (response.code) {
leaderboardData.value = response.data
if (activeTab.value === 'support') {
supportData.value = response.data
} else {
leaderboardData.value = response.data
}
// 设置当前日期
currentDate.value = response.data.yesterday
}
......@@ -393,10 +331,10 @@ const handleViewMore = () => {
const topRanks = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
if (!supportData.value || !supportData.value.families) {
return []
}
return supportData.value.kindergartens.slice(0, 3)
return supportData.value.families.slice(0, 3)
}
// 家庭排行榜数据
......@@ -409,20 +347,18 @@ const topRanks = computed(() => {
// 计算我的排名信息
const myRank = computed(() => {
if (activeTab.value === 'support') {
// 助力榜我的幼儿园信息
if (!supportData.value || !supportData.value.current_kindergarten) {
// 助力榜我的单位信息
if (!supportData.value || !supportData.value.current_family) {
return null
}
const currentKindergarten = supportData.value.current_kindergarten
const currentInstitution = supportData.value.current_family
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
...currentInstitution,
name: currentInstitution.name,
avatar_url: currentInstitution.avatar_url,
step: currentInstitution.step,
rank: currentInstitution.rank
}
}
......
<!--
* @Date: 2025-09-01 13:07:52
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-09-18 16:56:23
* @LastEditTime: 2025-09-18 17:38:03
* @FilePath: /lls_program/src/pages/FamilyRank/index.vue
* @Description: 文件描述
-->
......@@ -56,10 +56,10 @@
<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">{{ activeTab === 'support' ? `${topThreeData[1]?.family_count}个家庭` : `大家长:${topThreeData[1]?.created_by_nickname}` }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[1]?.created_by_nickname}个家庭` : `大家长:${topThreeData[1]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">2</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[1]?.total_steps) : formatSteps(topThreeData[1]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[1]?.step) : formatSteps(topThreeData[1]?.step) }}</view>
</view>
</view>
......@@ -72,10 +72,10 @@
<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">{{ activeTab === 'support' ? `${topThreeData[0]?.family_count}个家庭` : `大家长:${topThreeData[0]?.created_by_nickname}` }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[0]?.created_by_nickname}个家庭` : `大家长:${topThreeData[0]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">1</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[0]?.total_steps) : formatSteps(topThreeData[0]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[0]?.step) : formatSteps(topThreeData[0]?.step) }}</view>
</view>
</view>
......@@ -88,10 +88,10 @@
<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">{{ activeTab === 'support' ? `${topThreeData[2]?.family_count}个家庭` : `大家长:${topThreeData[2]?.created_by_nickname}` }}</view>
<view class="leader-name">{{ activeTab === 'support' ? `${topThreeData[2]?.created_by_nickname}个家庭` : `大家长:${topThreeData[2]?.created_by_nickname}` }}</view>
<view class="rank-number">
<view class="rank-num">3</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[2]?.total_steps) : formatSteps(topThreeData[2]?.step) }}</view>
<view class="steps-in-rank">{{ activeTab === 'support' ? formatSupportSteps(topThreeData[2]?.step) : formatSteps(topThreeData[2]?.step) }}</view>
</view>
</view>
</view>
......@@ -106,15 +106,15 @@
<view class="rank-info">
<view class="rank-num">{{ index + 4 }}</view>
<view class="avatar-small">
<image :src="activeTab === 'support' ? item.logo : (item.avatar_url || defaultAvatar)" class="avatar-small-img" mode="aspectFill" />
<image :src="activeTab === 'support' ? item.avatar_url : (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">{{ activeTab === 'support' ? `${item.family_count}个家庭` : `大家长:${item.created_by_nickname}` }}</view>
<view class="leader-name-small">{{ activeTab === 'support' ? `${item.created_by_nickname}个家庭` : `大家长:${item.created_by_nickname}` }}</view>
</view>
</view>
<view class="steps-info">
<view class="steps">{{ activeTab === 'support' ? formatSupportSteps(item.total_steps) : formatStepsForList(item.step) }}</view>
<view class="steps">{{ activeTab === 'support' ? formatSupportSteps(item.step) : formatStepsForList(item.step) }}</view>
</view>
</view>
</view>
......@@ -180,76 +180,8 @@ 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 supportData = ref(null)
const joinOrganization = () => {
Taro.navigateTo({
......@@ -263,6 +195,8 @@ const loading = ref(false)
// 当前日期
const currentDate = ref('')
/**
* 切换tab
* @param {string} tab - tab名称
......@@ -270,25 +204,6 @@ const currentDate = ref('')
const switchTab = async (tab) => {
if (activeTab.value === tab) return
// 助力榜使用mock数据
if (tab === 'support') {
// 开始切换动画
isContentSwitching.value = true
// 延迟切换内容,让淡出动画先执行
setTimeout(() => {
activeTab.value = tab
// 设置助力榜的日期
currentDate.value = supportData.value.yesterday
// 内容切换后,结束切换状态,开始淡入动画
setTimeout(() => {
isContentSwitching.value = false
}, 50)
}, 200)
return
}
// 开始切换动画
isContentSwitching.value = true
......@@ -349,13 +264,22 @@ const loadLeaderboardData = async (isInitialLoad = false) => {
loading.value = true
const params = {}
// 添加current_county参数:1=是,0=否,默认为否
// 根据activeTab动态设置:上海榜时为0,区域榜时为1
params.current_county = activeTab.value === 'shanghai' ? '0' : '1'
// 根据activeTab设置type参数
if (activeTab.value === 'shanghai') {
params.type = 'shanghai_family'
} else if (activeTab.value === 'support') {
params.type = 'institution'
} else {
params.type = 'county_family'
}
const response = await getStepLeaderboardAPI(params)
if (response.code) {
leaderboardData.value = response.data
if (activeTab.value === 'support') {
supportData.value = response.data
} else {
leaderboardData.value = response.data
}
currentDate.value = response.data.yesterday
}
} catch (error) {
......@@ -422,10 +346,10 @@ const getTabDisplayName = (region) => {
const topThreeData = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
if (!supportData.value || !supportData.value.families) {
return []
}
return supportData.value.kindergartens.slice(0, 3)
return supportData.value.families.slice(0, 3)
}
// 家庭排行榜数据
......@@ -441,10 +365,10 @@ const topThreeData = computed(() => {
const otherRankData = computed(() => {
if (activeTab.value === 'support') {
// 助力榜数据
if (!supportData.value || !supportData.value.kindergartens) {
if (!supportData.value || !supportData.value.families) {
return []
}
return supportData.value.kindergartens.slice(3)
return supportData.value.families.slice(3)
}
// 家庭排行榜数据
......@@ -459,19 +383,18 @@ const otherRankData = computed(() => {
*/
const myRankInfo = computed(() => {
if (activeTab.value === 'support') {
// 助力榜我的幼儿园信息
if (!supportData.value || !supportData.value.current_kindergarten) {
// 助力榜我的单位信息
if (!supportData.value || !supportData.value.current_family) {
return null
}
const currentKindergarten = supportData.value.current_kindergarten
const currentInstitution = supportData.value.current_family
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
...currentInstitution,
name: currentInstitution.name,
avatar_url: currentInstitution.avatar_url,
step: currentInstitution.step,
rank: currentInstitution.rank
}
}
......