Fix: Validate songId as number and add user notification for leaderboard submission
This commit is contained in:
@@ -77,9 +77,16 @@ class Leaderboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchLeaderboard() {
|
async fetchLeaderboard() {
|
||||||
|
// Validate songId is a valid number
|
||||||
|
if (!this.songId || isNaN(parseInt(this.songId))) {
|
||||||
|
console.error("Invalid song ID for leaderboard:", this.songId)
|
||||||
|
this.leaderboardData = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var response = await loader.ajax(
|
var response = await loader.ajax(
|
||||||
`${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${this.songId}&difficulty=${this.difficulty}`
|
`${gameConfig.basedir || "/"}api/leaderboard/get?song_id=${parseInt(this.songId)}&difficulty=${this.difficulty}`
|
||||||
)
|
)
|
||||||
var data = JSON.parse(response)
|
var data = JSON.parse(response)
|
||||||
if (data.status === "ok") {
|
if (data.status === "ok") {
|
||||||
@@ -94,6 +101,7 @@ class Leaderboard {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
changeDifficulty(direction) {
|
changeDifficulty(direction) {
|
||||||
var difficulties = ["easy", "normal", "hard", "oni", "ura"]
|
var difficulties = ["easy", "normal", "hard", "oni", "ura"]
|
||||||
var currentIndex = difficulties.indexOf(this.difficulty)
|
var currentIndex = difficulties.indexOf(this.difficulty)
|
||||||
|
|||||||
@@ -958,27 +958,92 @@ class Scoresheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
submitToLeaderboard(songId, difficulty, scoreObj) {
|
submitToLeaderboard(songId, difficulty, scoreObj) {
|
||||||
// Only submit if user is logged in and song has valid ID
|
// Only submit if user is logged in and song has valid numeric ID
|
||||||
if (!account.loggedIn || !songId) {
|
if (!account.loggedIn || !songId || isNaN(parseInt(songId))) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var self = this
|
||||||
loader.getCsrfToken().then(token => {
|
loader.getCsrfToken().then(token => {
|
||||||
var request = new XMLHttpRequest()
|
var request = new XMLHttpRequest()
|
||||||
request.open("POST", "api/leaderboard/submit")
|
request.open("POST", "api/leaderboard/submit")
|
||||||
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
|
request.setRequestHeader("Content-Type", "application/json;charset=UTF-8")
|
||||||
request.setRequestHeader("X-CSRFToken", token)
|
request.setRequestHeader("X-CSRFToken", token)
|
||||||
|
|
||||||
|
request.onload = function () {
|
||||||
|
if (request.status === 200) {
|
||||||
|
try {
|
||||||
|
var response = JSON.parse(request.responseText)
|
||||||
|
if (response.status === "ok") {
|
||||||
|
self.showLeaderboardNotification(response.message)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to parse leaderboard response:", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
request.send(JSON.stringify({
|
request.send(JSON.stringify({
|
||||||
song_id: songId,
|
song_id: parseInt(songId),
|
||||||
difficulty: difficulty,
|
difficulty: difficulty,
|
||||||
score: scoreObj
|
score: scoreObj
|
||||||
}))
|
}))
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
// Silently fail - leaderboard submission is optional
|
|
||||||
console.log("Leaderboard submission failed")
|
console.log("Leaderboard submission failed")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showLeaderboardNotification(message) {
|
||||||
|
var notification = document.createElement("div")
|
||||||
|
notification.className = "leaderboard-notification"
|
||||||
|
notification.style.cssText = `
|
||||||
|
position: fixed;
|
||||||
|
top: 20px;
|
||||||
|
right: 20px;
|
||||||
|
padding: 15px 25px;
|
||||||
|
background: linear-gradient(135deg, #4a90e2, #7b68ee);
|
||||||
|
color: white;
|
||||||
|
border-radius: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: ${strings.font || "sans-serif"};
|
||||||
|
z-index: 10000;
|
||||||
|
box-shadow: 0 4px 15px rgba(0,0,0,0.3);
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateX(100px);
|
||||||
|
transition: all 0.3s ease-out;
|
||||||
|
`
|
||||||
|
|
||||||
|
var text = ""
|
||||||
|
switch (message) {
|
||||||
|
case "score_submitted": text = "🏆 成绩已提交到排行榜!"; break
|
||||||
|
case "score_updated": text = "🎉 排行榜成绩已更新!"; break
|
||||||
|
case "score_not_higher": text = "📊 已有更高成绩"; break
|
||||||
|
case "score_too_low": text = "未进入排行榜前50"; break
|
||||||
|
default: text = "排行榜已更新"
|
||||||
|
}
|
||||||
|
notification.innerText = text
|
||||||
|
|
||||||
|
document.body.appendChild(notification)
|
||||||
|
|
||||||
|
// Trigger animation
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.style.opacity = "1"
|
||||||
|
notification.style.transform = "translateX(0)"
|
||||||
|
}, 10)
|
||||||
|
|
||||||
|
// Remove after 3 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
notification.style.opacity = "0"
|
||||||
|
notification.style.transform = "translateX(100px)"
|
||||||
|
setTimeout(() => {
|
||||||
|
if (notification.parentNode) {
|
||||||
|
notification.parentNode.removeChild(notification)
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
clean() {
|
clean() {
|
||||||
this.keyboard.clean()
|
this.keyboard.clean()
|
||||||
this.gamepad.clean()
|
this.gamepad.clean()
|
||||||
|
|||||||
Reference in New Issue
Block a user