import tkinter as tkfrom tkinter import messageboxfrom datetime import datetime, timedelta import os import tkinter.font as tkFont from zhdate import ZhDateimport randomDEFAULT_OFF_WORK_TIME = "17:00:00"off_work_time_str = DEFAULT_OFF_WORK_TIMEBG_COLOR = "#000000"FG_COLOR = "#cccccc"TITLE_COLOR = "#ffffff"ACCENT_RED = "#ff6b6b"ACCENT_CYAN = "#ff6b6b"ACCENT_YELLOW = "#ff6b6b"BUTTON_COLOR = "#333333"BUTTON_TEXT = "white"POPUP_BG = "#1a1a1a"MASK_COLOR = "#0a0a0a"CAT_IMAGE_PATH = r"E:\Bil大业\ELSE\下班\Cat.png" def get_next_holiday_info(): now = datetime.now() current_year = now.year spring_festival = ZhDate(current_year, 1, 1).to_datetime() dragon_boat = ZhDate(current_year, 5, 5).to_datetime() mid_autumn = ZhDate(current_year, 8, 15).to_datetime() qingming = datetime(current_year, 4, 4) holidays = [ (datetime(current_year, 1, 1), "元旦"), (spring_festival, "春节"), (qingming, "清明节"), (datetime(current_year, 5, 1), "劳动节"), (dragon_boat, "端午节"), (datetime(current_year, 10, 1), "国庆节"), (mid_autumn, "中秋节"), ] min_diff = None next_holiday_name = "" for year_offset in [0, 1]: year = current_year + year_offset for holiday_date, name in holidays: if name == "元旦": date_obj = datetime(year, 1, 1) elif name == "春节": date_obj = ZhDate(year, 1, 1).to_datetime() elif name == "清明节": date_obj = datetime(year, 4, 4) elif name == "劳动节": date_obj = datetime(year, 5, 1) elif name == "端午节": date_obj = ZhDate(year, 5, 5).to_datetime() elif name == "国庆节": date_obj = datetime(year, 10, 1) elif name == "中秋节": date_obj = ZhDate(year, 8, 15).to_datetime() else: continue if date_obj > now: diff = date_obj - now days = diff.days if min_diff is None or days < min_diff: min_diff = days next_holiday_name = name if min_diff is not None: return min_diff, next_holiday_name return 0, "暂无数据"def calculate_time_diff(target_time_str): now = datetime.now() try: h, m, s = map(int, target_time_str.split(':')) target_time_today = now.replace(hour=h, minute=m, second=s, microsecond=0) except ValueError: return "时间格式错误", ACCENT_RED if now >= target_time_today: return "已经下班啦!", ACCENT_RED delta = target_time_today - now total_seconds = int(delta.total_seconds()) hours, remainder = divmod(total_seconds, 3600) minutes, seconds = divmod(remainder, 60) return f"{hours:02d}时{minutes:02d}分{seconds:02d}秒", ACCENT_RED def get_weekend_diff(target_time_str): now = datetime.now() weekday = now.weekday() if weekday >= 5: return "现在就是周末哦~", ACCENT_CYAN try: h, m, s = map(int, target_time_str.split(':')) except ValueError: return "时间格式错误", ACCENT_CYAN if weekday == 4: target = now.replace(hour=h, minute=m, second=s, microsecond=0) delta = target - now total_seconds = int(delta.total_seconds()) if total_seconds < 0: return "周末已开始~", ACCENT_CYAN hours, remainder = divmod(total_seconds, 3600) minutes, seconds = divmod(remainder, 60) return f"{hours}小时{minutes}分{seconds}秒", ACCENT_CYAN else: days_to_friday = 4 - weekday target = now + timedelta(days=days_to_friday) target = target.replace(hour=h, minute=m, second=s, microsecond=0) delta = target - now return f"{delta.days}天", ACCENT_CYAN class RoundedButton(tk.Canvas): def __init__(self, parent, text, command=None, radius=3, bg=BUTTON_COLOR, fg="white", font=("arial", 11)): tmp_font = tk.font.Font(family="arial", size=11) text_w = tmp_font.measure(text) w = text_w + 50 h = 40 super().__init__(parent, width=w, height=h, bg=parent["bg"], highlightthickness=0, cursor="hand2") self.command = command self.radius = radius self.bg = bg self.fg = fg self.text = text self.font = font self._hover = False self._draw() self.bind("<Button-1>", lambda e: self.command() if self.command else None) self.bind("<Enter>", lambda e: self._set_hover(True)) self.bind("<Leave>", lambda e: self._set_hover(False)) def _draw(self): self.delete("all") w = self.winfo_reqwidth() h = self.winfo_reqheight() r = self.radius color = "#454545" if self._hover else self.bg self.create_oval(0, 0, 2*r, 2*r, fill=color, outline=color) self.create_oval(w-2*r, 0, w, 2*r, fill=color, outline=color) self.create_oval(0, h-2*r, 2*r, h, fill=color, outline=color) self.create_oval(w-2*r, h-2*r, w, h, fill=color, outline=color) self.create_rectangle(r, 0, w-r, h, fill=color, outline=color) self.create_rectangle(0, r, w, h-r, fill=color, outline=color) self.create_text(w/2, h/2, text=self.text, fill=self.fg, font=self.font) def _set_hover(self, hover): self._hover = hover self._draw()def create_rounded_image(image_path, size, radius=10): try: from PIL import Image, ImageDraw, ImageTk img = Image.open(image_path).convert("RGBA") img = img.resize(size, Image.LANCZOS) mask = Image.new('L', size, 0) draw = ImageDraw.Draw(mask) draw.rounded_rectangle([(0, 0), size], radius=radius, fill=255) result = Image.new('RGBA', size, (0, 0, 0, 0)) result.paste(img, (0, 0), mask) return ImageTk.PhotoImage(result) except ImportError: return None except Exception as e: print(f"图片处理错误: {e}") return Noneclass MiniGameApp: def __init__(self, parent): self.top = tk.Toplevel(parent) self.top.title("摸鱼小游戏") self.top.geometry("1200x500") self.top.configure(bg="black") self.top.resizable(False, False) self.canvas = tk.Canvas(self.top, width=1200, height=500, bg="black", highlightthickness=0) self.canvas.pack() self.top.bind("<KeyPress>", self.on_key_press) self.top.bind("<KeyRelease>", self.on_key_release) self.top.bind("<r>", self.restart_game) self.top.bind("<t>", self.close_game) self.top.bind("<R>", self.restart_game) self.top.bind("<T>", self.close_game) self.GRAVITY = 0.8 self.MAX_CHARGE = 22 self.CHARGE_RATE = 0.4 self.player = {'x': 0, 'y': 0, 'w': 20, 'h': 20, 'vx': 0, 'vy': 0} self.platforms = [] self.is_charging = False self.charge_power = 0 self.game_over = False self.game_won = False self.game_state = 'playing' self.text_fade = 0.0 self.reset_game() self.game_loop() def generate_platforms(self): self.platforms = [] current_x = 0 self.platforms.append({'x': 0, 'y': 350, 'w': 120, 'h': 50}) current_x = 120 while current_x < 1200: gap = random.randint(80, 160) width = random.randint(60, 100) next_y = random.randint(280, 360) self.platforms.append({ 'x': current_x + gap, 'y': next_y, 'w': width, 'h': 500 - next_y }) current_x += gap + width def reset_game(self): self.generate_platforms() start_plat = self.platforms[0] self.player['x'] = start_plat['x'] + 10 self.player['y'] = start_plat['y'] - self.player['h'] self.player['vx'] = 0 self.player['vy'] = 0 self.game_over = False self.game_won = False self.is_charging = False self.charge_power = 0 self.game_state = 'playing' self.text_fade = 0.0 self.draw() def on_key_press(self, event): if event.keysym == 'space' and not self.game_over and not self.game_won: self.is_charging = True def on_key_release(self, event): if event.keysym == 'space' and self.is_charging: self.jump() self.is_charging = False self.charge_power = 0 def jump(self): self.player['vx'] = 5 + (self.charge_power * 0.6) self.player['vy'] = -(7 + (self.charge_power * 0.6)) def _get_faded_color(self, target_color_hex, progress): if not target_color_hex.startswith('#'): color_map = { "red": (255, 0, 0), "gray": (128, 128, 128) } if target_color_hex in color_map: rgb = color_map[target_color_hex] else: rgb = (255, 255, 255) else: h = target_color_hex.lstrip('#') rgb = tuple(int(h[i:i+2], 16) for i in (0, 2, 4)) r = int(rgb[0] * progress) g = int(rgb[1] * progress) b = int(rgb[2] * progress) return f'#{r:02x}{g:02x}{b:02x}' def update(self): if self.game_over or self.game_won: pass else: if self.is_charging: if self.charge_power < self.MAX_CHARGE: self.charge_power += self.CHARGE_RATE self.player['vy'] += self.GRAVITY self.player['x'] += self.player['vx'] self.player['y'] += self.player['vy'] player_bottom = self.player['y'] + self.player['h'] player_left = self.player['x'] player_right = self.player['x'] + self.player['w'] for p in self.platforms: plat_top = p['y'] plat_left = p['x'] plat_right = p['x'] + p['w'] if player_right > plat_left and player_left < plat_right: if player_bottom > plat_top: prev_bottom = player_bottom - self.player['vy'] if self.player['vy'] > 0 and prev_bottom <= plat_top: self.player['y'] = plat_top - self.player['h'] self.player['vy'] = 0 self.player['vx'] = 0 break else: self.game_over = True break if self.player['x'] > 1200: self.game_won = True if self.player['y'] > 500: self.game_over = True current_state = 'won' if self.game_won else ('over' if self.game_over else 'playing') if current_state != self.game_state: self.game_state = current_state self.text_fade = 0.0 if self.text_fade < 1.0: self.text_fade += 0.03 if self.text_fade > 1.0: self.text_fade = 1.0 self.draw() def draw(self): self.canvas.delete("all") for p in self.platforms: self.canvas.create_rectangle( p['x'], p['y'], p['x'] + p['w'], p['y'] + p['h'], fill="#222222", outline="" ) p = self.player self.canvas.create_rectangle( p['x'], p['y'], p['x'] + p['w'], p['y'] + p['h'], fill="white", outline="" ) if self.is_charging: ratio = self.charge_power / self.MAX_CHARGE bar_width = ratio * 40 if ratio <= 0.5: local_ratio = ratio * 2 r = 255 g = int(255 * (1 - local_ratio)) b = 0 else: local_ratio = (ratio - 0.5) * 2 r = int(255 - (255 - 139) * local_ratio) g = 0 b = 0 color_hex = f'#{r:02x}{g:02x}{b:02x}' self.canvas.create_rectangle( p['x'], p['y'] - 10, p['x'] + bar_width, p['y'] - 5, fill=color_hex, outline="" ) if self.game_over: text_color = self._get_faded_color("red", self.text_fade) self.canvas.create_text(580, 200, text="万物皆生,唯你独枯。茫茫天地间,竟全然无你托身之所……", fill=text_color, font=("STKaiti", 30)) text_color = self._get_faded_color("grey", self.text_fade) self.canvas.create_text(90, 30, text="R: retry, T: exit", fill=text_color, font=("times", 12)) elif self.game_won: text_color = self._get_faded_color("#00ff00", self.text_fade) self.canvas.create_text(450, 200, text="穿尽千山与万水,始知天地本来宽.", fill=text_color, font=("STKaiti", 30)) text_color = self._get_faded_color("grey", self.text_fade) self.canvas.create_text(90, 30, text="R: retry, T: exit", fill=text_color, font=("times", 12)) else: text_color = self._get_faded_color("white", self.text_fade) self.canvas.create_text(450, 70, text="正入万山圈子里,一山放过一山拦——", fill=text_color, font=("STKaiti", 20)) def game_loop(self): self.update() self.top.after(20, self.game_loop) def restart_game(self, event=None): self.reset_game() def close_game(self, event=None): self.top.destroy()class OffWorkCountdownApp: def __init__(self, root): self.root = root self.root.title("下班倒计时界面") self.root.geometry("590x390") self.root.configure(bg=BG_COLOR) self.title_font = ("arial", 18, "bold") self.label_font = ("arial", 12) self.time_font = ("arial", 22, "bold") self.btn_font = ("arials", 11) self.create_widgets() self.update_time() def create_widgets(self): main = tk.Frame(self.root, bg=BG_COLOR) main.pack(fill="both", expand=True, padx=15, pady=10) left = tk.Frame(main, bg=BG_COLOR) left.pack(side="left", fill="both", expand=True, padx=(0, 20)) tk.Label(left, text=" ~下班倒计时~ ", font=self.title_font, bg=BG_COLOR, fg=TITLE_COLOR).pack(pady=(0, 20), anchor="w") f1 = tk.Frame(left, bg=BG_COLOR) f1.pack(pady=8, fill="x") tk.Label(f1, text="离下班还有:", font=self.label_font, bg=BG_COLOR, fg=FG_COLOR).pack(anchor="w") self.lbl_off_work = tk.Label(f1, text="计算中...", font=self.time_font, bg=BG_COLOR, fg=ACCENT_RED) self.lbl_off_work.pack(anchor="w", pady=(5, 0)) f2 = tk.Frame(left, bg=BG_COLOR) f2.pack(pady=8, fill="x") tk.Label(f2, text="离周末还有:", font=self.label_font, bg=BG_COLOR, fg=FG_COLOR).pack(anchor="w") self.lbl_friday = tk.Label(f2, text="计算中...", font=self.time_font, bg=BG_COLOR, fg=ACCENT_CYAN) self.lbl_friday.pack(anchor="w", pady=(5, 0)) f3 = tk.Frame(left, bg=BG_COLOR) f3.pack(pady=8, fill="x") tk.Label(f3, text="离节假日还有:", font=self.label_font, bg=BG_COLOR, fg=FG_COLOR).pack(anchor="w") self.lbl_holiday = tk.Label(f3, text="计算中...", font=("arial", 16), bg=BG_COLOR, fg=ACCENT_YELLOW) self.lbl_holiday.pack(anchor="w", pady=(5, 0)) RoundedButton(left, text="⚙️设置下班时间", command=self.open_settings).pack(pady=(30, 0), anchor="w") right = tk.Frame(main, bg=BG_COLOR, width=390, height=390) right.pack(side="right", fill="y") right.pack_propagate(False) mask = tk.Frame(right, bg=MASK_COLOR, width=360, height=370) mask.place(relx=0.5, rely=0.5, anchor="center") self.cat_img = None if os.path.exists(CAT_IMAGE_PATH): try: self.cat_img = create_rounded_image(CAT_IMAGE_PATH, size=(320, 320), radius=10) if self.cat_img: img_label = tk.Label(right, image=self.cat_img, bg=MASK_COLOR, bd=0, cursor="hand2") img_label.place(relx=0.5, rely=0.5, anchor="center") img_label.bind("<Button-1>", lambda e: self.open_game()) else: from PIL import Image, ImageTk img = Image.open(CAT_IMAGE_PATH) img = img.resize((320, 320), Image.LANCZOS) self.cat_img = ImageTk.PhotoImage(img) img_label = tk.Label(right, image=self.cat_img, bg=MASK_COLOR, bd=0, cursor="hand2") img_label.place(relx=0.5, rely=0.5, anchor="center") img_label.bind("<Button-1>", lambda e: self.open_game()) except ImportError: tk.Label(right, text="(需安装Pillow才能显示图片哦)\npip install pillow", bg=MASK_COLOR, fg=FG_COLOR, font=("arial", 11), justify="center").place(relx=0.5, rely=0.5, anchor="center") else: tk.Label(right, text=f"这里本该有只哈基米。", bg=MASK_COLOR, fg=FG_COLOR, font=("arial", 10), justify="center").place(relx=0.5, rely=0.5, anchor="center") def update_time(self): global off_work_time_str text, color = calculate_time_diff(off_work_time_str) self.lbl_off_work.config(text=text, fg=color) text, color = get_weekend_diff(off_work_time_str) self.lbl_friday.config(text=text, fg=color) days, name = get_next_holiday_info() self.lbl_holiday.config(text=f"{days}天 ({name})") self.root.after(1000, self.update_time) def open_settings(self): top = tk.Toplevel(self.root) top.title("设置") top.geometry("320x160") top.configure(bg=POPUP_BG) tk.Label(top, text="请输入下班时间 (HH:MM:SS):", bg=POPUP_BG, fg=FG_COLOR, font=("arial", 10)).pack(pady=15) entry = tk.Entry(top, font=("arial", 12), justify="center", bg="#3c3f41", fg="white", insertbackground="white") entry.insert(0, off_work_time_str) entry.pack(pady=5) entry.focus_set() def save(): global off_work_time_str new_time = entry.get() try: h, m, s = map(int, new_time.split(':')) if 0 <= h < 24 and 0 <= m < 60 and 0 <= s < 60: off_work_time_str = new_time messagebox.showinfo("成功", "下班时间已更新!") top.destroy() else: messagebox.showerror("错误", "时间数值不合法!") except Exception: messagebox.showerror("错误", "格式错误,请使用 HH:MM:SS") tk.Button(top, text="确定", command=save, bg=BUTTON_COLOR, fg=BUTTON_TEXT, font=("arial", 10), relief="flat").pack(pady=15) def open_game(self): MiniGameApp(self.root)if __name__ == "__main__": root = tk.Tk() app = OffWorkCountdownApp(root) root.mainloop()