210 lines
8.7 KiB
Python
210 lines
8.7 KiB
Python
|
|
import tkinter as tk
|
||
|
|
from tkinter import ttk, messagebox, filedialog
|
||
|
|
import pandas as pd
|
||
|
|
|
||
|
|
class KeywordDialog:
|
||
|
|
def __init__(self, parent, keyword_manager):
|
||
|
|
self.dialog = tk.Toplevel(parent)
|
||
|
|
self.dialog.title("关键词管理")
|
||
|
|
self.dialog.geometry("800x600")
|
||
|
|
self.keyword_manager = keyword_manager
|
||
|
|
|
||
|
|
# 创建选项卡
|
||
|
|
self.notebook = ttk.Notebook(self.dialog)
|
||
|
|
self.exact_frame = ttk.Frame(self.notebook)
|
||
|
|
self.fuzzy_frame = ttk.Frame(self.notebook)
|
||
|
|
self.notebook.add(self.exact_frame, text="精准匹配")
|
||
|
|
self.notebook.add(self.fuzzy_frame, text="模糊匹配")
|
||
|
|
self.notebook.pack(expand=True, fill="both")
|
||
|
|
|
||
|
|
# 创建精准匹配界面
|
||
|
|
self.create_keyword_frame(self.exact_frame, False)
|
||
|
|
# 创建模糊匹配界面
|
||
|
|
self.create_keyword_frame(self.fuzzy_frame, True)
|
||
|
|
|
||
|
|
# 在每个标签页添加批量导入按钮
|
||
|
|
self.create_import_buttons(self.exact_frame, False)
|
||
|
|
self.create_import_buttons(self.fuzzy_frame, True)
|
||
|
|
|
||
|
|
def create_keyword_frame(self, frame, is_fuzzy):
|
||
|
|
# 输入区域
|
||
|
|
input_frame = ttk.LabelFrame(frame, text="添加关键词", padding=5)
|
||
|
|
input_frame.pack(fill="x", padx=5, pady=5)
|
||
|
|
|
||
|
|
ttk.Label(input_frame, text="关键词:").grid(row=0, column=0, padx=5)
|
||
|
|
keyword_entry = ttk.Entry(input_frame, width=30)
|
||
|
|
keyword_entry.grid(row=0, column=1, padx=5)
|
||
|
|
|
||
|
|
ttk.Label(input_frame, text="类型:").grid(row=0, column=2, padx=5)
|
||
|
|
type_entry = ttk.Entry(input_frame, width=20)
|
||
|
|
type_entry.grid(row=0, column=3, padx=5)
|
||
|
|
|
||
|
|
def add_keyword():
|
||
|
|
keyword = keyword_entry.get().strip()
|
||
|
|
type_name = type_entry.get().strip()
|
||
|
|
if keyword and type_name:
|
||
|
|
self.keyword_manager.add_keyword(keyword, type_name, is_fuzzy)
|
||
|
|
keyword_entry.delete(0, tk.END)
|
||
|
|
type_entry.delete(0, tk.END)
|
||
|
|
refresh_list()
|
||
|
|
else:
|
||
|
|
messagebox.showwarning("警告", "关键词和类型不能为空!")
|
||
|
|
|
||
|
|
ttk.Button(input_frame, text="添加", command=add_keyword).grid(row=0, column=4, padx=5)
|
||
|
|
|
||
|
|
# 列表区域
|
||
|
|
list_frame = ttk.Frame(frame)
|
||
|
|
list_frame.pack(fill="both", expand=True, padx=5, pady=5)
|
||
|
|
|
||
|
|
columns = ("关键词", "类型")
|
||
|
|
tree = ttk.Treeview(list_frame, columns=columns, show="headings")
|
||
|
|
for col in columns:
|
||
|
|
tree.heading(col, text=col)
|
||
|
|
tree.column(col, width=100)
|
||
|
|
|
||
|
|
scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=tree.yview)
|
||
|
|
tree.configure(yscrollcommand=scrollbar.set)
|
||
|
|
|
||
|
|
tree.pack(side="left", fill="both", expand=True)
|
||
|
|
scrollbar.pack(side="right", fill="y")
|
||
|
|
|
||
|
|
def refresh_list():
|
||
|
|
tree.delete(*tree.get_children())
|
||
|
|
keywords = self.keyword_manager.fuzzy_keywords if is_fuzzy else self.keyword_manager.exact_keywords
|
||
|
|
for keyword, type_name in keywords.items():
|
||
|
|
tree.insert("", "end", values=(keyword, type_name))
|
||
|
|
|
||
|
|
def remove_selected():
|
||
|
|
selected = tree.selection()
|
||
|
|
if selected:
|
||
|
|
item = tree.item(selected[0])
|
||
|
|
keyword = item['values'][0]
|
||
|
|
self.keyword_manager.remove_keyword(keyword, is_fuzzy)
|
||
|
|
refresh_list()
|
||
|
|
|
||
|
|
ttk.Button(frame, text="删除选中", command=remove_selected).pack(pady=5)
|
||
|
|
|
||
|
|
refresh_list()
|
||
|
|
|
||
|
|
def create_import_buttons(self, frame, is_fuzzy):
|
||
|
|
# 创建按钮框架并居中
|
||
|
|
import_frame = ttk.Frame(frame)
|
||
|
|
import_frame.pack(fill="x", padx=5, pady=10)
|
||
|
|
|
||
|
|
# 创建一个子框架来容纳按钮,并使其居中
|
||
|
|
button_frame = ttk.Frame(import_frame)
|
||
|
|
button_frame.pack(anchor="center")
|
||
|
|
|
||
|
|
# 导入按钮 - 设置宽度和高度
|
||
|
|
ttk.Button(button_frame, text="导入Excel", width=15, padding=(5, 8),
|
||
|
|
command=lambda: self.import_from_excel(is_fuzzy)).pack(side="left", padx=10)
|
||
|
|
|
||
|
|
# 导出按钮 - 设置宽度和高度
|
||
|
|
ttk.Button(button_frame, text="导出Excel", width=15, padding=(5, 8),
|
||
|
|
command=lambda: self.export_to_excel(is_fuzzy)).pack(side="left", padx=10)
|
||
|
|
|
||
|
|
def import_from_excel(self, is_fuzzy):
|
||
|
|
filename = filedialog.askopenfilename(
|
||
|
|
title="选择Excel文件",
|
||
|
|
filetypes=[
|
||
|
|
("Excel文件", "*.xlsx *.xls"),
|
||
|
|
("所有文件", "*.*")
|
||
|
|
]
|
||
|
|
)
|
||
|
|
if not filename:
|
||
|
|
return
|
||
|
|
|
||
|
|
try:
|
||
|
|
df = pd.read_excel(filename)
|
||
|
|
|
||
|
|
# 检查必要的列
|
||
|
|
required_columns = ['关键词', '类型']
|
||
|
|
if not all(col in df.columns for col in required_columns):
|
||
|
|
messagebox.showerror("错误", "Excel文件必须包含'关键词'和'类型'列!")
|
||
|
|
return
|
||
|
|
|
||
|
|
# 准备导入数据
|
||
|
|
keywords_data = list(zip(df['关键词'], df['类型']))
|
||
|
|
|
||
|
|
# 创建导入选项对话框
|
||
|
|
option_dialog = tk.Toplevel(self.dialog)
|
||
|
|
option_dialog.title("导入选项")
|
||
|
|
option_dialog.geometry("300x150")
|
||
|
|
|
||
|
|
overwrite_var = tk.BooleanVar(value=True)
|
||
|
|
ttk.Checkbutton(option_dialog, text="覆盖已存在的关键词",
|
||
|
|
variable=overwrite_var).pack(pady=10)
|
||
|
|
|
||
|
|
def do_import():
|
||
|
|
success_count, skip_count, errors = self.keyword_manager.batch_import(
|
||
|
|
keywords_data, is_fuzzy, overwrite_var.get()
|
||
|
|
)
|
||
|
|
|
||
|
|
result_msg = f"成功导入: {success_count}\n跳过: {skip_count}"
|
||
|
|
if errors:
|
||
|
|
result_msg += f"\n\n错误信息:\n" + "\n".join(errors)
|
||
|
|
|
||
|
|
messagebox.showinfo("导入结果", result_msg)
|
||
|
|
option_dialog.destroy()
|
||
|
|
|
||
|
|
# 刷新显示
|
||
|
|
for frame in [self.exact_frame, self.fuzzy_frame]:
|
||
|
|
for child in frame.winfo_children():
|
||
|
|
if isinstance(child, ttk.Frame):
|
||
|
|
for widget in child.winfo_children():
|
||
|
|
if isinstance(widget, ttk.Treeview):
|
||
|
|
self.refresh_list(widget, frame == self.fuzzy_frame)
|
||
|
|
|
||
|
|
ttk.Button(option_dialog, text="开始导入",
|
||
|
|
command=do_import).pack(pady=10)
|
||
|
|
ttk.Button(option_dialog, text="取消",
|
||
|
|
command=option_dialog.destroy).pack(pady=5)
|
||
|
|
|
||
|
|
# 使对话框模态
|
||
|
|
option_dialog.transient(self.dialog)
|
||
|
|
option_dialog.grab_set()
|
||
|
|
self.dialog.wait_window(option_dialog)
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
messagebox.showerror("错误", f"导入过程中出错:\n{str(e)}")
|
||
|
|
|
||
|
|
def export_to_excel(self, is_fuzzy):
|
||
|
|
try:
|
||
|
|
# 获取要导出的关键词库
|
||
|
|
keywords = self.keyword_manager.fuzzy_keywords if is_fuzzy else self.keyword_manager.exact_keywords
|
||
|
|
|
||
|
|
# 检查关键词库是否为空
|
||
|
|
if not keywords:
|
||
|
|
messagebox.showwarning("警告", "关键词库为空,无法导出!")
|
||
|
|
return
|
||
|
|
|
||
|
|
# 创建DataFrame
|
||
|
|
df = pd.DataFrame([
|
||
|
|
{'关键词': keyword, '类型': type_name}
|
||
|
|
for keyword, type_name in keywords.items()
|
||
|
|
])
|
||
|
|
|
||
|
|
# 让用户选择保存位置
|
||
|
|
filename = filedialog.asksaveasfilename(
|
||
|
|
title="保存Excel文件",
|
||
|
|
defaultextension=".xlsx",
|
||
|
|
filetypes=[
|
||
|
|
("Excel文件", "*.xlsx"),
|
||
|
|
("所有文件", "*.*")
|
||
|
|
]
|
||
|
|
)
|
||
|
|
|
||
|
|
if filename:
|
||
|
|
# 导出到Excel
|
||
|
|
df.to_excel(filename, index=False)
|
||
|
|
messagebox.showinfo("成功", f"关键词库已导出到:\n{filename}")
|
||
|
|
|
||
|
|
except Exception as e:
|
||
|
|
messagebox.showerror("错误", f"导出过程中出错:\n{str(e)}")
|
||
|
|
|
||
|
|
def refresh_list(self, tree, is_fuzzy):
|
||
|
|
"""刷新指定树形视图的显示"""
|
||
|
|
tree.delete(*tree.get_children())
|
||
|
|
keywords = self.keyword_manager.fuzzy_keywords if is_fuzzy else self.keyword_manager.exact_keywords
|
||
|
|
for keyword, type_name in keywords.items():
|
||
|
|
tree.insert("", "end", values=(keyword, type_name))
|