feat: 添加
This commit is contained in:
parent
7ba4f6ec29
commit
9a65194e4f
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,3 +1,3 @@
|
|||||||
/build/
|
/yun/build/
|
||||||
/dist/
|
/yun/dist/
|
||||||
client.spec
|
/yun/client.spec
|
||||||
|
|||||||
134
yun/client.py
134
yun/client.py
@ -3,9 +3,8 @@ from tkinter import messagebox, simpledialog
|
|||||||
import time
|
import time
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
API_URL = "http://47.80.30.142:6364" # Flask 接口地址
|
API_URL = "http://47.80.30.142:6364/"
|
||||||
|
|
||||||
# 读取排行榜数据(从 Flask 获取)
|
|
||||||
def load_leaderboard():
|
def load_leaderboard():
|
||||||
try:
|
try:
|
||||||
resp = requests.get(f"{API_URL}/get_board")
|
resp = requests.get(f"{API_URL}/get_board")
|
||||||
@ -17,52 +16,62 @@ def load_leaderboard():
|
|||||||
messagebox.showerror("错误", f"无法加载排行榜数据:{e}")
|
messagebox.showerror("错误", f"无法加载排行榜数据:{e}")
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# 获取参赛者姓名
|
|
||||||
def get_player_name():
|
def get_player_name():
|
||||||
name = simpledialog.askstring("参赛者姓名", "请输入您的姓名:")
|
name = simpledialog.askstring("参赛者姓名", "请输入您的姓名:")
|
||||||
if not name:
|
if not name:
|
||||||
messagebox.showwarning("警告", "姓名不能为空,请重新输入。")
|
messagebox.showwarning("警告", "姓名不能为空")
|
||||||
return get_player_name()
|
return get_player_name()
|
||||||
return name
|
return name
|
||||||
|
|
||||||
# 上传成绩并刷新排行榜
|
def get_player_message():
|
||||||
def submit_result(name, error):
|
return simpledialog.askstring("祝贺留言", "你太棒了!要留下什么话?")
|
||||||
try:
|
|
||||||
# 先下载当前排行榜
|
|
||||||
leaderboard = load_leaderboard()
|
|
||||||
|
|
||||||
# 查找或更新当前用户成绩(误差更小的)
|
def submit_result(name, error, message=None):
|
||||||
found = False
|
try:
|
||||||
|
leaderboard = load_leaderboard()
|
||||||
|
updated = False
|
||||||
for entry in leaderboard:
|
for entry in leaderboard:
|
||||||
if entry["name"] == name:
|
if entry["name"] == name:
|
||||||
found = True
|
|
||||||
if abs(error) < entry["error"]:
|
if abs(error) < entry["error"]:
|
||||||
entry["error"] = round(abs(error), 3)
|
entry["error"] = round(abs(error), 3)
|
||||||
|
if abs(error) < 0.1 and message:
|
||||||
|
entry["message"] = message
|
||||||
|
updated = True
|
||||||
break
|
break
|
||||||
if not found:
|
if not updated:
|
||||||
leaderboard.append({"name": name, "error": round(abs(error), 3)})
|
entry = {"name": name, "error": round(abs(error), 3)}
|
||||||
|
if abs(error) < 0.1 and message:
|
||||||
|
entry["message"] = message
|
||||||
|
leaderboard.append(entry)
|
||||||
|
|
||||||
# 按误差升序排序
|
|
||||||
leaderboard.sort(key=lambda x: x["error"])
|
leaderboard.sort(key=lambda x: x["error"])
|
||||||
|
|
||||||
# 提交新的排行榜到服务器
|
|
||||||
resp = requests.post(f"{API_URL}/set_board", json=leaderboard)
|
resp = requests.post(f"{API_URL}/set_board", json=leaderboard)
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
update_rank_display(leaderboard)
|
update_rank_display(leaderboard)
|
||||||
|
update_message_display(leaderboard)
|
||||||
else:
|
else:
|
||||||
messagebox.showerror("提交失败", "提交成绩失败,请稍后再试。")
|
messagebox.showerror("提交失败", "成绩上传失败")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messagebox.showerror("错误", f"提交成绩时出错:{e}")
|
messagebox.showerror("错误", f"提交成绩时出错:{e}")
|
||||||
|
|
||||||
|
|
||||||
# 显示排行榜
|
|
||||||
def update_rank_display(leaderboard):
|
def update_rank_display(leaderboard):
|
||||||
rank_listbox.delete(0, tk.END)
|
rank_listbox.delete(0, tk.END)
|
||||||
for i, entry in enumerate(leaderboard, 1):
|
for i, entry in enumerate(leaderboard, 1):
|
||||||
n, e = entry["name"], entry["error"]
|
rank_listbox.insert(tk.END, f"{i}. {entry['name']:<8} 误差: {entry['error']:.3f}s")
|
||||||
rank_listbox.insert(tk.END, f"{i}. {n:<8} 误差: {e:.3f}s")
|
|
||||||
|
def update_message_display(leaderboard):
|
||||||
|
messages.clear()
|
||||||
|
for entry in leaderboard:
|
||||||
|
if "message" in entry and entry["message"]:
|
||||||
|
messages.append(f"{entry['name']}:{entry['message']}")
|
||||||
|
|
||||||
|
def scroll_messages():
|
||||||
|
if messages:
|
||||||
|
msg = messages.pop(0)
|
||||||
|
message_var.set(msg)
|
||||||
|
messages.append(msg)
|
||||||
|
root.after(3000, scroll_messages)
|
||||||
|
|
||||||
# 更新时间函数
|
|
||||||
def update_time():
|
def update_time():
|
||||||
if flag:
|
if flag:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@ -72,30 +81,13 @@ def update_time():
|
|||||||
|
|
||||||
def show_win_animation():
|
def show_win_animation():
|
||||||
anim = tk.Toplevel(root)
|
anim = tk.Toplevel(root)
|
||||||
anim.geometry("320x200")
|
anim.geometry("300x150")
|
||||||
anim.title("🎉 胜利动画")
|
anim.configure(bg="white")
|
||||||
anim.configure(bg="#ffffff")
|
tk.Label(anim, text="🎉 完美掌控时间!", font=("微软雅黑", 18, "bold"), bg="white").pack(expand=True)
|
||||||
anim.attributes("-topmost", True)
|
anim.after(1500, anim.destroy)
|
||||||
|
|
||||||
label = tk.Label(anim, text="🎉 完美掌控时间!🎉", font=("微软雅黑", 18, "bold"), bg="#ffffff")
|
|
||||||
label.pack(expand=True)
|
|
||||||
|
|
||||||
colors = ["#ff6666", "#66cc66", "#3399ff", "#ffcc00", "#cc66ff"]
|
|
||||||
sizes = [18, 22, 26, 30, 26, 22, 18]
|
|
||||||
|
|
||||||
def animate(i=0):
|
|
||||||
if i < len(sizes):
|
|
||||||
label.config(font=("微软雅黑", sizes[i], "bold"), fg=colors[i % len(colors)])
|
|
||||||
anim.after(150, animate, i + 1)
|
|
||||||
else:
|
|
||||||
anim.destroy()
|
|
||||||
|
|
||||||
animate()
|
|
||||||
|
|
||||||
# 控制开始/停止
|
|
||||||
def change():
|
def change():
|
||||||
global flag, start_time
|
global flag, start_time
|
||||||
|
|
||||||
if not flag:
|
if not flag:
|
||||||
flag = True
|
flag = True
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
@ -105,57 +97,57 @@ def change():
|
|||||||
end_time = time.time()
|
end_time = time.time()
|
||||||
timex = end_time - start_time
|
timex = end_time - start_time
|
||||||
error = timex - 10
|
error = timex - 10
|
||||||
|
|
||||||
timex_label.config(text=f"✅ 实际时间:{timex:.3f} 秒\n误差:{error:.3f} 秒")
|
timex_label.config(text=f"✅ 实际时间:{timex:.3f} 秒\n误差:{error:.3f} 秒")
|
||||||
|
|
||||||
name = get_player_name()
|
name = get_player_name()
|
||||||
submit_result(name, error)
|
message = None
|
||||||
|
if abs(error) < 0.1:
|
||||||
if abs(error) < 0.01:
|
message = get_player_message()
|
||||||
show_win_animation()
|
show_win_animation()
|
||||||
else:
|
else:
|
||||||
messagebox.showinfo("结果", "还差一点点,再接再厉吧!")
|
messagebox.showinfo("结果", "再接再厉!")
|
||||||
|
submit_result(name, error, message)
|
||||||
|
|
||||||
# ================================
|
# ============================ UI ============================
|
||||||
# 主窗口
|
|
||||||
# ================================
|
|
||||||
|
|
||||||
root = tk.Tk()
|
root = tk.Tk()
|
||||||
root.geometry("340x500")
|
root.geometry("360x550")
|
||||||
root.title("10秒挑战")
|
root.title("10秒挑战")
|
||||||
root.configure(bg="#f0faff")
|
root.configure(bg="#f0faff")
|
||||||
|
|
||||||
# 标题
|
title_label = tk.Label(root, text="🎯 10 秒挑战 🎯", font=("微软雅黑", 18, "bold"), bg="#f0faff", fg="#004466")
|
||||||
title_label = tk.Label(root, text="🎯 10 秒挑战 🎯", font=("微软雅黑", 18, "bold"), fg="#004466", bg="#f0faff")
|
title_label.pack(pady=10)
|
||||||
title_label.pack(pady=15)
|
|
||||||
|
|
||||||
# 排行榜框
|
|
||||||
rank_frame = tk.Frame(root, bg="#ffffff", bd=2, relief="groove")
|
rank_frame = tk.Frame(root, bg="#ffffff", bd=2, relief="groove")
|
||||||
rank_frame.pack(pady=10)
|
rank_frame.pack(pady=5)
|
||||||
|
|
||||||
rank_title = tk.Label(rank_frame, text="🏆 排行榜(误差越小越靠前)", font=("微软雅黑", 10, "bold"), bg="#ffffff", fg="#333333")
|
rank_title = tk.Label(rank_frame, text="🏆 排行榜", font=("微软雅黑", 10, "bold"), bg="#ffffff")
|
||||||
rank_title.pack(pady=(5, 0))
|
rank_title.pack(pady=5)
|
||||||
|
|
||||||
rank_listbox = tk.Listbox(rank_frame, font=("Courier", 10), height=5, width=35, bg="#f9f9f9")
|
rank_listbox = tk.Listbox(rank_frame, font=("Courier", 10), height=5, width=35, bg="#f9f9f9")
|
||||||
rank_listbox.pack(padx=10, pady=5)
|
rank_listbox.pack(padx=10, pady=5)
|
||||||
|
|
||||||
# 初始显示排行榜
|
timex_label = tk.Label(root, text="点击按钮开始挑战", font=("微软雅黑", 12), bg="#f0faff")
|
||||||
leaderboard = load_leaderboard()
|
|
||||||
update_rank_display(leaderboard)
|
|
||||||
|
|
||||||
# 时间标签
|
|
||||||
timex_label = tk.Label(root, text="点击按钮开始挑战", font=("微软雅黑", 12), bg="#f0faff", fg="#333333")
|
|
||||||
timex_label.pack(pady=20)
|
timex_label.pack(pady=20)
|
||||||
|
|
||||||
# 按钮
|
|
||||||
start_button = tk.Button(root, text="🎮 开始 / 停止", font=("微软雅黑", 12, "bold"),
|
start_button = tk.Button(root, text="🎮 开始 / 停止", font=("微软雅黑", 12, "bold"),
|
||||||
bg="#66ccff", fg="white", activebackground="#3399cc",
|
bg="#66ccff", fg="white", activebackground="#3399cc",
|
||||||
width=20, height=2, command=change, relief="raised", bd=3)
|
width=20, height=2, command=change)
|
||||||
start_button.pack(pady=30)
|
start_button.pack(pady=10)
|
||||||
|
|
||||||
|
# 滚动留言框
|
||||||
|
message_var = tk.StringVar()
|
||||||
|
message_label = tk.Label(root, textvariable=message_var, font=("微软雅黑", 10), fg="#444", bg="#f0faff", wraplength=320, justify="center")
|
||||||
|
message_label.pack(pady=20)
|
||||||
|
|
||||||
|
# 初始数据加载
|
||||||
|
messages = []
|
||||||
|
leaderboard = load_leaderboard()
|
||||||
|
update_rank_display(leaderboard)
|
||||||
|
update_message_display(leaderboard)
|
||||||
|
scroll_messages()
|
||||||
|
|
||||||
# 控制变量
|
|
||||||
flag = False
|
flag = False
|
||||||
start_time = 0
|
start_time = 0
|
||||||
|
|
||||||
# 启动主循环
|
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
|
|||||||
39
yun/client.spec
Normal file
39
yun/client.spec
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['client.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=[],
|
||||||
|
datas=[],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='client',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=False,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon=['icon.ico'],
|
||||||
|
)
|
||||||
@ -3,35 +3,32 @@ import json
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
LEADERBOARD_FILE = "../leaderboard.json"
|
LEADERBOARD_FILE = "leaderboard.json"
|
||||||
|
|
||||||
# 加载排行榜数据
|
# 加载排行榜
|
||||||
def load_leaderboard():
|
def load_leaderboard():
|
||||||
if os.path.exists(LEADERBOARD_FILE):
|
if os.path.exists(LEADERBOARD_FILE):
|
||||||
with open(LEADERBOARD_FILE, "r", encoding="utf-8") as f:
|
with open(LEADERBOARD_FILE, "r", encoding="utf-8") as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# 保存排行榜数据
|
# 保存排行榜
|
||||||
def save_leaderboard(data):
|
def save_leaderboard(data):
|
||||||
with open(LEADERBOARD_FILE, "w", encoding="utf-8") as f:
|
with open(LEADERBOARD_FILE, "w", encoding="utf-8") as f:
|
||||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
# 获取排行榜
|
|
||||||
@app.route("/get_board", methods=["GET"])
|
@app.route("/get_board", methods=["GET"])
|
||||||
def get_board():
|
def get_board():
|
||||||
return jsonify(load_leaderboard())
|
return jsonify(load_leaderboard())
|
||||||
|
|
||||||
# 上传排行榜
|
|
||||||
@app.route("/set_board", methods=["POST"])
|
@app.route("/set_board", methods=["POST"])
|
||||||
def set_board():
|
def set_board():
|
||||||
try:
|
try:
|
||||||
data = request.json
|
data = request.json
|
||||||
save_leaderboard(data)
|
save_leaderboard(data)
|
||||||
return jsonify(data) # 直接返回排行榜
|
return jsonify(data)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({"status": "error", "message": str(e)}), 400
|
return jsonify({"status": "error", "message": str(e)}), 400
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
app.run(debug=True, port=5000)
|
app.run(host="0.0.0.0", port=5000)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user