hookehuyr

feat(排行榜): 重构家庭排行榜页面并优化数据加载逻辑

重构家庭排行榜页面,使用真实API数据替代模拟数据
添加加载状态和暂无数据提示
优化区域切换逻辑,自动显示用户所在区县
改进步数显示格式,支持万单位显示
...@@ -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);
......