Time to_s(:db) 的背后

本文介绍了Rails中时间格式化的实现方式,通过简单的代码示例展示了如何利用Rails提供的API来定制时间显示格式,包括内置的几种格式及如何扩展自定义格式。
rails提供了很友好的管理时间的API,其中包括 创建,计算,格式化。
其中,对时间格式化支持的主要代码下面这个文件中
active_support/core_ext/time/conversions.rb
[code]
def self.included(klass) #:nodoc:
klass.send(:alias_method, :to_default_s, :to_s)
klass.send(:alias_method, :to_s, :to_formatted_s)
end

def to_formatted_s(format = :default)
DATE_FORMATS[format] ? strftime(DATE_FORMATS[format]).strip : to_default_s
end
[/code]
用included对被加载代码,进行hack,在rails中到处都是,最经典的是rails acts_as模块,
这个会在以后的blog中重点讲到。
在这里,conversions.rb将to_s的调用转移到方法to_formatted_s。
下面就很清楚了,直接从常量DATE_FORMATS中拿出format,然后交给strftime。

看看,短短两行代码,就可以将时间格式化的api转换成:
Time.now.to_s(:db) #"2007-11-19 12:10:14"

rails内置了4个
[code] DATE_FORMATS = {
:db => "%Y-%m-%d %H:%M:%S",
:short => "%d %b %H:%M",
:long => "%B %d, %Y %H:%M",
:rfc822 => "%a, %d %b %Y %H:%M:%S %z"
}[/code]
当然,如果你要扩展,也很容易
Time::DATE_FORMATS[:stamp] = '%Y%m%d%M%S'
这个代码在rails加载完毕后加入,或者直接放到lib中的某个文件中。
使用的时候
>> Time.now.to_s(:stamp)
=> "200711191316"
>>
基于以下代码修改,怎么改变悬浮窗口的背景颜色,现在的背景颜色为什么是LOGIN_BG的颜色,请将背景颜色修改为有点透明的浅灰色。仅给出需修改部分的代码即可。 import tkinter as tk from tkinter import simpledialog, messagebox, scrolledtext, ttk import time import threading import json import os import platform from cryptography.fernet import Fernet from pynput import mouse, keyboard import sys import subprocess import csv import pandas as pd # 获取当前脚本所在目录作为基础路径 if getattr(sys, 'frozen', False): # 打包后的可执行文件路径 BASE_DIR = os.path.dirname(sys.executable) else: # 脚本文件路径 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 配置参数(常量使用大写) IDLE_THRESHOLD = 5 # 3分钟空闲时间(秒) COUNTDOWN_DURATION = 10 # 锁屏倒计时(秒) KEY_FILE = os.path.join(BASE_DIR, "system_secret.key") # 加密密钥文件名改为绝对路径 LOG_FILE = os.path.join(BASE_DIR, "secure_usage_log.log") # 操作日志文件路径改为绝对路径 ADMIN_PASSWORD = "123" # 管理员密码 LOCK_SCREEN_BG = "#000000" # 锁屏背景色(黑色) LOGIN_BG = "#2c3e50" # 登录界面背景色(深蓝色) BUTTON_BG = "#3498db" # 按钮背景色(亮蓝色) USER_FILE = os.path.join(BASE_DIR, "培训通过人员名单.csv") # 改为绝对路径 USER_MANAGEMENT_PASSWORD = ADMIN_PASSWORD # 用户管理密码设置为管理员密码 # 确保BASE_DIR存在 os.makedirs(BASE_DIR, exist_ok=True) # 培训通过人员名单(工号:密码) # 修改全局用户加载逻辑 def load_trained_users(file_path): """ 从CSV文件加载培训通过人员名单 文件格式要求:工号,密码 返回字典 {工号: 密码} """ users = {} try: # 检查文件是否存在 if not os.path.exists(file_path): print(f"用户文件 {file_path} 不存在,创建初始管理员账号") # 创建只包含管理员的初始用户名单 users = {"ADMIN": ADMIN_PASSWORD} # 保存加密的用户名单 save_user_file(users, file_path) return users # 加载加密密钥 if not os.path.exists(KEY_FILE): key = Fernet.generate_key() with open(KEY_FILE, "wb") as f: f.write(key) with open(KEY_FILE, "rb") as f: key = f.read() cipher = Fernet(key) # 解密用户数据 with open(file_path, "rb") as f: encrypted_data = f.read() decrypted_data = cipher.decrypt(encrypted_data) return json.loads(decrypted_data) except Exception as e: print(f"加载用户名单错误: {str(e)}") # 返回只包含管理员的用户名单 return {"ADMIN": ADMIN_PASSWORD} # 添加保存用户文件的函数 def save_user_file(users, file_path): """保存用户字典到CSV文件""" try: # 确保密钥存在 if not os.path.exists(KEY_FILE): key = Fernet.generate_key() with open(KEY_FILE, "wb") as f: f.write(key) with open(KEY_FILE, "rb") as f: key = f.read() cipher = Fernet(key) # 加密用户数据 encrypted_data = cipher.encrypt(json.dumps(users).encode()) # 新加 os.makedirs(os.path.dirname(file_path) or '.', exist_ok=True) with open(file_path, "wb") as f: f.write(encrypted_data) return True except Exception as e: print(f"保存用户文件时出错: {str(e)}") return False # 从文件加载培训通过人员名单 TRAINED_USERS = load_trained_users(USER_FILE) # 确保管理员账户存在 if "ADMIN" not in TRAINED_USERS: TRAINED_USERS["ADMIN"] = ADMIN_PASSWORD save_user_file(TRAINED_USERS, USER_FILE) class SecureDesktopMonitor: def __init__(self): # 创建主窗口 self.root = tk.Tk() # 创建主窗口对象 self.root.title("安全桌面监控系统") # 设置窗口标题 self.root.geometry("800x600") # 初始窗口尺寸 self.root.configure(bg=LOGIN_BG) # 设置背景色 # 设置窗口在最顶层 self.root.attributes("-topmost", True) # 系统状态变量,防止用户绕过监控 self.current_user = None # 当前登录用户(未登录时为None) self.login_time = 0 # 登陆时间(初始为0) self.last_activity = time.time() # 最后活动时间(初始化为当前时间) self.idle_timer = None # 空闲检测定时器(用于推迟锁屏) self.countdown_timer = None # 倒计时定时器(锁屏前提示) self.listening = False # 监听器状态标志 self.is_locked = False # 界面锁屏状态(初始为True,即未登录时锁定) # 创建鼠标键盘监听器 self.mouse_listener = mouse.Listener(on_move=self.activity_detected) # 鼠标移动触发活动检测 self.keyboard_listener = keyboard.Listener(on_press=self.activity_detected) # 键盘按键触发活动检测 # 显示初始登录界面 self.show_login_screen() # Tkinter事件循环(阻塞式,保持程序运行),mainloop()是Tkinter的核心,用于处理用户事件(如点击、输入) self.root.mainloop() def show_login_screen(self): """显示登录界面""" self.clear_screen() # 清空当前屏幕所有内容 self.is_locked = True # 标记系统为锁定状态 # 设置全屏模式(防止用户切换窗口) self.root.attributes('-fullscreen', True) # 创建居中主框架 main_frame = tk.Frame(self.root, bg=LOGIN_BG) # bg颜色深蓝色 main_frame.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # 使用place布局精确居中 # 系统标题标签 title = tk.Label( main_frame, text="安全桌面登录", font=("Arial", 24, "bold"), # 字体族、大小、粗体 fg="white", # 前景色(白色) bg=LOGIN_BG # 背景色与界面一致 ) title.pack(pady=20) # 打包布局,垂直间距20像素 # 登录表单框架(使用grid布局对齐输入框) form_frame = tk.Frame(main_frame, bg=LOGIN_BG) form_frame.pack(pady=20) # 工号输入标签和输入框 tk.Label( form_frame, # 框架格式 text="工号:", font=("黑体", 14), fg="white", bg=LOGIN_BG ).grid(row=0, column=0, padx=10, pady=10, sticky="e") self.id_entry = tk.Entry(form_frame, font=("Arial", 14), width=20) # 单行文本输入框 self.id_entry.grid(row=0, column=1, padx=10, pady=10) self.id_entry.focus_set() # 自动聚焦到工号输入框(提升用户体验) # 密码输入标签和输入框(内容显示为*号) tk.Label( form_frame, text="密码:", font=("黑体", 14), fg="white", bg=LOGIN_BG ).grid(row=1, column=0, padx=10, pady=10, sticky="e") self.pw_entry = tk.Entry(form_frame, show="*", font=("Arial", 14), width=20) # show="*" 隐藏输入 self.pw_entry.grid(row=1, column=1, padx=10, pady=10) # 放置位置 # 绑定回车键(用户输入密码后按回车可直接登录) self.pw_entry.bind("<Return>", lambda event: self.authenticate_user()) # 登录按钮 login_btn = tk.Button( form_frame, text="登 录", command=self.authenticate_user, # 点击时触发认证方法 font=("黑体", 18, "bold"), bg=BUTTON_BG, # 按钮背景色 fg="white", # 按钮文字颜色 width=15, height=2 ) login_btn.grid(row=2, column=0, columnspan=2, pady=20) # 放置位置跨两列居中 # 系统信息 sys_info = tk.Label( main_frame, text="用户使用时长监测系统 | 仅限授权人员使用", font=("黑体", 10), fg="#bdc3c7", bg=LOGIN_BG ) sys_info.pack(side=tk.BOTTOM, pady=10) def authenticate_user(self): """验证用户身份(首次登录设置密码)""" user_id = self.id_entry.get().strip() # 获取用户id和密码 password = self.pw_entry.get().strip() # 检查是否是管理员登录且用户名单只有管理员 is_only_admin = len(TRAINED_USERS) == 1 and "ADMIN" in TRAINED_USERS # 检查用户是否存在 if user_id in TRAINED_USERS: # 如果是管理员且用户名单为空,直接进入用户管理界面 if is_only_admin and user_id == "ADMIN": self.current_user = user_id self.login_time = time.time() self.last_activity = self.login_time self.is_locked = False self.manage_users() # 直接进入用户管理 return # 处理首次登录(密码为空) if TRAINED_USERS[user_id] == "": self.set_initial_password(user_id) return # 如果id和密码匹配,则正常启动桌面会话 if TRAINED_USERS[user_id] == password: self.current_user = user_id self.login_time = time.time() self.last_activity = self.login_time self.is_locked = False self.start_desktop_session() # 开始桌面会话函数 return else: messagebox.showerror("访问拒绝", "输入密码有误,请重新输入!") self.pw_entry.delete(0, tk.END) return # 如果用户名单只有管理员,给出特定提示 if is_only_admin: messagebox.showerror("访问拒绝", "当前只有管理员可以登录系统,请使用管理员账号登录") else: messagebox.showerror("访问拒绝", "未授权操作!禁止访问系统!") # 清空密码框 self.pw_entry.delete(0, tk.END) # 新用户首次登陆设置密码 def set_initial_password(self, user_id): """新用户首次登录设置密码""" dialog = tk.Toplevel(self.root) dialog.title("设置初始密码") dialog.geometry("300x200") dialog.transient(self.root) dialog.grab_set() # 窗口居中设置 screen_width = dialog.winfo_screenwidth() screen_height = dialog.winfo_screenheight() x = (screen_width - 300) // 2 y = (screen_height - 200) // 2 dialog.geometry(f"300x200+{x}+{y}") tk.Label(dialog, text=f"欢迎新用户 {user_id}").pack(pady=(10, 0)) tk.Label(dialog, text="请设置您的初始密码:").pack(pady=(10, 0)) password_entry = tk.Entry(dialog, show="*", width=20) password_entry.pack() tk.Label(dialog, text="确认密码:").pack(pady=(10, 0)) confirm_entry = tk.Entry(dialog, show="*", width=20) confirm_entry.pack() def save_password(): password = password_entry.get().strip() confirm = confirm_entry.get().strip() if not password: messagebox.showerror("错误", "密码不能为空", parent=dialog) return if password != confirm: messagebox.showerror("错误", "两次输入的密码不一致", parent=dialog) return # 更新密码 TRAINED_USERS[user_id] = password save_user_file(TRAINED_USERS, USER_FILE) # 完成设置 dialog.destroy() messagebox.showinfo("成功", "密码设置成功!") # 自动登录 self.current_user = user_id self.login_time = time.time() self.last_activity = self.login_time self.is_locked = False self.start_desktop_session() tk.Button(dialog, text="保存", command=save_password).pack(pady=10) def start_desktop_session(self): """开始桌面会话""" self.clear_screen() self.root.attributes('-fullscreen', False) # 设置悬浮窗口属性 self.root.overrideredirect(True) # 移除窗口边框和标题栏 self.root.attributes("-topmost", False) # 取消置顶显示 self.root.geometry("300x300") self.root.title(f"使用中 - 用户: {self.current_user}") # 移除窗口关闭功能 self.root.protocol("WM_DELETE_WINDOW", lambda: None) # 停止可能存在的旧监听器 self.stop_activity_monitoring() # 启动新的监听 self.start_activity_monitoring() # 显示桌面内容 desktop_frame = tk.Frame(self.root) desktop_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=40) # expand可将组件由其势力范围扩大到扩展范围 # 欢迎信息(简化显示) welcome_msg = tk.Label( desktop_frame, text=f"用户: {self.current_user}", font=("Arial", 14, "bold"), pady=10 ) welcome_msg.pack() # 使用时间显示 self.time_label = tk.Label( desktop_frame, text="使用时间: 00:00", font=("黑体", 10) ) self.time_label.pack(pady=5) # 手动锁定按钮 lock_btn = tk.Button( desktop_frame, text="锁定系统", command=self.lock_system, font=("黑体", 10), bg="#e74c3c", fg="white" ) lock_btn.pack(pady=10) # ⭐管理员按钮组框架 admin_frame = tk.Frame(desktop_frame) admin_frame.pack(pady=5) # 管理员查看记录按钮(仅管理员可见) if self.current_user == "ADMIN": admin_btn = tk.Button( admin_frame, text="查看使用记录", command=self.admin_view, font=("黑体", 10), bg="#F5FFFA", fg="#e74c3c" ) admin_btn.pack(side=tk.LEFT, padx=5) # 新增:管理用户名单按钮(仅管理员可见) manage_users_btn = tk.Button( admin_frame, text="管理用户名单", command=self.manage_users, font=("黑体", 10), bg="#F5FFFA", fg="#e74c3c" ) manage_users_btn.pack(side=tk.LEFT, padx=5) # 启动鼠标键盘事件监听 self.start_activity_monitoring() # 鼠标键盘监听函数 # 开始空闲检测 self.start_idle_monitor() # 开始更新使用时间显示 self.update_usage_time() # 管理员管理培训通过名单⭐ def manage_users(self): """管理员管理用户名单""" # 如果是首次登录(只有管理员),跳过密码验证 if len(TRAINED_USERS) > 1 or "ADMIN" not in TRAINED_USERS: # 验证管理员密码 password = simpledialog.askstring("❗", "请输入管理员密码:", show='*') if password != ADMIN_PASSWORD: messagebox.showerror("认证失败", "密码错误!") return # 如果是首次登录(只有管理员),显示特殊提示 is_only_admin = len(TRAINED_USERS) == 1 and "ADMIN" in TRAINED_USERS self.clear_screen() self.root.title("用户名单管理") self.root.geometry("800x600") # 标题 title = tk.Label( self.root, text="用户名单管理", font=("Arial", 24, "bold"), pady=20, bg=LOGIN_BG, fg="white" ) title.pack() # 如果是首次登录,显示提示信息 if is_only_admin: prompt = tk.Label( self.root, text="首次使用请添加至少一个普通用户账号", font=("黑体", 14), fg="red", pady=10 ) prompt.pack() # 框架容器 container = tk.Frame(self.root) container.pack(fill=tk.BOTH, expand=True, padx=20, pady=10) # both指定容器在X和Y两个方向上填充父容器分配的空间, expand容器会随着父容器的扩大而扩展, pady设置容器的外间距(边距) # 创建Treeview显示用户(只显示工号) columns = ("工号",) # 单元素元组需要加逗号 self.user_tree = ttk.Treeview(container, columns=columns, show="headings", selectmode="browse") # 设置列标题 for col in columns: self.user_tree.heading(col, text=col) self.user_tree.column(col, width=100, anchor=tk.CENTER) # 添加滚动条 scrollbar = ttk.Scrollbar(container, orient=tk.VERTICAL, command=self.user_tree.yview) self.user_tree.configure(yscroll=scrollbar.set) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.user_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 刷新用户列表 self.refresh_user_list() # 按钮框架 btn_frame = tk.Frame(self.root) btn_frame.pack(pady=20) # 添加用户按钮 add_btn = tk.Button( btn_frame, text="添加用户", command=self.add_user, font=("黑体", 12), bg="#2ecc71", fg="white" ) add_btn.pack(side=tk.LEFT, padx=10) # 删除用户按钮 delete_btn = tk.Button( btn_frame, text="删除用户", command=self.delete_user, font=("黑体", 12), bg="#e74c3c", fg="white" ) delete_btn.pack(side=tk.LEFT, padx=10) # 导出用户名单按钮 export_users_btn = tk.Button( btn_frame, text="导出文件", command=self.export_users_csv, font=("黑体", 12), bg=BUTTON_BG, fg="white" ) export_users_btn.pack(side=tk.LEFT, padx=10) # 返回按钮 back_btn = tk.Button( btn_frame, text="返回桌面", command=self.start_desktop_session, font=("黑体", 12), bg=BUTTON_BG, fg="white" ) back_btn.pack(side=tk.LEFT, padx=10) def refresh_user_list(self): """刷新用户列表显示(只显示工号)""" # 清除现有数据 for item in self.user_tree.get_children(): self.user_tree.delete(item) # 添加用户数据(只显示工号) for user_id in TRAINED_USERS.keys(): self.user_tree.insert("", tk.END, values=(user_id,)) def add_user(self): """添加新用户(只添加工号,密码为空)""" dialog = tk.Toplevel(self.root) dialog.title("添加新用户") dialog.geometry("200x150") dialog.transient(self.root) dialog.grab_set() # 窗口剧中设置 screen_width = dialog.winfo_screenwidth() screen_height = dialog.winfo_screenheight() x = (screen_width - 200) // 2 y = (screen_height - 150) // 2 dialog.geometry(f"200x150+{x}+{y}") # 只要求输入工号(不需要密码) tk.Label(dialog, text="工号:").pack(pady=(20, 0)) id_entry = tk.Entry(dialog, width=20) id_entry.pack() # tk.Label(dialog, text="密码:").pack(pady=(10, 0)) # password_entry = tk.Entry(dialog, show="*", width=20) # password_entry.pack() def save_new_user(): user_id = id_entry.get().strip() if not user_id: messagebox.showerror("错误", "工号不能为空", parent=dialog) return if user_id in TRAINED_USERS: messagebox.showerror("错误", "该工号已存在", parent=dialog) return # 添加到全局用户列表(密码初始化为空字符串) TRAINED_USERS[user_id] = "" # 设置初始密码为空 save_user_file(TRAINED_USERS, USER_FILE) # 刷新显示 self.refresh_user_list() dialog.destroy() messagebox.showinfo("成功", f"用户 {user_id} 添加成功") tk.Button(dialog, text="保存", command=save_new_user).pack(pady=20) def delete_user(self): """删除选中用户""" selected = self.user_tree.selection() if not selected: messagebox.showerror("错误", "请先选择一个用户") return item = selected[0] values = self.user_tree.item(item, "values") user_id = values[0] if user_id == "ADMIN": messagebox.showerror("错误", "不能删除管理员账户") return if messagebox.askyesno("确认", f"确定要删除用户 {user_id} 吗?"): # 从全局用户列表中删除 if user_id in TRAINED_USERS: del TRAINED_USERS[user_id] save_user_file(TRAINED_USERS, USER_FILE) self.refresh_user_list() messagebox.showinfo("成功", f"用户 {user_id} 已删除") def update_usage_time(self): """更新使用时间显示""" if not self.is_locked: # 如果没有锁 usage_seconds = time.time() - self.login_time minutes, seconds = divmod(int(usage_seconds), 60) self.time_label.config(text=f"使用时间: {minutes:02d}:{seconds:02d}") self.root.after(1000, self.update_usage_time) # 1s后更新时间显示 def start_activity_monitoring(self): """启动鼠标键盘事件监听""" # 如果已有监听器在运行,先停止 if self.listening: self.stop_activity_monitoring() # 创建新的监听器实例 self.mouse_listener = mouse.Listener(on_move=self.activity_detected) self.keyboard_listener = keyboard.Listener(on_press=self.activity_detected) # 启动线程 mouse_thread = threading.Thread(target=self.mouse_listener.start) keyboard_thread = threading.Thread(target=self.keyboard_listener.start) mouse_thread.daemon = True keyboard_thread.daemon = True mouse_thread.start() keyboard_thread.start() self.listening = True def stop_activity_monitoring(self): """停止鼠标键盘事件监听""" if self.listening: if self.mouse_listener: self.mouse_listener.stop() if self.keyboard_listener: self.keyboard_listener.stop() self.mouse_listener = None self.keyboard_listener = None self.listening = False def activity_detected(self, *args): """检测到用户活动""" if not self.is_locked: # 系统未被锁定 self.last_activity = time.time() # 更新最后活动时间 # ⭐ 修改点1:确保在倒计时期间检测到活动时重新启动监听 if self.countdown_timer: # 如果倒计时正在进行 self.root.after_cancel(self.countdown_timer) self.countdown_timer = None # 重新启动桌面会话和监听 self.stop_activity_monitoring() # 先停止当前监听 self.clear_screen() self.start_desktop_session() # 这会重新启动监听 def start_idle_monitor(self): """监控空闲状态""" if not self.is_locked: idle_time = time.time() - self.last_activity if idle_time > IDLE_THRESHOLD: # 空闲超时 self.start_lock_countdown() else: # 每秒检查一次 self.idle_timer = self.root.after(1000, self.start_idle_monitor) def start_lock_countdown(self): """开始锁屏倒计时""" # 关键修改:在倒计时开始前恢复全屏模式 self.root.overrideredirect(False) # 恢复窗口边框 self.root.attributes('-fullscreen', True) # 设置全屏 self.clear_screen() self.root.configure(bg=LOCK_SCREEN_BG) # self.root.attributes('-fullscreen', True) # 倒计时显示 self.countdown = COUNTDOWN_DURATION self.countdown_label = tk.Label( self.root, text=f"系统将在 {self.countdown} 秒后锁定...", font=("Arial", 36, "bold"), fg="red", bg=LOCK_SCREEN_BG ) self.countdown_label.place(relx=0.5, rely=0.4, anchor=tk.CENTER) # 提示信息 prompt = tk.Label( self.root, text="检测到系统空闲,移动鼠标或按键取消锁定", font=("Arial", 20), fg="#3498db", bg=LOCK_SCREEN_BG ) prompt.place(relx=0.5, rely=0.5, anchor=tk.CENTER) # 用户信息 user_info = tk.Label( self.root, text=f"当前用户: {self.current_user}", font=("Arial", 16), fg="white", bg=LOCK_SCREEN_BG ) user_info.place(relx=0.5, rely=0.6, anchor=tk.CENTER) # 开始倒计时 self.update_countdown() def update_countdown(self): """更新倒计时显示""" self.countdown -= 1 self.countdown_label.config(text=f"系统将在 {self.countdown} 秒后锁定...") if self.countdown <= 0: self.lock_system() else: # 每秒检查一次 self.countdown_timer = self.root.after(1000, self.update_countdown) def lock_system(self, manual=False): """锁定系统并保存使用记录""" logout_time = time.time() usage_seconds = logout_time - self.login_time # 格式化使用时间 minutes, seconds = divmod(int(usage_seconds), 60) usage_time = f"{minutes:02d}:{seconds:02d}" # 创建记录 record = { "user_id": self.current_user, "login_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.login_time)), "logout_time": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(logout_time)), "usage_duration": usage_time } # 加密保存记录 self.save_usage_record(record) # 停止监听和计时器 if self.idle_timer: self.root.after_cancel(self.idle_timer) if self.countdown_timer: self.root.after_cancel(self.countdown_timer) self.stop_activity_monitoring() # 重置用户状态 self.current_user = None self.is_locked = True # 关键修改:在锁定时恢复全屏模式 self.root.overrideredirect(False) # 恢复窗口边框 self.root.attributes('-fullscreen', True) # 设置全屏 # 显示登录界面 self.show_login_screen() def save_usage_record(self, record): """加密保存使用记录""" # 生成或加载加密密钥 if not os.path.exists(KEY_FILE): # 检查密钥文件是否存在 key = Fernet.generate_key() # 若不存在(首次运行),Fernet.generate_key()生成一个新的对称加密密钥(256位),并以二进制模式写入文件 with open(KEY_FILE, "wb") as f: f.write(key) with open(KEY_FILE, "rb") as f: # 如果已存在,直接读取密钥内容 key = f.read() cipher = Fernet(key) # 创建Fernet加密器实例.Fernet是AES加密的封装库,提供简单易用的对称加密功能 # 读取已有记录,避免新记录覆盖旧数据 records = [] if os.path.exists(LOG_FILE): # 检查日志文件是否存在 with open(LOG_FILE, "rb") as f: # 如果存在,以二进制模式读取加密数据 encrypted_data = f.read() decrypted_data = cipher.decrypt(encrypted_data) # 使用cipher.decrypt()解密 records = json.loads(decrypted_data) # 通过json.loads()将JSON字符串解析为Python列表 # 添加新记录 records.append(record) # 加密保存 encrypted_data = cipher.encrypt(json.dumps(records).encode()) # 将整个记录列表重新加密 with open(LOG_FILE, "wb") as f: f.write(encrypted_data) # 管理员管理使用记录⭐ def admin_view(self): """管理员查看使用记录""" password = simpledialog.askstring("❗", "请输入管理员密码:", show='*') if password == ADMIN_PASSWORD: records = self.get_usage_records() # 获取使用记录函数 self.display_records(records) # 显示使用记录函数 else: messagebox.showerror("认证失败", "密码错误!") # 密码框 def get_usage_records(self): """获取使用记录(解密)""" if not os.path.exists(KEY_FILE) or not os.path.exists(LOG_FILE): return [] try: with open(KEY_FILE, "rb") as f: key = f.read() cipher = Fernet(key) with open(LOG_FILE, "rb") as f: encrypted_data = f.read() decrypted_data = cipher.decrypt(encrypted_data) return json.loads(decrypted_data) except: return [] def display_records(self, records): """显示使用记录""" self.clear_screen() self.root.title("使用记录 - 管理员视图") self.root.geometry("1000x700") # 标题 title = tk.Label( self.root, text="电脑使用记录 - 安全报告", font=("Arial", 24, "bold"), pady=20, bg=LOGIN_BG, fg="white" ) title.pack() # 滚动文本框 text_area = scrolledtext.ScrolledText( self.root, wrap=tk.WORD, font=("Consolas", 12), width=120, height=30 ) text_area.pack(padx=20, pady=3, fill=tk.BOTH, expand=True) # 添加表头 header = "工号 登录时间 登出时间 使用时间\n" text_area.insert(tk.INSERT, header) text_area.insert(tk.INSERT, "-" * 65 + "\n") # 添加记录 for record in records: line = ( f"{record['user_id']:<8} " f"{record['login_time']:<20} " f"{record['logout_time']:<20} " f"{record['usage_duration']:<8}\n" # f"{record.get('lock_type', '自动'):<8}\n" ) text_area.insert(tk.INSERT, line) text_area.configure(state='disabled') # 设为只读 # 添加返回桌面按钮 btn_frame = tk.Frame(self.root) btn_frame.pack(pady=5) # pady参数在垂直方向(上下)添加10像素的填充,确保与其他界面元素有足够的间距 # 导出记录按钮 tk.Button( btn_frame, text="导出文件", command=lambda: self.export_records_csv(records), font=("黑体", 12), bg=BUTTON_BG, fg="white", width=15 ).pack(side=tk.LEFT, padx=10) # 返回按钮 tk.Button( btn_frame, text="返回桌面", command=self.start_desktop_session, font=("黑体", 12), bg=BUTTON_BG, fg="white", width=15 ).pack(side=tk.LEFT, padx=10) # # tk.Button( # btn_frame, # text="返回登录界面", # command=self.show_login_screen, # font=("黑体", 12), # bg=BUTTON_BG, # fg="white", # width=20 # ).pack(side=tk.LEFT, padx=10) # 将使用记录和人员名单导出 def export_records_csv(self, records): """导出使用记录为CSV文件""" try: # 获取当前时间作为文件名 timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime()) filename = f"使用记录_{timestamp}.csv" with open(filename, 'w', newline='', encoding='utf-8') as file: writer = csv.writer(file) # 写入表头 writer.writerow(["工号", "登录时间", "登出时间", "使用时间"]) # 写入每条记录 for record in records: writer.writerow([ record['user_id'], record['login_time'], record['logout_time'], record['usage_duration'] ]) # ⭐导出为excel表格 # try: # # 获取当前时间作为文件名 # timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime()) # filename = f"使用记录_{timestamp}.xlsx" # # # 创建DataFrame # data = { # "工号": [record['user_id'] for record in records], # "登录时间": [record['login_time'] for record in records], # "登出时间": [record['logout_time'] for record in records], # "使用时间": [record['usage_duration'] for record in records] # } # df = pd.DataFrame(data) # # # 导出到Excel # df.to_excel(filename, index=False, engine='openpyxl') # messagebox.showinfo("导出成功", f"使用记录已导出到: {os.path.abspath(filename)}") except Exception as e: messagebox.showerror("导出失败", f"导出使用记录时出错: {str(e)}") def export_users_csv(self): """导出用户名单为CSV文件(解密后导出只包含工号)""" try: # 获取当前时间作为文件名 timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime()) filename = f"用户名单_{timestamp}.csv" with open(filename, 'w', newline='', encoding='utf-8') as file: writer = csv.writer(file) # 写入表头(只包含工号) writer.writerow(["工号"]) # 写入每条记录(只导出工号) for user_id in TRAINED_USERS.keys(): writer.writerow([user_id]) messagebox.showinfo("导出成功", f"用户名单已解密并导出到: {os.path.abspath(filename)}") except Exception as e: messagebox.showerror("导出失败", f"导出用户名单时出错: {str(e)}") """导出excel文件""" # try: # timestamp = time.strftime("%Y%m%d_%H%M%S", time.localtime()) # filename = f"用户名单_{timestamp}.xlsx" # # # 创建dataframe # data = [] # for user_id, password in TRAINED_USERS.items(): # data.append([user_id, password]) # df = pd.DataFrame(data, columns=["工号", "密码"]) # # # 导出到excel # df.to_excel(filename, index=False, engine='openpyxl') def clear_screen(self): """清除当前屏幕所有内容""" for widget in self.root.winfo_children(): widget.destroy() def lock_on_close(self): """关闭窗口时锁定系统""" if self.current_user: self.lock_system(manual=True) self.root.destroy() # 启动系统 if __name__ == "__main__": app = SecureDesktopMonitor() # 绑定窗口关闭事件 app.root.protocol("WM_DELETE_WINDOW", app.lock_on_close)
11-01
先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值