diff --git a/public/src/js/scoresheet.js b/public/src/js/scoresheet.js
index 78cb015..3d81acc 100644
--- a/public/src/js/scoresheet.js
+++ b/public/src/js/scoresheet.js
@@ -178,8 +178,67 @@ class Scoresheet {
}
this.game.appendChild(this.tetsuoHana)
}
+
+ // Add leaderboard submit button if user is logged in
+ if (account.loggedIn && !this.multiplayer) {
+ this.leaderboardBtn = document.createElement("div")
+ this.leaderboardBtn.id = "leaderboard-submit-btn"
+ this.leaderboardBtn.innerHTML = "🏆 提交排行榜
Submit to Leaderboard"
+ this.leaderboardBtn.style.cssText = `
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ padding: 15px 25px;
+ background: linear-gradient(135deg, #ff6b9d, #c44db3);
+ color: white;
+ border-radius: 15px;
+ font-size: 18px;
+ font-family: ${strings.font || "sans-serif"};
+ text-align: center;
+ cursor: pointer;
+ z-index: 1000;
+ box-shadow: 0 4px 15px rgba(0,0,0,0.3);
+ border: 3px solid #fff;
+ transition: all 0.2s ease;
+ user-select: none;
+ `
+ this.leaderboardBtn.onmouseover = () => {
+ if (!this.leaderboardSubmitted) {
+ this.leaderboardBtn.style.transform = "scale(1.05)"
+ this.leaderboardBtn.style.boxShadow = "0 6px 20px rgba(0,0,0,0.4)"
+ }
+ }
+ this.leaderboardBtn.onmouseout = () => {
+ this.leaderboardBtn.style.transform = "scale(1)"
+ this.leaderboardBtn.style.boxShadow = "0 4px 15px rgba(0,0,0,0.3)"
+ }
+ this.leaderboardBtn.onclick = () => this.onLeaderboardBtnClick()
+ this.game.appendChild(this.leaderboardBtn)
+ }
}
+ onLeaderboardBtnClick() {
+ if (this.leaderboardSubmitted) {
+ return
+ }
+ if (!this.leaderboardData || !this.leaderboardData.songId) {
+ this.showLeaderboardNotification("no_song_id")
+ return
+ }
+
+ // Disable button and show submitting state
+ this.leaderboardBtn.innerHTML = "⏳ 提交中..."
+ this.leaderboardBtn.style.background = "linear-gradient(135deg, #888, #666)"
+ this.leaderboardBtn.style.cursor = "default"
+
+ this.submitToLeaderboard(
+ this.leaderboardData.songId,
+ this.leaderboardData.difficulty,
+ this.leaderboardData.scoreObj
+ )
+ }
+
+
redraw() {
if (!this.redrawRunning) {
return
@@ -933,6 +992,15 @@ class Scoresheet {
if (clearReached) {
crown = this.resultsObj.bad === 0 ? "gold" : "silver"
}
+
+ // Store data for manual leaderboard submission
+ this.leaderboardData = {
+ songId: songId,
+ difficulty: difficulty,
+ scoreObj: Object.assign({}, this.resultsObj)
+ }
+ this.leaderboardSubmitted = false
+
if (!oldScore || oldScore.points <= this.resultsObj.points) {
if (oldScore && (oldScore.crown === "gold" || oldScore.crown === "silver" && !crown)) {
crown = oldScore.crown
@@ -941,10 +1009,7 @@ class Scoresheet {
delete this.resultsObj.title
delete this.resultsObj.difficulty
delete this.resultsObj.gauge
- scoreStorage.add(hash, difficulty, this.resultsObj, true, title).then(() => {
- // Auto-submit to leaderboard if logged in and has song ID
- this.submitToLeaderboard(songId, difficulty, this.resultsObj)
- }).catch(() => {
+ scoreStorage.add(hash, difficulty, this.resultsObj, true, title).catch(() => {
this.showWarning = { name: "scoreSaveFailed" }
})
} else if (oldScore && (crown === "gold" && oldScore.crown !== "gold" || crown && !oldScore.crown)) {
@@ -957,13 +1022,13 @@ class Scoresheet {
this.scoreSaved = true
}
+
submitToLeaderboard(songId, difficulty, scoreObj) {
// Only submit if user is logged in and song has an ID
if (!account.loggedIn || !songId) {
return
}
-
var self = this
loader.getCsrfToken().then(token => {
var request = new XMLHttpRequest()
@@ -976,11 +1041,39 @@ class Scoresheet {
try {
var response = JSON.parse(request.responseText)
if (response.status === "ok") {
+ self.leaderboardSubmitted = true
self.showLeaderboardNotification(response.message)
+ // Update button to show success
+ if (self.leaderboardBtn) {
+ self.leaderboardBtn.innerHTML = "✅ 已提交
Submitted!"
+ self.leaderboardBtn.style.background = "linear-gradient(135deg, #4CAF50, #45a049)"
+ }
+ } else {
+ // Show error
+ self.showLeaderboardNotification("error")
+ if (self.leaderboardBtn) {
+ self.leaderboardBtn.innerHTML = "❌ 失败
Failed"
+ self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
+ }
}
} catch (e) {
console.error("Failed to parse leaderboard response:", e)
+ self.showLeaderboardNotification("error")
}
+ } else {
+ self.showLeaderboardNotification("error")
+ if (self.leaderboardBtn) {
+ self.leaderboardBtn.innerHTML = "❌ 失败
Failed"
+ self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
+ }
+ }
+ }
+
+ request.onerror = function () {
+ self.showLeaderboardNotification("error")
+ if (self.leaderboardBtn) {
+ self.leaderboardBtn.innerHTML = "❌ 失败
Failed"
+ self.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
}
}
@@ -991,9 +1084,15 @@ class Scoresheet {
}))
}).catch(() => {
console.log("Leaderboard submission failed")
+ this.showLeaderboardNotification("error")
+ if (this.leaderboardBtn) {
+ this.leaderboardBtn.innerHTML = "❌ 失败
Failed"
+ this.leaderboardBtn.style.background = "linear-gradient(135deg, #f44336, #d32f2f)"
+ }
})
}
+
showLeaderboardNotification(message) {
var notification = document.createElement("div")
notification.className = "leaderboard-notification"
@@ -1020,6 +1119,8 @@ class Scoresheet {
case "score_updated": text = "🎉 排行榜成绩已更新!"; break
case "score_not_higher": text = "📊 已有更高成绩"; break
case "score_too_low": text = "未进入排行榜前50"; break
+ case "error": text = "❌ 提交失败,请重试"; break
+ case "no_song_id": text = "❌ 无法提交:歌曲ID缺失"; break
default: text = "排行榜已更新"
}
notification.innerText = text
@@ -1063,10 +1164,17 @@ class Scoresheet {
if (!this.multiplayer) {
delete this.tetsuoHana
}
+ // Clean up leaderboard button
+ if (this.leaderboardBtn && this.leaderboardBtn.parentNode) {
+ this.leaderboardBtn.parentNode.removeChild(this.leaderboardBtn)
+ }
+ delete this.leaderboardBtn
+ delete this.leaderboardData
delete this.ctx
delete this.canvas
delete this.fadeScreen
delete this.results
delete this.rules
}
+
}