跟据以下代码,进行修改并给出完整python:1、筛选功能移除,不需要了,2、添加档案时,页数为空,保存后显示不要为NONE,展示为空就可以了 3、统计页面优化一下美观程度 4、表格数据按灰白背景色交替展示import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext, simpledialog
import sqlite3
import os
import sys
import traceback
import re
from datetime import datetime
from tkinter import filedialog
class FileManagementSystem:
def init(self, root):
# 主窗口设置
self.root = root
self.root.title(“档案管理系统”)
self.root.geometry(“1200x750”)
self.root.minsize(1000, 650)
self.root.configure(bg=“#f0f2f5”)
# 设置应用程序图标 self.set_app_icon() # 样式配置 self.setup_styles() # 初始化数据库 self.init_database() # 当前类别 self.current_category = "文书类" self.current_infra_view = "总表" # 基建类当前视图:总表/明细 # 分页设置 self.current_page = 1 self.page_size = 20 # 每页显示20条记录 self.total_records = 0 self.total_pages = 1 # 筛选条件 self.filter_conditions = [] # 创建界面组件 self.create_widgets() # 加载数据 self.load_data() def set_app_icon(self): """设置应用程序图标(如果有图标文件)""" try: if getattr(sys, 'frozen', False): base_dir = os.path.dirname(sys.executable) else: base_dir = os.path.dirname(os.path.abspath(__file__)) icon_path = os.path.join(base_dir, "archive_icon.ico") if os.path.exists(icon_path): self.root.iconbitmap(icon_path) except: pass def setup_styles(self): """设置界面样式""" self.style = ttk.Style() # 基础字体设置 self.style.configure(".", font=("Microsoft YaHei", 10)) # 主题配置 self.style.theme_use("clam") # 统一按钮样式 (添加 focuswidth=0 去除焦点虚线框) self.style.configure("Primary.TButton", font=("Microsoft YaHei", 10), padding=8, background="#4285f4", foreground="white", borderwidth=1, relief="flat", width=4, focuswidth=0,focuscolor='') self.style.map("Primary.TButton", background=[("active", "#3367d6"), ("pressed", "#2850b3")]) # 删除按钮使用不同颜色 (添加 focuswidth=0) self.style.configure("Danger.TButton", font=("Microsoft YaHei", 10), padding=8, background="#ea4335", foreground="white", borderwidth=1, relief="flat", width=4, focuswidth=0,focuscolor='') self.style.map("Danger.TButton", background=[("active", "#d93025"), ("pressed", "#b31412")]) # 表格样式 self.style.configure("Treeview", background="white", foreground="#202124", rowheight=30, fieldbackground="white", borderwidth=1, relief="solid") self.style.configure("Treeview.Heading", background="#f8f9fa", foreground="#5f6368", font=("Microsoft YaHei", 10, "bold"), padding=8, relief="flat") self.style.map("Treeview.Heading", background=[("active", "#e8eaed")]) self.style.map("Treeview", background=[("selected", "#e8f0fe")], foreground=[("selected", "#202124")]) # 单选按钮样式 self.style.configure("TRadiobutton", background="#f0f2f5", font=("Microsoft YaHei", 10), foreground="#5f6368",focuswidth=0,focuscolor='') self.style.map("TRadiobutton", foreground=[("selected", "#4285f4")]) # 输入框样式 self.style.configure("TEntry", fieldbackground="white", borderwidth=1, relief="solid", padding=5) # 必填输入框样式 self.style.configure("Required.TEntry", fieldbackground="#fff8f8", borderwidth=1, relief="solid", padding=5) # 标签样式 self.style.configure("Header.TLabel", font=("Microsoft YaHei", 16, "bold"), background="#4285f4", foreground="white") self.style.configure("Section.TLabel", font=("Microsoft YaHei", 10, "bold"), background="#f0f2f5", foreground="#5f6368") # 分页按钮样式 (添加 focuswidth=0) self.style.configure("Page.TButton", font=("Microsoft YaHei", 9), padding=4, background="#e8eaed", foreground="#5f6368", borderwidth=1, relief="flat",focuswidth=0,focuscolor='') self.style.map("Page.TButton", background=[("active", "#d7d9dd"), ("pressed", "#c5c7cb")]) # 分页标签样式 self.style.configure("Page.TLabel", background="#f0f2f5", foreground="#5f6368", font=("Microsoft YaHei", 9)) def init_database(self): """初始化数据库,处理打包路径问题""" try: # 获取可执行文件所在目录(打包后) if getattr(sys, 'frozen', False): base_dir = os.path.dirname(sys.executable) else: base_dir = os.path.dirname(os.path.abspath(__file__)) # 确保目录存在 os.makedirs(base_dir, exist_ok=True) db_path = os.path.join(base_dir, "file_management.db") self.conn = sqlite3.connect(db_path) self.cursor = self.conn.cursor() # 创建文书类表(增加保存库房字段) self.cursor.execute(''' CREATE TABLE IF NOT EXISTS documents ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_number TEXT NOT NULL, document_number TEXT, responsible TEXT, title TEXT NOT NULL, date TEXT, security_level TEXT, page_count INTEGER, retention_period TEXT, carrier_form TEXT, storage_location TEXT, -- 新增保存库房字段 remarks TEXT ) ''') # 创建基建类总表 self.cursor.execute(''' CREATE TABLE IF NOT EXISTS infrastructure_summary ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_number TEXT NOT NULL, title TEXT NOT NULL, date TEXT, security_level TEXT, total_pages INTEGER, retention_period TEXT, carrier_form TEXT, storage_location TEXT, -- 保存库房 remarks TEXT ) ''') # 创建基建类明细表 self.cursor.execute(''' CREATE TABLE IF NOT EXISTS infrastructure_detail ( id INTEGER PRIMARY KEY AUTOINCREMENT, summary_id INTEGER, -- 关联总表ID file_number TEXT NOT NULL, document_number TEXT, responsible TEXT, title TEXT NOT NULL, date TEXT, security_level TEXT, page_number TEXT, -- 页次(可以是范围) retention_period TEXT, carrier_form TEXT, storage_location TEXT, -- 保存库房 remarks TEXT, FOREIGN KEY (summary_id) REFERENCES infrastructure_summary(id) ) ''') self.conn.commit() except Exception as e: messagebox.showerror("数据库错误", f"初始化数据库失败: {str(e)}") traceback.print_exc() sys.exit(1) def create_widgets(self): """创建现代化界面组件""" # 主布局容器 main_frame = tk.Frame(self.root, bg="#f0f2f5") main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=15) # 顶部标题栏 header_frame = tk.Frame(main_frame, bg="#4285f4", height=60) header_frame.pack(fill=tk.X) header_frame.pack_propagate(False) title_label = tk.Label(header_frame, text="档案管理系统", font=("Microsoft YaHei", 18, "bold"), bg="#4285f4", fg="white") title_label.pack(pady=15) # 功能区 function_frame = tk.Frame(main_frame, bg="#f0f2f5", pady=15) function_frame.pack(fill=tk.X) # 左侧分类选择 category_frame = tk.Frame(function_frame, bg="#f0f2f5") category_frame.pack(side=tk.LEFT, padx=(0, 20)) ttk.Label(category_frame, text="档案类别:", style="Section.TLabel").pack(side=tk.LEFT, padx=5) self.category_var = tk.StringVar(value="文书类") category_container = tk.Frame(category_frame, bg="#f0f2f5") category_container.pack(side=tk.LEFT) doc_radio = ttk.Radiobutton( category_container, text="文书类", variable=self.category_var, value="文书类", command=self.on_category_change, style="TRadiobutton" ) inf_radio = ttk.Radiobutton( category_container, text="基建类", variable=self.category_var, value="基建类", command=self.on_category_change, style="TRadiobutton" ) doc_radio.pack(side=tk.LEFT, padx=10) inf_radio.pack(side=tk.LEFT, padx=10) # 基建类视图切换 self.view_frame = tk.Frame(function_frame, bg="#f0f2f5") # 基建类视图切换标签 self.view_label = ttk.Label(self.view_frame, text="视图:", style="Section.TLabel") self.view_label.pack(side=tk.LEFT, padx=5) # 基建类视图切换按钮 self.view_var = tk.StringVar(value="总表") self.summary_btn = ttk.Radiobutton( self.view_frame, text="总表", variable=self.view_var, value="总表", command=self.on_view_change, style="TRadiobutton" ) self.detail_btn = ttk.Radiobutton( self.view_frame, text="明细", variable=self.view_var, value="明细", command=self.on_view_change, style="TRadiobutton" ) # 初始隐藏视图切换 self.view_frame.pack_forget() # 搜索区 search_frame = tk.Frame(function_frame, bg="#f0f2f5") search_frame.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 20)) ttk.Label(search_frame, text="搜索:", style="Section.TLabel").pack(side=tk.LEFT, padx=5) self.search_var = tk.StringVar() self.search_entry = ttk.Entry(search_frame, textvariable=self.search_var, style="TEntry", font=("Microsoft YaHei", 10)) self.search_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True, ipady=2) self.search_entry.bind("<Return>", lambda event: self.search_data()) # 搜索按钮 search_btn = ttk.Button(search_frame, text="搜索", command=self.search_data, style="Primary.TButton") search_btn.pack(side=tk.LEFT, padx=5) # 重置按钮 reset_btn = ttk.Button(search_frame, text="重置", command=self.reset_search, style="Primary.TButton") reset_btn.pack(side=tk.LEFT) # 高级筛选按钮 adv_filter_btn = ttk.Button(search_frame, text="筛选", command=self.open_advanced_filter, style="Primary.TButton") adv_filter_btn.pack(side=tk.LEFT, padx=5) # 统计按钮 stats_btn = ttk.Button(search_frame, text="统计", command=self.show_statistics, style="Primary.TButton") stats_btn.pack(side=tk.LEFT) # 右侧操作按钮 button_frame = tk.Frame(function_frame, bg="#f0f2f5") button_frame.pack(side=tk.RIGHT) self.add_btn = ttk.Button(button_frame, text="添加", command=self.add_record, style="Primary.TButton") self.add_btn.pack(side=tk.LEFT, padx=5) self.edit_btn = ttk.Button(button_frame, text="修改", command=self.edit_record, style="Primary.TButton") self.edit_btn.pack(side=tk.LEFT, padx=5) self.delete_btn = ttk.Button(button_frame, text="删除", command=self.delete_record, style="Danger.TButton") self.delete_btn.pack(side=tk.LEFT, padx=5) # 表格区域 table_frame = tk.Frame(main_frame, bg="#e0e0e0", padx=1, pady=1) table_frame.pack(fill=tk.BOTH, expand=True) # 表格标题栏 table_header = tk.Frame(table_frame, bg="#f8f9fa", height=40) table_header.pack(fill=tk.X) table_header.pack_propagate(False) self.table_title = tk.Label(table_header, text=f"{self.current_category}档案列表", font=("Microsoft YaHei", 11, "bold"), bg="#f8f9fa", fg="#5f6368") self.table_title.pack(side=tk.LEFT, padx=15) # 表格容器 table_container = tk.Frame(table_frame, bg="white", bd=1, relief=tk.SOLID) table_container.pack(fill=tk.BOTH, expand=True) # 滚动条 scrollbar_x = ttk.Scrollbar(table_container, orient=tk.HORIZONTAL) scrollbar_y = ttk.Scrollbar(table_container, orient=tk.VERTICAL) # 表格 self.tree = ttk.Treeview( table_container, columns=self.get_columns(), show="headings", yscrollcommand=scrollbar_y.set, xscrollcommand=scrollbar_x.set, style="Treeview" ) # 配置列 columns = self.get_columns() for col in columns: self.tree.heading(col, text=col) width = 110 if col not in ["题名", "备注"] else 200 if col == "题名" else 150 self.tree.column(col, width=width, anchor=tk.CENTER, stretch=False) # 布局 scrollbar_y.pack(side=tk.RIGHT, fill=tk.Y) scrollbar_x.pack(side=tk.BOTTOM, fill=tk.X) self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar_y.config(command=self.tree.yview) scrollbar_x.config(command=self.tree.xview) # 绑定事件 self.tree.bind("<Double-1>", lambda e: self.edit_record()) # 分页控件 pagination_frame = tk.Frame(main_frame, bg="#f0f2f5", height=40, pady=10) pagination_frame.pack(fill=tk.X) # 上一页按钮 self.prev_btn = ttk.Button(pagination_frame, text="上一页", command=self.prev_page, style="Page.TButton", width=8) self.prev_btn.pack(side=tk.LEFT, padx=5) # 页码标签 self.page_label = ttk.Label(pagination_frame, text="1/1", style="Page.TLabel") self.page_label.pack(side=tk.LEFT, padx=10) # 下一页按钮 self.next_btn = ttk.Button(pagination_frame, text="下一页", command=self.next_page, style="Page.TButton", width=8) self.next_btn.pack(side=tk.LEFT, padx=5) # 跳转输入框 ttk.Label(pagination_frame, text="跳转至:", style="Page.TLabel").pack(side=tk.LEFT, padx=(20, 5)) self.page_var = tk.StringVar() self.page_entry = ttk.Entry(pagination_frame, textvariable=self.page_var, width=5, font=("Microsoft YaHei", 9)) self.page_entry.pack(side=tk.LEFT) # 跳转按钮 goto_btn = ttk.Button(pagination_frame, text="跳转", command=self.goto_page, style="Page.TButton", width=6) goto_btn.pack(side=tk.LEFT, padx=5) # 每页显示数量 ttk.Label(pagination_frame, text="每页显示:", style="Page.TLabel").pack(side=tk.LEFT, padx=(20, 5)) self.page_size_var = tk.StringVar(value=str(self.page_size)) page_size_combo = ttk.Combobox(pagination_frame, textvariable=self.page_size_var, width=5, font=("Microsoft YaHei", 9), state="readonly") page_size_combo['values'] = ('10', '20', '50', '100') page_size_combo.pack(side=tk.LEFT) page_size_combo.bind("<<ComboboxSelected>>", self.change_page_size) # 页脚 footer_frame = tk.Frame(main_frame, bg="#f0f2f5", height=30) footer_frame.pack(fill=tk.X, pady=(10, 0)) # 左侧状态信息 self.status_var = tk.StringVar(value="记录数量:0") status_label = ttk.Label( footer_frame, textvariable=self.status_var, style="Page.TLabel", anchor=tk.W ) status_label.pack(side=tk.LEFT, padx=20, pady=5) # 右侧版权信息 footer_label = ttk.Label( footer_frame, text="矿调所大数据中心 © 2025 开发人员:袁沙", style="Page.TLabel" ) footer_label.pack(side=tk.RIGHT, padx=20, pady=5) def center_window(self, window, width, height): """使窗口居中显示""" screen_width = window.winfo_screenwidth() screen_height = window.winfo_screenheight() x = (screen_width - width) // 2 y = (screen_height - height) // 2 - 20 # 稍微上移一点 window.geometry(f"{width}x{height}+{x}+{y}") window.focus_set() def get_columns(self): """获取当前类别的列""" if self.current_category == "文书类": return ["序号", "档号", "文号", "责任者", "题名", "日期", "密级", "页数", "保存期限", "载体形式", "保存库房", "备注"] else: if self.current_infra_view == "总表": return ["序号", "档号", "题名", "日期", "密级", "总页数", "保存期限", "载体形式", "保存库房", "备注"] else: return ["序号", "档号", "文号", "责任者", "题名", "日期", "密级", "页次", "保存期限", "载体形式", "保存库房", "备注"] def on_category_change(self): """类别改变时更新界面""" self.current_category = self.category_var.get() self.current_page = 1 # 重置到第一页 # 更新表格标题 self.table_title.config(text=f"{self.current_category}档案列表") # 清空表格数据 for item in self.tree.get_children(): self.tree.delete(item) # 根据类别显示/隐藏视图切换 if self.current_category == "基建类": self.view_frame.pack(side=tk.LEFT, padx=(0, 20)) self.summary_btn.pack(side=tk.LEFT, padx=10) self.detail_btn.pack(side=tk.LEFT, padx=10) else: self.view_frame.pack_forget() self.current_infra_view = "总表" # 重置视图 # 重新设置表格列 new_columns = self.get_columns() self.tree["columns"] = new_columns # 配置新列 for col in new_columns: self.tree.heading(col, text=col) width = 110 if col not in ["题名", "备注"] else 200 if col == "题名" else 150 self.tree.column(col, width=width, anchor=tk.CENTER, stretch=False) # 重新加载对应类别的数据 self.load_data() def on_view_change(self): """基建类视图切换""" if self.current_category == "基建类": self.current_infra_view = self.view_var.get() self.current_page = 1 # 重置到第一页 # 更新表格标题 self.table_title.config(text=f"基建类档案{self.current_infra_view}列表") # 清空表格数据 for item in self.tree.get_children(): self.tree.delete(item) # 重新设置表格列 new_columns = self.get_columns() self.tree["columns"] = new_columns # 配置新列 for col in new_columns: self.tree.heading(col, text=col) width = 110 if col not in ["题名", "备注"] else 200 if col == "题名" else 150 self.tree.column(col, width=width, anchor=tk.CENTER, stretch=False) # 重新加载数据 self.load_data() def load_data(self, search_term=None): """加载数据,使用参数化查询防止SQL注入""" try: # 清空表格 for item in self.tree.get_children(): self.tree.delete(item) # 根据当前类别和视图查询数据 if self.current_category == "文书类": query = """ SELECT id, file_number, document_number, responsible, title, date, security_level, page_count, retention_period, carrier_form, storage_location, remarks FROM documents """ count_query = "SELECT COUNT(*) FROM documents" else: if self.current_infra_view == "总表": query = """ SELECT id, file_number, title, date, security_level, total_pages, retention_period, carrier_form, storage_location, remarks FROM infrastructure_summary """ count_query = "SELECT COUNT(*) FROM infrastructure_summary" else: query = """ SELECT d.id, d.file_number, d.document_number, d.responsible, d.title, d.date, d.security_level, d.page_number, d.retention_period, d.carrier_form, d.storage_location, d.remarks FROM infrastructure_detail d """ count_query = "SELECT COUNT(*) FROM infrastructure_detail" # 添加筛选条件 where_clause = "" params = () # 应用高级筛选条件 if self.filter_conditions: conditions = [] for condition in self.filter_conditions: field, operator, value = condition # 处理日期范围 if operator == "between": start, end = value conditions.append(f"{field} BETWEEN ? AND ?") params += (start, end) else: conditions.append(f"{field} {operator} ?") params += (value,) where_clause = " AND ".join(conditions) # 添加搜索条件 if search_term: search_condition = " OR ".join([ "file_number LIKE ?", "title LIKE ?", "responsible LIKE ?", "document_number LIKE ?" ]) if where_clause: where_clause += " AND (" + search_condition + ")" else: where_clause = "WHERE " + search_condition search_pattern = f"%{search_term}%" params += (search_pattern, search_pattern, search_pattern, search_pattern) elif where_clause: where_clause = "WHERE " + where_clause # 计算总记录数 if where_clause: count_query += " " + where_clause self.cursor.execute(count_query, params) self.total_records = self.cursor.fetchone()[0] # 计算总页数 self.total_pages = max(1, (self.total_records + self.page_size - 1) // self.page_size) # 确保当前页在有效范围内 if self.current_page > self.total_pages: self.current_page = max(1, self.total_pages) # 添加分页限制 offset = (self.current_page - 1) * self.page_size query += " " + where_clause if where_clause else "" query += " ORDER BY id LIMIT ? OFFSET ?" params = params + (self.page_size, offset) self.cursor.execute(query, params) records = self.cursor.fetchall() # 更新状态栏 if search_term or self.filter_conditions: self.status_var.set(f"搜索到 {self.total_records} 条记录") else: self.status_var.set(f"总记录:{self.total_records} 条,当前显示第 {(self.current_page-1)*self.page_size+1} 到 {min(self.current_page*self.page_size, self.total_records)} 条") # 更新分页控件状态 self.prev_btn.state(["!disabled" if self.current_page > 1 else "disabled"]) self.next_btn.state(["!disabled" if self.current_page < self.total_pages else "disabled"]) self.page_label.config(text=f"{self.current_page}/{self.total_pages}") # 插入数据 start_index = (self.current_page - 1) * self.page_size + 1 for i, record in enumerate(records, start_index): values = (i,) + record[1:] tag = "even" if i % 2 == 0 else "odd" self.tree.insert("", tk.END, values=values, tags=(record[0], tag)) # 配置行样式 self.tree.tag_configure("odd", background="white") self.tree.tag_configure("even", background="#f8f9fa") except Exception as e: messagebox.showerror("数据库错误", f"加载数据失败: {str(e)}") traceback.print_exc() def search_data(self): """搜索当前类别的数据""" search_term = self.search_var.get().strip() self.current_page = 1 # 搜索后重置到第一页 self.load_data(search_term) def reset_search(self): """重置搜索""" self.search_var.set("") self.filter_conditions = [] # 清除筛选条件 self.current_page = 1 self.load_data() def change_page_size(self, event=None): """更改每页显示数量""" try: new_size = int(self.page_size_var.get()) if new_size > 0: self.page_size = new_size self.current_page = 1 # 重置到第一页 self.load_data() except ValueError: pass def prev_page(self): """上一页""" if self.current_page > 1: self.current_page -= 1 self.load_data(self.search_var.get().strip()) def next_page(self): """下一页""" if self.current_page < self.total_pages: self.current_page += 1 self.load_data(self.search_var.get().strip()) def goto_page(self): """跳转到指定页码""" try: page_num = int(self.page_var.get()) if 1 <= page_num <= self.total_pages: self.current_page = page_num self.load_data(self.search_var.get().strip()) else: messagebox.showwarning("提示", f"请输入1到{self.total_pages}之间的页码") except ValueError: messagebox.showwarning("提示", "请输入有效的页码数字") def open_advanced_filter(self): """打开高级筛选对话框""" dialog = tk.Toplevel(self.root) dialog.title("筛选") self.center_window(dialog, 600, 400) dialog.resizable(False, False) dialog.transient(self.root) dialog.grab_set() dialog.configure(bg="#f0f2f5") # 标题栏 header = tk.Frame(dialog, bg="#4285f4", height=50) header.pack(fill=tk.X) header.pack_propagate(False) tk.Label(header, text="筛选条件", font=("Microsoft YaHei", 14, "bold"), bg="#4285f4", fg="white").pack(pady=12) # 内容区域 content_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) content_frame.pack(fill=tk.BOTH, expand=True) # 条件列表 conditions_frame = tk.Frame(content_frame, bg="#f0f2f5") conditions_frame.pack(fill=tk.BOTH, expand=True) # 字段列表(根据当前类别) if self.current_category == "文书类": fields = ["档号", "文号", "责任者", "题名", "日期", "密级", "页数", "保存期限", "载体形式", "保存库房", "备注"] else: if self.current_infra_view == "总表": fields = ["档号", "题名", "日期", "密级", "总页数", "保存期限", "载体形式", "保存库房", "备注"] else: fields = ["档号", "文号", "责任者", "题名", "日期", "密级", "页次", "保存期限", "载体形式", "保存库房", "备注"] # 运算符 operators = ["=", "!=", ">", "<", ">=", "<=", "LIKE", "BETWEEN"] # 当前条件 self.conditions = [] # 添加初始条件行 self.add_condition_row(conditions_frame, fields, operators) # 添加条件按钮 add_btn_frame = tk.Frame(conditions_frame, bg="#f0f2f5") add_btn_frame.pack(fill=tk.X, pady=10) ttk.Button(add_btn_frame, text="添加条件", command=lambda: self.add_condition_row(conditions_frame, fields, operators), style="Primary.TButton").pack(side=tk.LEFT) # 按钮区域 btn_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) btn_frame.pack(fill=tk.X) ttk.Button(btn_frame, text="筛选", command=lambda: self.apply_filter(dialog), style="Primary.TButton").pack(side=tk.RIGHT, padx=10) ttk.Button(btn_frame, text="取消", command=dialog.destroy, style="Primary.TButton").pack(side=tk.RIGHT) def add_condition_row(self, parent, fields, operators): """添加一个条件行""" row_frame = tk.Frame(parent, bg="#f0f2f5", pady=5) row_frame.pack(fill=tk.X) # 字段选择 field_var = tk.StringVar(value=fields[0]) field_combo = ttk.Combobox(row_frame, textvariable=field_var, values=fields, width=12, state="readonly") field_combo.pack(side=tk.LEFT, padx=5) # 运算符选择 operator_var = tk.StringVar(value=operators[0]) operator_combo = ttk.Combobox(row_frame, textvariable=operator_var, values=operators, width=8, state="readonly") operator_combo.pack(side=tk.LEFT, padx=5) # 值输入 value_var = tk.StringVar() value_entry = ttk.Entry(row_frame, textvariable=value_var, width=20) value_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) # 日期范围输入(当运算符为BETWEEN时显示) start_var = tk.StringVar() end_var = tk.StringVar() date_frame = tk.Frame(row_frame, bg="#f0f2f5") ttk.Entry(date_frame, textvariable=start_var, width=10).pack(side=tk.LEFT) ttk.Label(date_frame, text="至", bg="#f0f2f5").pack(side=tk.LEFT, padx=5) ttk.Entry(date_frame, textvariable=end_var, width=10).pack(side=tk.LEFT) date_frame.pack_forget() # 初始隐藏 # 删除按钮 delete_btn = ttk.Button(row_frame, text="×", width=2, command=lambda r=row_frame: r.destroy()) delete_btn.pack(side=tk.RIGHT, padx=5) # 绑定运算符变化事件 def on_operator_change(*args): if operator_var.get() == "BETWEEN": value_entry.pack_forget() date_frame.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) else: date_frame.pack_forget() value_entry.pack(side=tk.LEFT, padx=5, fill=tk.X, expand=True) operator_var.trace("w", on_operator_change) # 保存行引用 self.conditions.append({ "row": row_frame, "field": field_var, "operator": operator_var, "value": value_var, "start": start_var, "end": end_var }) def apply_filter(self, dialog): """应用筛选条件""" self.filter_conditions = [] for condition in self.conditions: if condition["row"].winfo_exists(): # 确保行未被删除 field = condition["field"].get() operator = condition["operator"].get() if operator == "BETWEEN": start = condition["start"].get().strip() end = condition["end"].get().strip() if not start or not end: continue # 验证日期格式 try: datetime.strptime(start, "%Y-%m-%d") datetime.strptime(end, "%Y-%m-%d") self.filter_conditions.append((field, operator, (start, end))) except ValueError: messagebox.showwarning("格式错误", "请输入有效的日期格式(YYYY-MM-DD)") return else: value = condition["value"].get().strip() if value: if operator == "LIKE": value = f"%{value}%" self.filter_conditions.append((field, operator, value)) self.current_page = 1 self.load_data() dialog.destroy() def show_statistics(self): """显示统计结果""" dialog = tk.Toplevel(self.root) dialog.title("档案统计") self.center_window(dialog, 600, 400) dialog.resizable(False, False) dialog.transient(self.root) dialog.grab_set() dialog.configure(bg="#f0f2f5") # 标题栏 header = tk.Frame(dialog, bg="#4285f4", height=50) header.pack(fill=tk.X) header.pack_propagate(False) tk.Label(header, text="档案统计结果", font=("Microsoft YaHei", 14, "bold"), bg="#4285f4", fg="white").pack(pady=12) # 内容区域 content_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) content_frame.pack(fill=tk.BOTH, expand=True) # 统计结果文本区域 stats_text = scrolledtext.ScrolledText(content_frame, wrap=tk.WORD, font=("Microsoft YaHei", 10)) stats_text.pack(fill=tk.BOTH, expand=True) # 获取统计结果 stats_result = self.get_statistics() stats_text.insert(tk.END, stats_result) stats_text.config(state=tk.DISABLED) # 导出按钮 btn_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=10) btn_frame.pack(fill=tk.X) ttk.Button(btn_frame, text="导出统计结果", command=lambda: self.export_statistics(stats_result), style="Primary.TButton").pack(side=tk.RIGHT) def get_statistics(self): """获取统计结果""" result = "" if self.current_category == "文书类": # 文书类按年份统计 self.cursor.execute(""" SELECT SUBSTR(file_number, INSTR(file_number, '·') + 1, 4) AS year, COUNT(DISTINCT file_number) AS file_count FROM documents WHERE year GLOB '[0-9][0-9][0-9][0-9]' GROUP BY year ORDER BY year """) year_stats = self.cursor.fetchall() result += "文书类档案按年份统计:\n" result += "年份\t档号数量\n" result += "----------------\n" for row in year_stats: result += f"{row[0]}\t{row[1]}\n" result += "\n" else: # 基建类 if self.current_infra_view == "总表": # 总表按保存库房统计 self.cursor.execute(""" SELECT storage_location, COUNT(*) AS count FROM infrastructure_summary GROUP BY storage_location ORDER BY storage_location """) location_stats = self.cursor.fetchall() result += "基建类总表按保存库房统计:\n" result += "保存库房\t数量\n" result += "----------------\n" for row in location_stats: result += f"{row[0]}\t{row[1]}\n" else: # 明细按档号统计 self.cursor.execute(""" SELECT file_number, COUNT(*) AS count FROM infrastructure_detail GROUP BY file_number ORDER BY file_number """) file_stats = self.cursor.fetchall() result += "基建类明细按档号统计:\n" result += "档号\t数量\n" result += "----------------\n" for row in file_stats: result += f"{row[0]}\t{row[1]}\n" return result # def export_statistics(self, stats_result): # """导出统计结果到文件""" # file_path = filedialog.asksaveasfilename( # defaultextension=".txt", # filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")], # title="保存统计结果" # ) # # if file_path: # try: # with open(file_path, "w", encoding="utf-8") as f: # f.write(stats_result) # messagebox.showinfo("成功", "统计结果已成功导出!") # except Exception as e: # messagebox.showerror("错误", f"导出失败: {str(e)}") def add_record(self): """添加记录对话框 - 两列布局""" dialog = tk.Toplevel(self.root) dialog.title(f"添加{self.current_category}档案") self.center_window(dialog, 800, 550) dialog.resizable(False, False) dialog.transient(self.root) dialog.grab_set() dialog.configure(bg="#f0f2f5") # 标题栏 header = tk.Frame(dialog, bg="#4285f4", height=50) header.pack(fill=tk.X) header.pack_propagate(False) tk.Label(header, text=f"添加{self.current_category}档案", font=("Microsoft YaHei", 14, "bold"), bg="#4285f4", fg="white").pack(pady=12) # 内容区域 content_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) content_frame.pack(fill=tk.BOTH, expand=True) # 创建双列容器 columns_frame = tk.Frame(content_frame, bg="#f0f2f5") columns_frame.pack(fill=tk.BOTH, expand=True) # 左列框架 left_frame = tk.Frame(columns_frame, bg="#f0f2f5", padx=10) left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 右列框架 right_frame = tk.Frame(columns_frame, bg="#f0f2f5", padx=10) right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) # 输入字段 entries = {} columns = self.get_columns()[1:] # 排除序号 # 左列字段 left_columns = columns[:len(columns)//2] for col in left_columns: frame = tk.Frame(left_frame, bg="#f0f2f5", pady=8) frame.pack(fill=tk.X) label_text = f"{col}*" if col in ["档号", "题名"] else col label_color = "#ea4335" if col in ["档号", "题名"] else "#5f6368" tk.Label(frame, text=label_text, width=8, font=("Microsoft YaHei", 10), bg="#f0f2f5", fg=label_color, anchor="w").pack(side=tk.LEFT) entry_style = "Required.TEntry" if col in ["档号", "题名"] else "TEntry" entry = ttk.Entry(frame, font=("Microsoft YaHei", 10), style=entry_style) entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, ipady=3, padx=(10, 0)) entries[col] = entry # 右列字段 right_columns = columns[len(columns)//2:] for col in right_columns: frame = tk.Frame(right_frame, bg="#f0f2f5", pady=8) frame.pack(fill=tk.X) label_text = f"{col}*" if col in ["档号", "题名"] else col label_color = "#ea4335" if col in ["档号", "题名"] else "#5f6368" tk.Label(frame, text=label_text, width=8, font=("Microsoft YaHei", 10), bg="#f0f2f5", fg=label_color, anchor="w").pack(side=tk.LEFT) entry_style = "Required.TEntry" if col in ["档号", "题名"] else "TEntry" entry = ttk.Entry(frame, font=("Microsoft YaHei", 10), style=entry_style) entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, ipady=3, padx=(10, 0)) entries[col] = entry # 按钮区域 btn_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) btn_frame.pack(fill=tk.X) # 交换按钮顺序:先保存后取消 ttk.Button(btn_frame, text="保存", command=lambda: self.save_record(entries, dialog, is_new=True), style="Primary.TButton").pack(side=tk.RIGHT, padx=10) ttk.Button(btn_frame, text="取消", command=dialog.destroy, style="Primary.TButton").pack(side=tk.RIGHT) def edit_record(self): """编辑记录对话框 - 两列布局""" selected_items = self.tree.selection() if not selected_items: messagebox.showwarning("提示", "请先选择一条记录!") return selected_item = selected_items[0] record_id = self.tree.item(selected_item, "tags")[0] current_values = self.tree.item(selected_item, "values") # 创建对话框 dialog = tk.Toplevel(self.root) dialog.title(f"修改{self.current_category}档案") self.center_window(dialog, 800, 550) dialog.resizable(False, False) dialog.transient(self.root) dialog.grab_set() dialog.configure(bg="#f0f2f5") # 标题栏 header = tk.Frame(dialog, bg="#4285f4", height=50) header.pack(fill=tk.X) header.pack_propagate(False) tk.Label(header, text=f"修改{self.current_category}档案", font=("Microsoft YaHei", 14, "bold"), bg="#4285f4", fg="white").pack(pady=12) # 内容区域 content_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) content_frame.pack(fill=tk.BOTH, expand=True) # 创建双列容器 columns_frame = tk.Frame(content_frame, bg="#f0f2f5") columns_frame.pack(fill=tk.BOTH, expand=True) # 左列框架 left_frame = tk.Frame(columns_frame, bg="#f0f2f5", padx=10) left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) # 右列框架 right_frame = tk.Frame(columns_frame, bg="#f0f2f5", padx=10) right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True) # 输入字段 entries = {} columns = self.get_columns()[1:] # 排除序号 values = current_values[1:] # 排除序号 # 左列字段 left_columns = columns[:len(columns)//2] for i, col in enumerate(left_columns): frame = tk.Frame(left_frame, bg="#f0f2f5", pady=8) frame.pack(fill=tk.X) label_text = f"{col}*" if col in ["档号", "题名"] else col label_color = "#ea4335" if col in ["档号", "题名"] else "#5f6368" tk.Label(frame, text=label_text, width=8, font=("Microsoft YaHei", 10), bg="#f0f2f5", fg=label_color, anchor="w").pack(side=tk.LEFT) entry_style = "Required.TEntry" if col in ["档号", "题名"] else "TEntry" entry = ttk.Entry(frame, font=("Microsoft YaHei", 10), style=entry_style) entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, ipady=3, padx=(10, 0)) # 填充现有值 if i < len(values): entry.insert(0, values[i]) entries[col] = entry # 右列字段 right_columns = columns[len(columns)//2:] for i, col in enumerate(right_columns): frame = tk.Frame(right_frame, bg="#f0f2f5", pady=8) frame.pack(fill=tk.X) label_text = f"{col}*" if col in ["档号", "题名"] else col label_color = "#ea4335" if col in ["档号", "题名"] else "#5f6368" tk.Label(frame, text=label_text, width=8, font=("Microsoft YaHei", 10), bg="#f0f2f5", fg=label_color, anchor="w").pack(side=tk.LEFT) entry_style = "Required.TEntry" if col in ["档号", "题名"] else "TEntry" entry = ttk.Entry(frame, font=("Microsoft YaHei", 10), style=entry_style) entry.pack(side=tk.RIGHT, fill=tk.X, expand=True, ipady=3, padx=(10, 0)) # 填充现有值 idx = len(left_columns) + i if idx < len(values): entry.insert(0, values[idx]) entries[col] = entry # 按钮区域 btn_frame = tk.Frame(dialog, bg="#f0f2f5", padx=20, pady=15) btn_frame.pack(fill=tk.X) # 交换按钮顺序:先保存后取消 ttk.Button(btn_frame, text="保存", command=lambda: self.save_record(entries, dialog, is_new=False, record_id=record_id), style="Primary.TButton").pack(side=tk.RIGHT, padx=10) ttk.Button(btn_frame, text="取消", command=dialog.destroy, style="Primary.TButton").pack(side=tk.RIGHT) def save_record(self, entries, dialog, is_new=True, record_id=None): """保存记录(新增或修改)""" try: # 收集数据 data = {} for col, entry in entries.items(): data[col] = entry.get().strip() # 验证 if not data["档号"]: messagebox.showerror("错误", "档号不能为空!") return if not data["题名"]: messagebox.showerror("错误", "题名不能为空!") return if is_new: # 新增记录 if self.current_category == "文书类": self.cursor.execute(''' INSERT INTO documents ( file_number, document_number, responsible, title, date, security_level, page_count, retention_period, carrier_form, storage_location, remarks ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( data["档号"], data["文号"], data["责任者"], data["题名"], data["日期"], data["密级"], data["页数"] if data["页数"] else None, data["保存期限"], data["载体形式"], data["保存库房"], data["备注"] )) else: if self.current_infra_view == "总表": self.cursor.execute(''' INSERT INTO infrastructure_summary ( file_number, title, date, security_level, total_pages, retention_period, carrier_form, storage_location, remarks ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( data["档号"], data["题名"], data["日期"], data["密级"], data["总页数"] if data["总页数"] else None, data["保存期限"], data["载体形式"], data["保存库房"], data["备注"] )) else: # 明细需要关联总表 # 查找总表ID self.cursor.execute("SELECT id FROM infrastructure_summary WHERE file_number = ?", (data["档号"],)) summary = self.cursor.fetchone() summary_id = summary[0] if summary else None self.cursor.execute(''' INSERT INTO infrastructure_detail ( summary_id, file_number, document_number, responsible, title, date, security_level, page_number, retention_period, carrier_form, storage_location, remarks ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ''', ( summary_id, data["档号"], data["文号"], data["责任者"], data["题名"], data["日期"], data["密级"], data["页次"], data["保存期限"], data["载体形式"], data["保存库房"], data["备注"] )) else: # 修改记录 if self.current_category == "文书类": self.cursor.execute(''' UPDATE documents SET file_number = ?, document_number = ?, responsible = ?, title = ?, date = ?, security_level = ?, page_count = ?, retention_period = ?, carrier_form = ?, storage_location = ?, remarks = ? WHERE id = ? ''', ( data["档号"], data["文号"], data["责任者"], data["题名"], data["日期"], data["密级"], data["页数"] if data["页数"] else None, data["保存期限"], data["载体形式"], data["保存库房"], data["备注"], record_id )) else: if self.current_infra_view == "总表": self.cursor.execute(''' UPDATE infrastructure_summary SET file_number = ?, title = ?, date = ?, security_level = ?, total_pages = ?, retention_period = ?, carrier_form = ?, storage_location = ?, remarks = ? WHERE id = ? ''', ( data["档号"], data["题名"], data["日期"], data["密级"], data["总页数"] if data["总页数"] else None, data["保存期限"], data["载体形式"], data["保存库房"], data["备注"], record_id )) else: # 更新明细时同时更新关联的总表ID self.cursor.execute("SELECT id FROM infrastructure_summary WHERE file_number = ?", (data["档号"],)) summary = self.cursor.fetchone() summary_id = summary[0] if summary else None self.cursor.execute(''' UPDATE infrastructure_detail SET summary_id = ?, file_number = ?, document_number = ?, responsible = ?, title = ?, date = ?, security_level = ?, page_number = ?, retention_period = ?, carrier_form = ?, storage_location = ?, remarks = ? WHERE id = ? ''', ( summary_id, data["档号"], data["文号"], data["责任者"], data["题名"], data["日期"], data["密级"], data["页次"], data["保存期限"], data["载体形式"], data["保存库房"], data["备注"], record_id )) self.conn.commit() dialog.destroy() self.load_data() messagebox.showinfo("成功", "记录保存成功!") except Exception as e: messagebox.showerror("错误", f"保存失败:{str(e)}") traceback.print_exc() def delete_record(self): """删除记录""" selected_items = self.tree.selection() if not selected_items: messagebox.showwarning("提示", "请先选择一条记录!") return if messagebox.askyesno("确认删除", "确定要删除选中的记录吗?\n此操作不可恢复。"): selected_item = selected_items[0] record_id = self.tree.item(selected_item, "tags")[0] try: if self.current_category == "文书类": self.cursor.execute("DELETE FROM documents WHERE id = ?", (record_id,)) else: if self.current_infra_view == "总表": # 删除总表时同时删除关联的明细 self.cursor.execute("DELETE FROM infrastructure_summary WHERE id = ?", (record_id,)) self.cursor.execute("DELETE FROM infrastructure_detail WHERE summary_id = ?", (record_id,)) else: self.cursor.execute("DELETE FROM infrastructure_detail WHERE id = ?", (record_id,)) self.conn.commit() self.load_data() messagebox.showinfo("成功", "记录已删除") except Exception as e: messagebox.showerror("错误", f"删除失败:{str(e)}") traceback.print_exc()
if name == “main”:
try:
root = tk.Tk()
app = FileManagementSystem(root)
root.mainloop()
except Exception as e:
messagebox.showerror(“系统错误”, f"程序发生致命错误: {str(e)}")
traceback.print_exc()