class ExcelImporter(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Excel 导入 MySQL 工具")
self.resize(600, 400) # 增加窗口高度以容纳新控件
self.last_created_excel = None # 记录最后创建的Excel文件路径
self.templates = {
"现病史": ["表现症状","问诊要点", "首拼"],
"辩证治法": ["中医辩证","中医治法", "辩证首拼","代表方药"],
"临床诊断": ["临床诊断", "首拼"],
"验方": ["类型","病名", "证候","方名","方药","用法","功效"],
"古方": ["来源", "方名", "方药", "用法", "功效", "注意"],
"经方": ["类型", "方名","功效","组成","用法","价格"],
"单方":["类型","功效","组成","用法"],
"食疗方": ["类型", "方名", "功效", "组成", "用法"],
"膳食方": ["类型", "方名", "功效", "组成", "用法"],
"医嘱建议": ["医嘱建议"]
}
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
# 模板选择区域
layout.addWidget(QLabel("选择模板:"))
template_layout = QHBoxLayout()
self.template_combo = QComboBox()
self.template_combo.addItems(self.templates.keys())
template_layout.addWidget(self.template_combo)
self.create_button = QPushButton("创建Excel")
self.create_button.clicked.connect(self.create_excel_template)
template_layout.addWidget(self.create_button)
self.complete_button = QPushButton("我已编辑完成")
self.complete_button.clicked.connect(self.on_complete_clicked)
self.complete_button.setEnabled(False) # 初始禁用
template_layout.addWidget(self.complete_button)
layout.addLayout(template_layout)
# 文件路径输入框
layout.addWidget(QLabel("选择 Excel 文件:"))
self.file_path_edit = QLineEdit()
self.browse_button = QPushButton("浏览")
self.browse_button.clicked.connect(self.select_file)
file_layout = QHBoxLayout()
file_layout.addWidget(self.file_path_edit)
file_layout.addWidget(self.browse_button)
layout.addLayout(file_layout)
# 表名输入框
layout.addWidget(QLabel("目标数据库表名:"))
self.table_name_edit = QLineEdit()
layout.addWidget(self.table_name_edit)
# 导入按钮
self.import_button = QPushButton("导入数据库")
self.import_button.clicked.connect(self.import_to_database)
layout.addWidget(self.import_button)
self.setLayout(layout)
def create_excel_template(self):
"""创建Excel模板并打开"""
try:
# 获取选中的模板名称
template_name = self.template_combo.currentText()
# 创建临时Excel文件
with tempfile.NamedTemporaryFile(suffix='.xlsx', delete=False) as tmp:
file_path = tmp.name
self.last_created_excel = file_path
# 创建DataFrame并写入列标题
headers = self.templates[template_name]
df = pd.DataFrame(columns=headers)
df.to_excel(self.last_created_excel, index=False)
# 使用Excel 2013打开文件
excel = win32.gencache.EnsureDispatch('Excel.Application')
excel.Visible = True
workbook = excel.Workbooks.Open(os.path.abspath(self.last_created_excel))
worksheet = workbook.Sheets(1) # 获取第一个工作表
# 设置所有列宽为30
worksheet.Columns.ColumnWidth = 30
# 设置所有行高为25
worksheet.Rows.RowHeight = 25
# 设置自动换行
worksheet.Cells.WrapText = True
# 获取标题行的列数
num_cols = len(headers)
# 定义区域:从第一行到最后一行,列数为标题行的列数
start_cell = worksheet.Cells(1, 1) # 第一行第一列
end_cell = worksheet.Cells(worksheet.Rows.Count, num_cols) # 最后一行最后一列
table_range = worksheet.Range(start_cell, end_cell)
# 设置边框样式
border_style = win32.constants.xlContinuous
border_weight = win32.constants.xlThick # 加粗边框
black_color = 0x000000 # 黑色边框(Excel使用BGR格式)
borders = table_range.Borders
# 设置所有边框
for line in [
win32.constants.xlEdgeLeft,
win32.constants.xlEdgeTop,
win32.constants.xlEdgeBottom,
win32.constants.xlEdgeRight,
win32.constants.xlInsideVertical,
win32.constants.xlInsideHorizontal,
]:
border = borders.Item(line)
border.LineStyle = border_style
border.Color = black_color
border.Weight = border_weight # 设置为加粗
# 启用"我已编辑完成"按钮
self.complete_button.setEnabled(True)
QMessageBox.information(self, "成功", f"Excel模板已创建,请编辑后点击'我已编辑完成'")
except Exception as e:
QMessageBox.critical(self, "错误", f"创建Excel失败: {str(e)}")
def generate_sp(self, s):
"""生成拼音首字母,全部小写"""
if not isinstance(s, str) or not s.strip():
return ""
# 处理中文字符串
if any('\u4e00' <= char <= '\u9fff' for char in s):
# 获取拼音首字母,转为小写
initials = pypinyin.lazy_pinyin(s, style=pypinyin.Style.FIRST_LETTER)
return ''.join(initials).lower()
else:
# 处理非中文(英文)名称
words = s.split()
if not words:
return ""
# 取每个单词的首字母,转为小写
return ''.join(word[0].lower() for word in words if word)
def on_complete_clicked(self):
"""处理编辑完成按钮点击事件,生成首拼列"""
if not self.last_created_excel or not os.path.exists(self.last_created_excel):
QMessageBox.warning(self, "警告", "未找到创建的Excel文件")
return
try:
# 读取Excel文件
df = pd.read_excel(self.last_created_excel)
# 获取模板类型
template_name = self.template_combo.currentText()
# 定义需要生成首拼的模板类型
templates_with_shoupin = ["现病史", "辩证治法", "临床诊断"]
# 如果当前模板不需要生成首拼,跳过生成首拼的逻辑
if template_name in templates_with_shoupin:
# 确定源列名
if template_name == "现病史":
source_col = "表现症状"
elif template_name == "辩证治法":
source_col = "中医辩证"
elif template_name == "临床诊断":
source_col = "临床诊断"
# 检查源列是否存在
if source_col not in df.columns:
QMessageBox.critical(self, "错误", f"Excel文件中缺少'{source_col}'列")
return
# 处理空值
df[source_col] = df[source_col].fillna('')
# 仅在对应的源列生成首拼
df['首拼'] = df[source_col].apply(self.generate_sp)
# 保存回Excel文件
df.to_excel(self.last_created_excel, index=False)
# 提示用户
QMessageBox.information(self, "成功", "首拼已自动生成并填充!")
else:
# 如果不需要生成首拼,可以在这里添加其他逻辑(可选)
pass # 当前不做任何处理
# 设置文件路径和表名(这部分无论是否生成首拼都执行)
self.file_path_edit.setText(self.last_created_excel)
self.table_name_edit.setText(template_name)
self.complete_button.setEnabled(False) # 重置按钮状态
except Exception as e:
QMessageBox.critical(self, "错误", f"操作失败: {str(e)}")
def select_file(self):
file_path, _ = QFileDialog.getOpenFileName(self, "选择 Excel 文件", "", "Excel 文件 (*.xlsx *.xls)")
if file_path:
self.file_path_edit.setText(file_path)
def import_to_database(self):
file_path = self.file_path_edit.text()
table_name = self.table_name_edit.text()
if not file_path:
QMessageBox.critical(self, "错误", "请选择一个 Excel 文件")
return
if not table_name:
QMessageBox.critical(self, "错误", "请输入目标数据库表名")
return
try:
with POOL.connection() as conn:
with conn.cursor() as cursor:
df = pd.read_excel(file_path)
if df.empty:
QMessageBox.critical(self, "错误", "Excel 文件为空")
return
# 替换所有 NaN、inf、-inf 为 None
df.replace([np.nan, np.inf, -np.inf], None, inplace=True)
# 构建插入语句
if not table_name.isidentifier():
raise ValueError("表名包含非法字符")
columns = ', '.join(df.columns.tolist())
placeholders = ', '.join(['%s'] * len(df.columns))
insert_sql = f"INSERT INTO `{table_name}` ({columns}) VALUES ({placeholders})"
# 转换为元组列表
data = [tuple(row) for _, row in df.iterrows()]
# 批量插入
cursor.executemany(insert_sql, data)
conn.commit()
QMessageBox.information(self, "成功", f"{cursor.rowcount} 条记录已成功导入到表 '{table_name}'")
except Exception as e:
try:
conn.rollback()
except:
pass
QMessageBox.critical(self, "错误", f"导入失败: {str(e)}") 我想再加一个按钮,能够导入sql文件到mysql数据库,我已经在sql文件指定了要存的位置