refactor: Improve data validation and avatar normalization
- Simplified data validation logic in the index.js file to handle cases where data is missing or incomplete. - Updated the index.wxml file to provide a clearer message when no ranking data is available. - Added a new method to normalize avatar URLs in the helper.js file, ensuring that default avatars are handled correctly across user and match controllers. - Refactored user and match controllers to utilize the new avatar normalization method, enhancing consistency in avatar display.
This commit is contained in:
parent
21c5bb9b57
commit
e871eed0e8
@ -156,17 +156,7 @@ Page({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const data = res && res.data ? res.data : null;
|
const data = res && res.data ? res.data : null;
|
||||||
if (!data) return;
|
if (!data || !data.ladderUserId || !data.page) {
|
||||||
|
|
||||||
if (data.qualified === false) {
|
|
||||||
wx.showToast({
|
|
||||||
title: `本月场次不足(${data.monthlyMatchCount}/${data.minMonthlyMatches})`,
|
|
||||||
icon: "none",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!data.ladderUserId || !data.page) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@
|
|||||||
<view wx:elif="{{!loading}}" class="empty-state">
|
<view wx:elif="{{!loading}}" class="empty-state">
|
||||||
<image class="empty-icon" src="/images/empty-ranking.svg" mode="aspectFit"></image>
|
<image class="empty-icon" src="/images/empty-ranking.svg" mode="aspectFit"></image>
|
||||||
<text class="empty-title">暂无排名数据</text>
|
<text class="empty-title">暂无排名数据</text>
|
||||||
<text class="empty-desc">每月完成3场比赛即可上榜</text>
|
<text class="empty-desc">暂无排名数据</text>
|
||||||
</view>
|
</view>
|
||||||
<!-- 加载更多 -->
|
<!-- 加载更多 -->
|
||||||
<view wx:if="{{loading}}" class="loading-state">
|
<view wx:if="{{loading}}" class="loading-state">
|
||||||
|
|||||||
@ -31,6 +31,19 @@ Page({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onPullDownRefresh() {
|
||||||
|
// 下拉刷新时重新加载比赛详情
|
||||||
|
if (this.data.matchId) {
|
||||||
|
this.loadMatchDetail().then(() => {
|
||||||
|
wx.stopPullDownRefresh()
|
||||||
|
}).catch(() => {
|
||||||
|
wx.stopPullDownRefresh()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
wx.stopPullDownRefresh()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 加载比赛详情
|
// 加载比赛详情
|
||||||
async loadMatchDetail() {
|
async loadMatchDetail() {
|
||||||
this.setData({ loading: true })
|
this.setData({ loading: true })
|
||||||
|
|||||||
@ -37,13 +37,6 @@ class LadderController {
|
|||||||
status: 1,
|
status: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 如果不是大屏显示,则需要满足每月最低参赛场次限制
|
|
||||||
if (!is_display) {
|
|
||||||
where.monthly_match_count = {
|
|
||||||
[Op.gte]: POWER_CALC.MIN_MONTHLY_MATCHES,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gender) {
|
if (gender) {
|
||||||
where.gender = gender;
|
where.gender = gender;
|
||||||
}
|
}
|
||||||
@ -87,13 +80,19 @@ class LadderController {
|
|||||||
|
|
||||||
// 添加排名
|
// 添加排名
|
||||||
const startRank = offset + 1;
|
const startRank = offset + 1;
|
||||||
const list = rows.map((lu, index) => ({
|
const list = rows.map((lu, index) => {
|
||||||
|
// 如果头像是服务端的默认头像URL,返回null让前端使用本地默认头像
|
||||||
|
let avatar = lu.user?.avatar;
|
||||||
|
if (avatar && (avatar.includes('/images/avatar-default.svg') || avatar.includes('avatar-default'))) {
|
||||||
|
avatar = null;
|
||||||
|
}
|
||||||
|
return {
|
||||||
rank: startRank + index,
|
rank: startRank + index,
|
||||||
id: lu.id,
|
id: lu.id,
|
||||||
userId: lu.user_id,
|
userId: lu.user_id,
|
||||||
realName: lu.real_name,
|
realName: lu.real_name,
|
||||||
nickname: lu.user?.nickname,
|
nickname: lu.user?.nickname,
|
||||||
avatar: lu.user?.avatar,
|
avatar: avatar || null,
|
||||||
gender: lu.gender,
|
gender: lu.gender,
|
||||||
level: lu.level,
|
level: lu.level,
|
||||||
levelName: LADDER_LEVEL_NAMES[lu.level],
|
levelName: LADDER_LEVEL_NAMES[lu.level],
|
||||||
@ -104,7 +103,8 @@ class LadderController {
|
|||||||
lu.match_count > 0
|
lu.match_count > 0
|
||||||
? Math.round((lu.win_count / lu.match_count) * 100)
|
? Math.round((lu.win_count / lu.match_count) * 100)
|
||||||
: 0,
|
: 0,
|
||||||
}));
|
};
|
||||||
|
});
|
||||||
|
|
||||||
res.json(pageResult(list, count, page, pageSize));
|
res.json(pageResult(list, count, page, pageSize));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -149,31 +149,11 @@ class LadderController {
|
|||||||
return res.status(404).json(error("未加入该门店天梯", 404));
|
return res.status(404).json(error("未加入该门店天梯", 404));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
!is_display &&
|
|
||||||
(ladderUser.monthly_match_count || 0) < POWER_CALC.MIN_MONTHLY_MATCHES
|
|
||||||
) {
|
|
||||||
return res.json(
|
|
||||||
success({
|
|
||||||
qualified: false,
|
|
||||||
ladderUserId: ladderUser.id,
|
|
||||||
monthlyMatchCount: ladderUser.monthly_match_count || 0,
|
|
||||||
minMonthlyMatches: POWER_CALC.MIN_MONTHLY_MATCHES,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const where = {
|
const where = {
|
||||||
store_id,
|
store_id,
|
||||||
status: 1,
|
status: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!is_display) {
|
|
||||||
where.monthly_match_count = {
|
|
||||||
[Op.gte]: POWER_CALC.MIN_MONTHLY_MATCHES,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (normalizedGender) {
|
if (normalizedGender) {
|
||||||
where.gender = normalizedGender;
|
where.gender = normalizedGender;
|
||||||
}
|
}
|
||||||
@ -233,17 +213,22 @@ class LadderController {
|
|||||||
gender: ladderUser.gender,
|
gender: ladderUser.gender,
|
||||||
status: 1,
|
status: 1,
|
||||||
power_score: { [Op.gt]: ladderUser.power_score },
|
power_score: { [Op.gt]: ladderUser.power_score },
|
||||||
monthly_match_count: { [Op.gte]: POWER_CALC.MIN_MONTHLY_MATCHES },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 如果头像是服务端的默认头像URL,返回null让前端使用本地默认头像
|
||||||
|
let avatar = ladderUser.user?.avatar;
|
||||||
|
if (avatar && (avatar.includes('/images/avatar-default.svg') || avatar.includes('avatar-default'))) {
|
||||||
|
avatar = null;
|
||||||
|
}
|
||||||
|
|
||||||
res.json(
|
res.json(
|
||||||
success({
|
success({
|
||||||
id: ladderUser.id,
|
id: ladderUser.id,
|
||||||
userId: ladderUser.user_id,
|
userId: ladderUser.user_id,
|
||||||
realName: ladderUser.real_name,
|
realName: ladderUser.real_name,
|
||||||
nickname: ladderUser.user?.nickname,
|
nickname: ladderUser.user?.nickname,
|
||||||
avatar: ladderUser.user?.avatar,
|
avatar: avatar || null,
|
||||||
memberCode: ladderUser.user?.member_code,
|
memberCode: ladderUser.user?.member_code,
|
||||||
gender: ladderUser.gender,
|
gender: ladderUser.gender,
|
||||||
level: ladderUser.level,
|
level: ladderUser.level,
|
||||||
@ -300,20 +285,25 @@ class LadderController {
|
|||||||
gender: ladderUser.gender,
|
gender: ladderUser.gender,
|
||||||
status: 1,
|
status: 1,
|
||||||
power_score: { [Op.gt]: ladderUser.power_score },
|
power_score: { [Op.gt]: ladderUser.power_score },
|
||||||
monthly_match_count: { [Op.gte]: POWER_CALC.MIN_MONTHLY_MATCHES },
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const matchCount = ladderUser.match_count || 0;
|
const matchCount = ladderUser.match_count || 0;
|
||||||
const winCount = ladderUser.win_count || 0;
|
const winCount = ladderUser.win_count || 0;
|
||||||
|
|
||||||
|
// 如果头像是服务端的默认头像URL,返回null让前端使用本地默认头像
|
||||||
|
let avatar = ladderUser.user && ladderUser.user.avatar;
|
||||||
|
if (avatar && (avatar.includes('/images/avatar-default.svg') || avatar.includes('avatar-default'))) {
|
||||||
|
avatar = null;
|
||||||
|
}
|
||||||
|
|
||||||
res.json(
|
res.json(
|
||||||
success({
|
success({
|
||||||
id: ladderUser.id,
|
id: ladderUser.id,
|
||||||
userId: ladderUser.user_id,
|
userId: ladderUser.user_id,
|
||||||
realName: ladderUser.real_name,
|
realName: ladderUser.real_name,
|
||||||
nickname: ladderUser.user && ladderUser.user.nickname,
|
nickname: ladderUser.user && ladderUser.user.nickname,
|
||||||
avatar: ladderUser.user && ladderUser.user.avatar,
|
avatar: avatar || null,
|
||||||
memberCode: ladderUser.user && ladderUser.user.member_code,
|
memberCode: ladderUser.user && ladderUser.user.member_code,
|
||||||
gender: ladderUser.gender,
|
gender: ladderUser.gender,
|
||||||
level: ladderUser.level,
|
level: ladderUser.level,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
const { Match, MatchGame, MatchPlayer, MatchRound, LadderUser, User, Store, sequelize } = require('../models');
|
const { Match, MatchGame, MatchPlayer, MatchRound, LadderUser, User, Store, sequelize } = require('../models');
|
||||||
const { MATCH_TYPES, MATCH_STATUS, CONFIRM_STATUS, RANKING_STAGE, MATCH_WEIGHTS, POWER_CALC } = require('../config/constants');
|
const { MATCH_TYPES, MATCH_STATUS, CONFIRM_STATUS, RANKING_STAGE, MATCH_WEIGHTS, POWER_CALC } = require('../config/constants');
|
||||||
const { generateMatchCode, success, error, getPagination, pageResult } = require('../utils/helper');
|
const { generateMatchCode, success, error, getPagination, pageResult, normalizeAvatarForClient } = require('../utils/helper');
|
||||||
const PowerCalculator = require('../services/powerCalculator');
|
const PowerCalculator = require('../services/powerCalculator');
|
||||||
const { sendChallengeNotification, sendScoreConfirmNotification, sendMatchNotification, broadcastToUsers } = require('../websocket');
|
const { sendChallengeNotification, sendScoreConfirmNotification, sendMatchNotification, broadcastToUsers } = require('../websocket');
|
||||||
const matchAdminController = require('./matchAdminController');
|
const matchAdminController = require('./matchAdminController');
|
||||||
@ -949,7 +949,7 @@ class MatchController {
|
|||||||
ladderUserId: p.ladder_user_id,
|
ladderUserId: p.ladder_user_id,
|
||||||
realName: p.ladderUser?.real_name || `选手${p.ladder_user_id}`,
|
realName: p.ladderUser?.real_name || `选手${p.ladder_user_id}`,
|
||||||
nickname: p.ladderUser?.user?.nickname,
|
nickname: p.ladderUser?.user?.nickname,
|
||||||
avatar: p.ladderUser?.user?.avatar,
|
avatar: normalizeAvatarForClient(p.ladderUser?.user?.avatar, req),
|
||||||
level: p.ladderUser?.level
|
level: p.ladderUser?.level
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1005,7 +1005,7 @@ class MatchController {
|
|||||||
ladderUserId: p.ladder_user_id,
|
ladderUserId: p.ladder_user_id,
|
||||||
realName: p.ladderUser?.real_name,
|
realName: p.ladderUser?.real_name,
|
||||||
nickname: p.ladderUser?.user?.nickname,
|
nickname: p.ladderUser?.user?.nickname,
|
||||||
avatar: p.ladderUser?.user?.avatar,
|
avatar: normalizeAvatarForClient(p.ladderUser?.user?.avatar, req),
|
||||||
level: p.ladderUser?.level,
|
level: p.ladderUser?.level,
|
||||||
initialPower: p.initial_power,
|
initialPower: p.initial_power,
|
||||||
winCount: p.win_count,
|
winCount: p.win_count,
|
||||||
@ -1140,7 +1140,7 @@ class MatchController {
|
|||||||
id: opponent.id,
|
id: opponent.id,
|
||||||
realName: opponent.real_name,
|
realName: opponent.real_name,
|
||||||
nickname: opponent.user?.nickname,
|
nickname: opponent.user?.nickname,
|
||||||
avatar: opponent.user?.avatar,
|
avatar: normalizeAvatarForClient(opponent.user?.avatar, req),
|
||||||
level: opponent.level,
|
level: opponent.level,
|
||||||
powerScore: opponent.power_score
|
powerScore: opponent.power_score
|
||||||
},
|
},
|
||||||
@ -1433,7 +1433,7 @@ class MatchController {
|
|||||||
id: opponent.id,
|
id: opponent.id,
|
||||||
realName: opponent.real_name,
|
realName: opponent.real_name,
|
||||||
nickname: opponent.user && opponent.user.nickname,
|
nickname: opponent.user && opponent.user.nickname,
|
||||||
avatar: opponent.user && opponent.user.avatar,
|
avatar: normalizeAvatarForClient(opponent.user && opponent.user.avatar, req),
|
||||||
level: opponent.level,
|
level: opponent.level,
|
||||||
powerScore: opponent.power_score
|
powerScore: opponent.power_score
|
||||||
}
|
}
|
||||||
@ -1544,7 +1544,7 @@ class MatchController {
|
|||||||
id: opponentLadder.id,
|
id: opponentLadder.id,
|
||||||
realName: opponentLadder.real_name,
|
realName: opponentLadder.real_name,
|
||||||
nickname: opponentLadder.user?.nickname,
|
nickname: opponentLadder.user?.nickname,
|
||||||
avatar: opponentLadder.user?.avatar,
|
avatar: normalizeAvatarForClient(opponentLadder.user?.avatar, req),
|
||||||
level: opponentLadder.level,
|
level: opponentLadder.level,
|
||||||
powerScore: opponentLadder.power_score
|
powerScore: opponentLadder.power_score
|
||||||
};
|
};
|
||||||
@ -1823,7 +1823,7 @@ class MatchController {
|
|||||||
id: challengerLadder.id,
|
id: challengerLadder.id,
|
||||||
realName: challengerLadder.real_name,
|
realName: challengerLadder.real_name,
|
||||||
nickname: challengerLadder.user?.nickname,
|
nickname: challengerLadder.user?.nickname,
|
||||||
avatar: challengerLadder.user?.avatar,
|
avatar: normalizeAvatarForClient(challengerLadder.user?.avatar, req),
|
||||||
level: challengerLadder.level,
|
level: challengerLadder.level,
|
||||||
powerScore: challengerLadder.power_score,
|
powerScore: challengerLadder.power_score,
|
||||||
userId: challengerLadder.user_id, // 添加 user_id,用于前端判断
|
userId: challengerLadder.user_id, // 添加 user_id,用于前端判断
|
||||||
@ -1836,7 +1836,7 @@ class MatchController {
|
|||||||
id: defenderLadder.id,
|
id: defenderLadder.id,
|
||||||
realName: defenderLadder.real_name,
|
realName: defenderLadder.real_name,
|
||||||
nickname: defenderLadder.user?.nickname,
|
nickname: defenderLadder.user?.nickname,
|
||||||
avatar: defenderLadder.user?.avatar,
|
avatar: normalizeAvatarForClient(defenderLadder.user?.avatar, req),
|
||||||
level: defenderLadder.level,
|
level: defenderLadder.level,
|
||||||
powerScore: defenderLadder.power_score,
|
powerScore: defenderLadder.power_score,
|
||||||
userId: defenderLadder.user_id, // 添加 user_id,用于前端判断
|
userId: defenderLadder.user_id, // 添加 user_id,用于前端判断
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const {
|
|||||||
calculateDistance,
|
calculateDistance,
|
||||||
getFullUrl,
|
getFullUrl,
|
||||||
normalizeAvatarUrl,
|
normalizeAvatarUrl,
|
||||||
|
normalizeAvatarForClient,
|
||||||
} = require("../utils/helper");
|
} = require("../utils/helper");
|
||||||
const { LADDER_LEVEL_NAMES } = require("../config/constants");
|
const { LADDER_LEVEL_NAMES } = require("../config/constants");
|
||||||
const { Op } = require("sequelize");
|
const { Op } = require("sequelize");
|
||||||
@ -76,7 +77,7 @@ class UserController {
|
|||||||
responseData.userInfo = {
|
responseData.userInfo = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
nickname: user.nickname,
|
nickname: user.nickname,
|
||||||
avatar: getFullUrl(user.avatar, req),
|
avatar: normalizeAvatarForClient(user.avatar, req),
|
||||||
phone: user.phone,
|
phone: user.phone,
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
memberCode: user.member_code,
|
memberCode: user.member_code,
|
||||||
@ -96,7 +97,7 @@ class UserController {
|
|||||||
? {
|
? {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
nickname: user.nickname,
|
nickname: user.nickname,
|
||||||
avatar: user.avatar,
|
avatar: normalizeAvatarForClient(user.avatar, req),
|
||||||
phone: user.phone,
|
phone: user.phone,
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
memberCode: user.member_code,
|
memberCode: user.member_code,
|
||||||
@ -281,7 +282,7 @@ class UserController {
|
|||||||
userInfo: {
|
userInfo: {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
nickname: user.nickname,
|
nickname: user.nickname,
|
||||||
avatar: getFullUrl(user.avatar, req),
|
avatar: normalizeAvatarForClient(user.avatar, req),
|
||||||
phone: user.phone,
|
phone: user.phone,
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
memberCode: user.member_code,
|
memberCode: user.member_code,
|
||||||
@ -373,7 +374,7 @@ class UserController {
|
|||||||
success(
|
success(
|
||||||
{
|
{
|
||||||
nickname: user.nickname,
|
nickname: user.nickname,
|
||||||
avatar: getFullUrl(user.avatar, req),
|
avatar: normalizeAvatarForClient(user.avatar, req),
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
},
|
},
|
||||||
"更新成功",
|
"更新成功",
|
||||||
@ -412,7 +413,7 @@ class UserController {
|
|||||||
const result = {
|
const result = {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
nickname: user.nickname,
|
nickname: user.nickname,
|
||||||
avatar: getFullUrl(user.avatar, req),
|
avatar: normalizeAvatarForClient(user.avatar, req),
|
||||||
phone: user.phone,
|
phone: user.phone,
|
||||||
gender: user.gender,
|
gender: user.gender,
|
||||||
memberCode: user.member_code,
|
memberCode: user.member_code,
|
||||||
|
|||||||
@ -204,6 +204,25 @@ function getFullUrl(path, req) {
|
|||||||
return `${protocol}://${host}${path}`;
|
return `${protocol}://${host}${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 规范化返回给客户端的头像URL
|
||||||
|
* 如果头像是服务端的默认头像URL,返回null让前端使用本地默认头像
|
||||||
|
* @param {string} avatar - 头像URL(可能是完整URL或相对路径)
|
||||||
|
* @param {object} req - Express request对象(用于获取host)
|
||||||
|
* @returns {string|null} 规范化后的头像URL,如果是默认头像则返回null
|
||||||
|
*/
|
||||||
|
function normalizeAvatarForClient(avatar, req) {
|
||||||
|
if (!avatar) return null;
|
||||||
|
|
||||||
|
// 检查是否是默认头像(相对路径或完整URL)
|
||||||
|
if (avatar.includes('/images/avatar-default.svg') || avatar.includes('avatar-default')) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 getFullUrl 处理其他头像URL
|
||||||
|
return getFullUrl(avatar, req) || null;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
generateMemberCode,
|
generateMemberCode,
|
||||||
generateMatchCode,
|
generateMatchCode,
|
||||||
@ -215,5 +234,6 @@ module.exports = {
|
|||||||
error,
|
error,
|
||||||
pageResult,
|
pageResult,
|
||||||
getFullUrl,
|
getFullUrl,
|
||||||
normalizeAvatarUrl
|
normalizeAvatarUrl,
|
||||||
|
normalizeAvatarForClient
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user