feat(排行榜): 重构家庭排行榜页面并优化数据加载逻辑
重构家庭排行榜页面,使用真实API数据替代模拟数据 添加加载状态和暂无数据提示 优化区域切换逻辑,自动显示用户所在区县 改进步数显示格式,支持万单位显示
Showing
4 changed files
with
229 additions
and
132 deletions
| ... | @@ -46,7 +46,7 @@ export const getPointRangesAPI = (params) => fn(fetch.get(Api.POINT_RANGES, para | ... | @@ -46,7 +46,7 @@ export const getPointRangesAPI = (params) => fn(fetch.get(Api.POINT_RANGES, para |
| 46 | /** | 46 | /** |
| 47 | * @description: 获取优惠券列表 | 47 | * @description: 获取优惠券列表 |
| 48 | * @param {Object} params - 查询参数 | 48 | * @param {Object} params - 查询参数 |
| 49 | - * @param {string} params.id - 优惠模块ID | 49 | + * @param {string} params.category_id - 优惠模块ID |
| 50 | * @param {string} params.keyword - 搜索关键词(可选) | 50 | * @param {string} params.keyword - 搜索关键词(可选) |
| 51 | * @param {string} params.point_range - 积分范围(可选) | 51 | * @param {string} params.point_range - 积分范围(可选) |
| 52 | * @param {string} params.sort - 排序字段(可选)ASC=从小到大,DESC=从大到小 | 52 | * @param {string} params.sort - 排序字段(可选)ASC=从小到大,DESC=从大到小 | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2023-12-22 10:29:37 | 2 | * @Date: 2023-12-22 10:29:37 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-09-09 11:49:32 | 4 | + * @LastEditTime: 2025-09-09 13:11:17 |
| 5 | * @FilePath: /lls_program/src/api/points.js | 5 | * @FilePath: /lls_program/src/api/points.js |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| ... | @@ -49,9 +49,9 @@ export const collectPointAPI = (params) => fn(fetch.post(Api.COLLECT_POINT, para | ... | @@ -49,9 +49,9 @@ export const collectPointAPI = (params) => fn(fetch.post(Api.COLLECT_POINT, para |
| 49 | export const getPointListAPI = (params) => fn(fetch.get(Api.POINT_LIST, params)); | 49 | export const getPointListAPI = (params) => fn(fetch.get(Api.POINT_LIST, params)); |
| 50 | 50 | ||
| 51 | /** | 51 | /** |
| 52 | - * @description: 查询步数排行榜, 加上county参数查询的是相关区域的数据, 数据长度为10个, 不加上county参数查询的是上海数据, 数据长度是20个, 都是固定长度. | 52 | + * @description: 查询步数排行榜, 数据长度为10个, 不加上county参数查询的是上海数据, 数据长度是20个, 都是固定长度. |
| 53 | * @param {Object} params - 请求参数 | 53 | * @param {Object} params - 请求参数 |
| 54 | - * @param {string} params.county - 区县 | 54 | + * @param {string} params.current_country - 是否只查我的当前家庭所在区县的排行榜。1=是,0=否。默认为否 |
| 55 | * @returns {Object} response - 响应对象 | 55 | * @returns {Object} response - 响应对象 |
| 56 | * @returns {number} response.code - 响应状态码 | 56 | * @returns {number} response.code - 响应状态码 |
| 57 | * @returns {string} response.msg - 响应消息 | 57 | * @returns {string} response.msg - 响应消息 |
| ... | @@ -71,5 +71,6 @@ export const getPointListAPI = (params) => fn(fetch.get(Api.POINT_LIST, params)) | ... | @@ -71,5 +71,6 @@ export const getPointListAPI = (params) => fn(fetch.get(Api.POINT_LIST, params)) |
| 71 | * @returns {string} response.data.current_family[].created_by_nickname - 创建人昵称 | 71 | * @returns {string} response.data.current_family[].created_by_nickname - 创建人昵称 |
| 72 | * @returns {number} response.data.current_family[].step - 步数 | 72 | * @returns {number} response.data.current_family[].step - 步数 |
| 73 | * @returns {number} response.data.current_family[].rank - 排名 | 73 | * @returns {number} response.data.current_family[].rank - 排名 |
| 74 | + * @returns {number} response.data.current_family[].country - 区县 | ||
| 74 | */ | 75 | */ |
| 75 | export const getStepLeaderboardAPI = (params) => fn(fetch.get(Api.STEP_LEADERBOARD, params)); | 76 | export const getStepLeaderboardAPI = (params) => fn(fetch.get(Api.STEP_LEADERBOARD, params)); | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-09-01 13:07:52 | 2 | * @Date: 2025-09-01 13:07:52 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-09-09 11:40:05 | 4 | + * @LastEditTime: 2025-09-09 14:07:23 |
| 5 | * @FilePath: /lls_program/src/pages/FamilyRank/index.vue | 5 | * @FilePath: /lls_program/src/pages/FamilyRank/index.vue |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | --> | 7 | --> |
| ... | @@ -16,150 +16,174 @@ | ... | @@ -16,150 +16,174 @@ |
| 16 | :class="{ 'indicator-shanghai': activeTab === 'shanghai' }" | 16 | :class="{ 'indicator-shanghai': activeTab === 'shanghai' }" |
| 17 | ></view> | 17 | ></view> |
| 18 | <view | 18 | <view |
| 19 | + v-for="region in availableRegions.slice(0, 2)" | ||
| 20 | + :key="region.value" | ||
| 19 | class="tab-item" | 21 | class="tab-item" |
| 20 | - :class="{ active: activeTab === 'huangpu' }" | 22 | + :class="{ active: activeTab === region.value }" |
| 21 | - @click="switchTab('huangpu')" | 23 | + @click="switchTab(region.value)" |
| 22 | > | 24 | > |
| 23 | - 黄埔榜 | 25 | + {{ region.text === '上海市' ? '上海榜' : region.text.replace('区', '榜') }} |
| 24 | - </view> | ||
| 25 | - <view | ||
| 26 | - class="tab-item" | ||
| 27 | - :class="{ active: activeTab === 'shanghai' }" | ||
| 28 | - @click="switchTab('shanghai')" | ||
| 29 | - > | ||
| 30 | - 上海榜 | ||
| 31 | </view> | 26 | </view> |
| 32 | </view> | 27 | </view> |
| 33 | </view> | 28 | </view> |
| 34 | 29 | ||
| 35 | <!-- 排行榜内容 --> | 30 | <!-- 排行榜内容 --> |
| 36 | <view class="rank-content" :class="{ 'content-switching': isContentSwitching }"> | 31 | <view class="rank-content" :class="{ 'content-switching': isContentSwitching }"> |
| 32 | + <!-- 加载状态 --> | ||
| 33 | + <view v-if="loading" class="loading-container"> | ||
| 34 | + <view class="loading-text">加载中...</view> | ||
| 35 | + </view> | ||
| 36 | + | ||
| 37 | <!-- 前三名展示 --> | 37 | <!-- 前三名展示 --> |
| 38 | - <view class="top-three"> | 38 | + <view v-else-if="topThreeData.length > 0" class="top-three"> |
| 39 | <!-- 第二名 --> | 39 | <!-- 第二名 --> |
| 40 | - <view class="rank-item second"> | 40 | + <view v-if="topThreeData[1]" class="rank-item second"> |
| 41 | <view class="crown crown-silver">👑</view> | 41 | <view class="crown crown-silver">👑</view> |
| 42 | <view class="avatar"> | 42 | <view class="avatar"> |
| 43 | - <image :src="topRanks[1]?.avatar" class="avatar-img" mode="aspectFill" /> | 43 | + <image :src="topThreeData[1]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" /> |
| 44 | </view> | 44 | </view> |
| 45 | - <view class="family-name">{{ topRanks[1]?.familyName }}</view> | 45 | + <view class="family-name">{{ topThreeData[1]?.name }}</view> |
| 46 | - <view class="leader-name">大家长:{{ topRanks[1]?.leaderName }}</view> | 46 | + <view class="leader-name">大家长:{{ topThreeData[1]?.created_by_nickname }}</view> |
| 47 | <view class="rank-number"> | 47 | <view class="rank-number"> |
| 48 | <view class="rank-num">2</view> | 48 | <view class="rank-num">2</view> |
| 49 | - <view class="steps-in-rank">{{ formatSteps(topRanks[1]?.steps) }}</view> | 49 | + <view class="steps-in-rank">{{ formatSteps(topThreeData[1]?.step) }}</view> |
| 50 | </view> | 50 | </view> |
| 51 | </view> | 51 | </view> |
| 52 | 52 | ||
| 53 | <!-- 第一名 --> | 53 | <!-- 第一名 --> |
| 54 | - <view class="rank-item first"> | 54 | + <view v-if="topThreeData[0]" class="rank-item first"> |
| 55 | <view class="crown crown-gold">👑</view> | 55 | <view class="crown crown-gold">👑</view> |
| 56 | <view class="avatar"> | 56 | <view class="avatar"> |
| 57 | - <image :src="topRanks[0]?.avatar" class="avatar-img" mode="aspectFill" /> | 57 | + <image :src="topThreeData[0]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" /> |
| 58 | </view> | 58 | </view> |
| 59 | - <view class="family-name">{{ topRanks[0]?.familyName }}</view> | 59 | + <view class="family-name">{{ topThreeData[0]?.name }}</view> |
| 60 | - <view class="leader-name">大家长:{{ topRanks[0]?.leaderName }}</view> | 60 | + <view class="leader-name">大家长:{{ topThreeData[0]?.created_by_nickname }}</view> |
| 61 | <view class="rank-number"> | 61 | <view class="rank-number"> |
| 62 | <view class="rank-num">1</view> | 62 | <view class="rank-num">1</view> |
| 63 | - <view class="steps-in-rank">{{ formatSteps(topRanks[0]?.steps) }}</view> | 63 | + <view class="steps-in-rank">{{ formatSteps(topThreeData[0]?.step) }}</view> |
| 64 | </view> | 64 | </view> |
| 65 | </view> | 65 | </view> |
| 66 | 66 | ||
| 67 | <!-- 第三名 --> | 67 | <!-- 第三名 --> |
| 68 | - <view class="rank-item third"> | 68 | + <view v-if="topThreeData[2]" class="rank-item third"> |
| 69 | <view class="crown crown-bronze">👑</view> | 69 | <view class="crown crown-bronze">👑</view> |
| 70 | <view class="avatar"> | 70 | <view class="avatar"> |
| 71 | - <image :src="topRanks[2]?.avatar" class="avatar-img" mode="aspectFill" /> | 71 | + <image :src="topThreeData[2]?.avatar_url || defaultAvatar" class="avatar-img" mode="aspectFill" /> |
| 72 | </view> | 72 | </view> |
| 73 | - <view class="family-name">{{ topRanks[2]?.familyName }}</view> | 73 | + <view class="family-name">{{ topThreeData[2]?.name }}</view> |
| 74 | - <view class="leader-name">大家长:{{ topRanks[2]?.leaderName }}</view> | 74 | + <view class="leader-name">大家长:{{ topThreeData[2]?.created_by_nickname }}</view> |
| 75 | <view class="rank-number"> | 75 | <view class="rank-number"> |
| 76 | <view class="rank-num">3</view> | 76 | <view class="rank-num">3</view> |
| 77 | - <view class="steps-in-rank">{{ formatSteps(topRanks[2]?.steps) }}</view> | 77 | + <view class="steps-in-rank">{{ formatSteps(topThreeData[2]?.step) }}</view> |
| 78 | </view> | 78 | </view> |
| 79 | </view> | 79 | </view> |
| 80 | </view> | 80 | </view> |
| 81 | 81 | ||
| 82 | <!-- 其他排名列表 --> | 82 | <!-- 其他排名列表 --> |
| 83 | - <view class="rank-list"> | 83 | + <view v-if="otherRankData.length > 0" class="rank-list"> |
| 84 | <view | 84 | <view |
| 85 | - v-for="(item, index) in otherRanks" | 85 | + v-for="(item, index) in otherRankData" |
| 86 | - :key="index" | 86 | + :key="item.family_id || index" |
| 87 | class="rank-list-item" | 87 | class="rank-list-item" |
| 88 | > | 88 | > |
| 89 | <view class="rank-info"> | 89 | <view class="rank-info"> |
| 90 | - <view class="rank-num">{{ item.rank }}</view> | 90 | + <view class="rank-num">{{ index + 4 }}</view> |
| 91 | <view class="avatar-small"> | 91 | <view class="avatar-small"> |
| 92 | - <image :src="item.avatar" class="avatar-small-img" /> | 92 | + <image :src="item.avatar_url || defaultAvatar" class="avatar-small-img" mode="aspectFill" /> |
| 93 | </view> | 93 | </view> |
| 94 | <view class="family-info"> | 94 | <view class="family-info"> |
| 95 | - <view class="family-name-small">{{ item.familyName }}</view> | 95 | + <view class="family-name-small">{{ item.name }}</view> |
| 96 | - <view class="leader-name-small">大家长:{{ item.leaderName }}</view> | 96 | + <view class="leader-name-small">大家长:{{ item.created_by_nickname }}</view> |
| 97 | </view> | 97 | </view> |
| 98 | </view> | 98 | </view> |
| 99 | <view class="steps-info"> | 99 | <view class="steps-info"> |
| 100 | - <view class="steps">{{ formatStepsForList(item.steps) }}</view> | 100 | + <view class="steps">{{ formatStepsForList(item.step) }}</view> |
| 101 | </view> | 101 | </view> |
| 102 | </view> | 102 | </view> |
| 103 | </view> | 103 | </view> |
| 104 | + | ||
| 105 | + <!-- 暂无数据 --> | ||
| 106 | + <view v-else-if="!loading" class="no-data"> | ||
| 107 | + <view class="no-data-text">暂无{{ currentRegionName }}排行榜数据</view> | ||
| 108 | + </view> | ||
| 104 | </view> | 109 | </view> |
| 105 | 110 | ||
| 106 | <!-- 我的排名悬浮卡片 --> | 111 | <!-- 我的排名悬浮卡片 --> |
| 107 | - <view class="my-rank-card"> | 112 | + <view v-if="myRankInfo" class="my-rank-card"> |
| 108 | <view class="my-rank-content"> | 113 | <view class="my-rank-content"> |
| 109 | <view class="my-rank-left"> | 114 | <view class="my-rank-left"> |
| 110 | - <view class="my-rank-number">{{ myRank.rank }}+</view> | 115 | + <view class="my-rank-number"> |
| 116 | + {{ myRankInfo.isNotRanked ? '未上榜' : (myRankInfo.rank > 99 ? myRankInfo.rank + '+' : myRankInfo.rank) }} | ||
| 117 | + </view> | ||
| 111 | <view class="my-avatar"> | 118 | <view class="my-avatar"> |
| 112 | - <image :src="myRank.avatar" class="my-avatar-img" mode="aspectFill" /> | 119 | + <image :src="myRankInfo.avatar_url || defaultAvatar" class="my-avatar-img" mode="aspectFill" /> |
| 113 | </view> | 120 | </view> |
| 114 | <view class="my-family-info"> | 121 | <view class="my-family-info"> |
| 115 | - <view class="my-family-name">{{ myRank.familyName }}</view> | 122 | + <view class="my-family-name">{{ myRankInfo.family_name }}</view> |
| 116 | - <view class="my-leader-name">大家长:{{ myRank.leaderName }}</view> | 123 | + <view class="my-leader-name">大家长:{{ myRankInfo.created_by_nickname }}</view> |
| 117 | </view> | 124 | </view> |
| 118 | </view> | 125 | </view> |
| 119 | <view class="my-rank-right"> | 126 | <view class="my-rank-right"> |
| 120 | - <view class="my-steps">{{ formatStepsForList(myRank.steps) }}</view> | 127 | + <view class="my-steps">{{ formatStepsForList(myRankInfo.step) }}</view> |
| 121 | - <view class="rank-status">{{ myRank.status }}</view> | 128 | + <view class="rank-status">{{ myRankInfo.isNotRanked ? '未上榜' : '已上榜' }}</view> |
| 122 | </view> | 129 | </view> |
| 123 | </view> | 130 | </view> |
| 124 | </view> | 131 | </view> |
| 125 | 132 | ||
| 126 | <!-- 返回顶部组件 --> | 133 | <!-- 返回顶部组件 --> |
| 127 | - <BackToTop :distance="200" /> | 134 | + <!-- <BackToTop :distance="200" /> --> |
| 128 | </view> | 135 | </view> |
| 129 | </template> | 136 | </template> |
| 130 | 137 | ||
| 131 | <script setup> | 138 | <script setup> |
| 132 | -import { ref, computed } from 'vue' | 139 | +import { ref, computed, onMounted } from 'vue' |
| 133 | import BackToTop from '@/components/BackToTop.vue' | 140 | import BackToTop from '@/components/BackToTop.vue' |
| 141 | +// 默认头像 | ||
| 142 | +const defaultAvatar = 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg' | ||
| 134 | // 导入接口 | 143 | // 导入接口 |
| 135 | import { getStepLeaderboardAPI } from '@/api/points' | 144 | import { getStepLeaderboardAPI } from '@/api/points' |
| 136 | -import { getFamilyInfoAPI } from '@/api/family' | ||
| 137 | 145 | ||
| 138 | // 区域信息 | 146 | // 区域信息 |
| 139 | -import { SHANGHAI_REGION } from '@/utils/config' | 147 | +import { SHANGHAI_REGION as shanghaiRegion } from '@/utils/config' |
| 148 | + | ||
| 149 | +const shanghaiRegionOptions = computed(() => { | ||
| 150 | + return shanghaiRegion.map(item => ({ | ||
| 151 | + text: item.text, | ||
| 152 | + value: String(item.value) | ||
| 153 | + })) | ||
| 154 | +}) | ||
| 140 | 155 | ||
| 141 | // 当前激活的tab | 156 | // 当前激活的tab |
| 142 | -const activeTab = ref('huangpu') | 157 | +const activeTab = ref('') |
| 143 | 158 | ||
| 144 | // 内容切换状态 | 159 | // 内容切换状态 |
| 145 | const isContentSwitching = ref(false) | 160 | const isContentSwitching = ref(false) |
| 146 | 161 | ||
| 162 | +// 排行榜数据 | ||
| 163 | +const leaderboardData = ref(null) | ||
| 164 | + | ||
| 165 | +// 加载状态 | ||
| 166 | +const loading = ref(false) | ||
| 167 | + | ||
| 147 | 168 | ||
| 148 | 169 | ||
| 149 | /** | 170 | /** |
| 150 | * 切换tab | 171 | * 切换tab |
| 151 | * @param {string} tab - tab名称 | 172 | * @param {string} tab - tab名称 |
| 152 | */ | 173 | */ |
| 153 | -const switchTab = (tab) => { | 174 | +const switchTab = async (tab) => { |
| 154 | if (activeTab.value === tab) return | 175 | if (activeTab.value === tab) return |
| 155 | 176 | ||
| 156 | // 开始切换动画 | 177 | // 开始切换动画 |
| 157 | isContentSwitching.value = true | 178 | isContentSwitching.value = true |
| 158 | 179 | ||
| 159 | // 延迟切换内容,让淡出动画先执行 | 180 | // 延迟切换内容,让淡出动画先执行 |
| 160 | - setTimeout(() => { | 181 | + setTimeout(async () => { |
| 161 | activeTab.value = tab | 182 | activeTab.value = tab |
| 162 | 183 | ||
| 184 | + // 重新加载排行榜数据 | ||
| 185 | + await loadLeaderboardData(false) | ||
| 186 | + | ||
| 163 | // 内容切换后,结束切换状态,开始淡入动画 | 187 | // 内容切换后,结束切换状态,开始淡入动画 |
| 164 | setTimeout(() => { | 188 | setTimeout(() => { |
| 165 | isContentSwitching.value = false | 189 | isContentSwitching.value = false |
| ... | @@ -173,7 +197,10 @@ const switchTab = (tab) => { | ... | @@ -173,7 +197,10 @@ const switchTab = (tab) => { |
| 173 | * @returns {string} 格式化后的步数 | 197 | * @returns {string} 格式化后的步数 |
| 174 | */ | 198 | */ |
| 175 | const formatSteps = (steps) => { | 199 | const formatSteps = (steps) => { |
| 176 | - return steps ? steps.toLocaleString() : '0' | 200 | + if (steps >= 10000) { |
| 201 | + return (steps / 10000).toFixed(1) + '万' | ||
| 202 | + } | ||
| 203 | + return steps?.toString() | ||
| 177 | } | 204 | } |
| 178 | 205 | ||
| 179 | /** | 206 | /** |
| ... | @@ -187,85 +214,128 @@ const formatStepsForList = (steps) => { | ... | @@ -187,85 +214,128 @@ const formatStepsForList = (steps) => { |
| 187 | 214 | ||
| 188 | 215 | ||
| 189 | 216 | ||
| 190 | -// 前三名数据 | 217 | +/** |
| 191 | -const topRanks = ref([ | 218 | + * 加载排行榜数据 |
| 192 | - { | 219 | + * @param {boolean} isInitialLoad - 是否为初始加载,避免无限递归 |
| 193 | - rank: 1, | 220 | + */ |
| 194 | - familyName: '明媚的晴', | 221 | +const loadLeaderboardData = async (isInitialLoad = false) => { |
| 195 | - leaderName: '张明', | 222 | + try { |
| 196 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | 223 | + loading.value = true |
| 197 | - steps: 45670 | 224 | + const params = {} |
| 198 | - }, | 225 | + |
| 199 | - { | 226 | + // 添加current_country参数:1=是,0=否,默认为否 |
| 200 | - rank: 2, | 227 | + // 根据activeTab动态设置:上海榜时为0,区域榜时为1 |
| 201 | - familyName: '甜心小桃', | 228 | + params.current_country = activeTab.value === 'shanghai' ? '0' : '1' |
| 202 | - leaderName: '李桃', | 229 | + |
| 203 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | 230 | + const response = await getStepLeaderboardAPI(params) |
| 204 | - steps: 42350 | 231 | + if (response.code) { |
| 205 | - }, | 232 | + leaderboardData.value = response.data |
| 206 | - { | 233 | + |
| 207 | - rank: 3, | 234 | + // 只在初始加载时从current_family.county获取区县信息,设置默认tab |
| 208 | - familyName: '真心找爱', | 235 | + if (isInitialLoad && response.data.current_family) { |
| 209 | - leaderName: '王真', | 236 | + const currentFamilyCounty = response.data.current_family.county; |
| 210 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | 237 | + if (currentFamilyCounty && String(currentFamilyCounty) !== activeTab.value) { |
| 211 | - steps: 38920 | 238 | + // 只在county与当前activeTab不同时才设置,确保county字段为字符串格式 |
| 239 | + activeTab.value = String(currentFamilyCounty) | ||
| 240 | + // 设置activeTab后需要重新加载数据以获取正确的区县排行榜 | ||
| 241 | + await loadLeaderboardData(false) | ||
| 242 | + return | ||
| 243 | + } | ||
| 244 | + } | ||
| 245 | + } | ||
| 246 | + } catch (error) { | ||
| 247 | + console.error('获取排行榜数据失败:', error) | ||
| 248 | + } finally { | ||
| 249 | + loading.value = false | ||
| 212 | } | 250 | } |
| 213 | -]) | 251 | +} |
| 214 | - | 252 | + |
| 215 | -// 其他排名数据 | 253 | +/** |
| 216 | -const otherRanks = ref([ | 254 | + * 计算当前区域的中文名称 |
| 217 | - { | 255 | + */ |
| 218 | - rank: 4, | 256 | +const currentRegionName = computed(() => { |
| 219 | - familyName: '藏点理想者', | 257 | + if (activeTab.value === 'shanghai') { |
| 220 | - leaderName: '陈理', | 258 | + return '上海市' |
| 221 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 222 | - steps: 35010 | ||
| 223 | - }, | ||
| 224 | - { | ||
| 225 | - rank: 5, | ||
| 226 | - familyName: '熊熊熊很大', | ||
| 227 | - leaderName: '熊大', | ||
| 228 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 229 | - steps: 32780 | ||
| 230 | - }, | ||
| 231 | - { | ||
| 232 | - rank: 6, | ||
| 233 | - familyName: '夏花流年❤️', | ||
| 234 | - leaderName: '夏花', | ||
| 235 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 236 | - steps: 28450 | ||
| 237 | - }, | ||
| 238 | - { | ||
| 239 | - rank: 7, | ||
| 240 | - familyName: '给大家拜个早年', | ||
| 241 | - leaderName: '拜年', | ||
| 242 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 243 | - steps: 25890 | ||
| 244 | - }, | ||
| 245 | - { | ||
| 246 | - rank: 8, | ||
| 247 | - familyName: '寻一人觅真心', | ||
| 248 | - leaderName: '觅心', | ||
| 249 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 250 | - steps: 23800 | ||
| 251 | - }, | ||
| 252 | - { | ||
| 253 | - rank: 9, | ||
| 254 | - familyName: '大咪花💕', | ||
| 255 | - leaderName: '大咪', | ||
| 256 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | ||
| 257 | - steps: 21669 | ||
| 258 | } | 259 | } |
| 259 | -]) | 260 | + const region = shanghaiRegionOptions.value.find(item => item.value === activeTab.value) |
| 260 | - | 261 | + return region ? region.text : '黄浦区' |
| 261 | -// 我的排名信息 | 262 | +}) |
| 262 | -const myRank = ref({ | 263 | + |
| 263 | - rank: 99, | 264 | +/** |
| 264 | - familyName: '和谐之家', | 265 | + * 计算可用的区域选项 |
| 265 | - leaderName: '陈家明', | 266 | + */ |
| 266 | - avatar: 'https://cdn.ipadbiz.cn/hager/0513-1_FsxMk28AGz6N_D1zZFFOl_EaRdss.png', | 267 | +const availableRegions = computed(() => { |
| 267 | - steps: 8920, | 268 | + // 从current_family.county获取区县信息,优先显示用户区域,然后是上海市 |
| 268 | - status: '未上榜' | 269 | + const currentFamilyCounty = leaderboardData.value?.current_family?.county |
| 270 | + if (currentFamilyCounty) { | ||
| 271 | + // 确保county字段为字符串格式进行比较 | ||
| 272 | + const userCounty = String(currentFamilyCounty) | ||
| 273 | + // value值需要转成字符串进行比较 | ||
| 274 | + const userRegion = shanghaiRegionOptions.value.find(item => item.value === userCounty) | ||
| 275 | + if (userRegion) { | ||
| 276 | + // 用户区域在第一位,上海市在第二位 | ||
| 277 | + return [userRegion, { text: '上海市', value: 'shanghai' }] | ||
| 278 | + } | ||
| 279 | + } | ||
| 280 | + | ||
| 281 | + // 默认显示黄浦区和上海市 | ||
| 282 | + return [ | ||
| 283 | + { text: '黄浦区', value: '310101' }, | ||
| 284 | + { text: '上海市', value: 'shanghai' } | ||
| 285 | + ] | ||
| 286 | +}) | ||
| 287 | + | ||
| 288 | +/** | ||
| 289 | + * 计算前三名数据 | ||
| 290 | + */ | ||
| 291 | +const topThreeData = computed(() => { | ||
| 292 | + if (!leaderboardData.value || !leaderboardData.value.families) { | ||
| 293 | + return [] | ||
| 294 | + } | ||
| 295 | + return leaderboardData.value.families.slice(0, 3) | ||
| 296 | +}) | ||
| 297 | + | ||
| 298 | +/** | ||
| 299 | + * 计算其他排名数据 | ||
| 300 | + */ | ||
| 301 | +const otherRankData = computed(() => { | ||
| 302 | + if (!leaderboardData.value || !leaderboardData.value.families) { | ||
| 303 | + return [] | ||
| 304 | + } | ||
| 305 | + return leaderboardData.value.families.slice(3) | ||
| 306 | +}) | ||
| 307 | + | ||
| 308 | +/** | ||
| 309 | + * 计算我的排名信息 | ||
| 310 | + */ | ||
| 311 | +const myRankInfo = computed(() => { | ||
| 312 | + if (!leaderboardData.value || !leaderboardData.value.current_family) { | ||
| 313 | + return null | ||
| 314 | + } | ||
| 315 | + | ||
| 316 | + const currentFamily = leaderboardData.value.current_family | ||
| 317 | + | ||
| 318 | + // 如果没有排名信息,返回未上榜状态 | ||
| 319 | + if (!currentFamily.rank || currentFamily.rank === 0) { | ||
| 320 | + return { | ||
| 321 | + ...currentFamily, | ||
| 322 | + rank: 0, | ||
| 323 | + isNotRanked: true | ||
| 324 | + } | ||
| 325 | + } | ||
| 326 | + | ||
| 327 | + return { | ||
| 328 | + ...currentFamily, | ||
| 329 | + isNotRanked: false | ||
| 330 | + } | ||
| 331 | +}) | ||
| 332 | + | ||
| 333 | +/** | ||
| 334 | + * 页面初始化 | ||
| 335 | + */ | ||
| 336 | +onMounted(async () => { | ||
| 337 | + // 直接加载排行榜数据,使用current_country参数获取当前家庭所在区县信息 | ||
| 338 | + await loadLeaderboardData(true) | ||
| 269 | }) | 339 | }) |
| 270 | </script> | 340 | </script> |
| 271 | 341 | ||
| ... | @@ -573,6 +643,32 @@ const myRank = ref({ | ... | @@ -573,6 +643,32 @@ const myRank = ref({ |
| 573 | } | 643 | } |
| 574 | } | 644 | } |
| 575 | 645 | ||
| 646 | + /* 加载状态 */ | ||
| 647 | + .loading-container { | ||
| 648 | + display: flex; | ||
| 649 | + justify-content: center; | ||
| 650 | + align-items: center; | ||
| 651 | + padding: 100rpx 0; | ||
| 652 | + } | ||
| 653 | + | ||
| 654 | + .loading-text { | ||
| 655 | + font-size: 28rpx; | ||
| 656 | + color: rgba(255, 255, 255, 0.8); | ||
| 657 | + } | ||
| 658 | + | ||
| 659 | + /* 暂无数据 */ | ||
| 660 | + .no-data { | ||
| 661 | + display: flex; | ||
| 662 | + justify-content: center; | ||
| 663 | + align-items: center; | ||
| 664 | + padding: 100rpx 0; | ||
| 665 | + } | ||
| 666 | + | ||
| 667 | + .no-data-text { | ||
| 668 | + font-size: 28rpx; | ||
| 669 | + color: rgba(255, 255, 255, 0.8); | ||
| 670 | + } | ||
| 671 | + | ||
| 576 | .my-rank-card { | 672 | .my-rank-card { |
| 577 | position: fixed; | 673 | position: fixed; |
| 578 | bottom: 40rpx; | 674 | bottom: 40rpx; | ... | ... |
| ... | @@ -278,7 +278,7 @@ const fetchCouponList = async (reset = false) => { | ... | @@ -278,7 +278,7 @@ const fetchCouponList = async (reset = false) => { |
| 278 | sort: sortOrder.value.toUpperCase(), | 278 | sort: sortOrder.value.toUpperCase(), |
| 279 | page: reset ? 0 : currentPage.value, | 279 | page: reset ? 0 : currentPage.value, |
| 280 | limit: 10, | 280 | limit: 10, |
| 281 | - id: pageParams.value.id || undefined | 281 | + category_id: pageParams.value.id || undefined |
| 282 | }; | 282 | }; |
| 283 | 283 | ||
| 284 | const { code, data } = await getCouponListAPI(params); | 284 | const { code, data } = await getCouponListAPI(params); | ... | ... |
-
Please register or login to post a comment