实验室耗材管理平台
一、输入员工基本信息。
二、预览、提交申请,自动生成申请记录。
三、在records文件中累计申请记录,便于统计耗材消耗情况,安排预算。
实验室耗材申请单
软件关键代码:
def setup_application_tab(self):
layout = QVBoxLayout()
# 标题
title_label = QLabel("实验室耗材管理平台")
title_label.setFont(QFont("Arial", 16, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
layout.addWidget(title_label)
# 申请人信息
info_layout = QVBoxLayout()
# 姓名
name_layout = QHBoxLayout()
name_label = QLabel("姓 名:")
name_label.setFixedWidth(80)
self.name_input = QLineEdit()
self.name_input.setPlaceholderText("请输入申请人姓名")
name_layout.addWidget(name_label)
name_layout.addWidget(self.name_input)
info_layout.addLayout(name_layout)
# 部门
dept_layout = QHBoxLayout()
dept_label = QLabel("部 门:")
dept_label.setFixedWidth(80)
self.dept_input = QLineEdit()
self.dept_input.setPlaceholderText("请输入所在部门")
dept_layout.addWidget(dept_label)
dept_layout.addWidget(self.dept_input)
info_layout.addLayout(dept_layout)
layout.addLayout(info_layout)
# 耗材选择
material_layout = QVBoxLayout()
material_title = QLabel("耗材选择:")
material_title.setFont(QFont("Arial", 12, QFont.Bold))
material_layout.addWidget(material_title)
# 耗材类型
type_layout = QHBoxLayout()
type_label = QLabel("耗材类型:")
type_label.setFixedWidth(80)
self.material_combo = QComboBox()
self.materials = ["实验服", "**", "**", "**", "**", "**", "**"]
self.material_combo.addItems(self.materials)
type_layout.addWidget(type_label)
type_layout.addWidget(self.material_combo)
material_layout.addLayout(type_layout)
# 数量
quantity_layout = QHBoxLayout()
quantity_label = QLabel("数 量:")
quantity_label.setFixedWidth(80)
self.quantity_spin = QSpinBox()
self.quantity_spin.setRange(1, 100)
self.quantity_spin.setValue(1)
quantity_layout.addWidget(quantity_label)
quantity_layout.addWidget(self.quantity_spin)
material_layout.addLayout(quantity_layout)
layout.addLayout(material_layout)
# 按钮
button_layout = QHBoxLayout()
self.preview_btn = QPushButton("预览申请")
self.preview_btn.clicked.connect(self.preview_application)
self.submit_btn = QPushButton("提交申请")
self.submit_btn.clicked.connect(self.submit_application)
self.clear_btn = QPushButton("清空表单")
self.clear_btn.clicked.connect(self.clear_form)
button_layout.addWidget(self.preview_btn)
button_layout.addWidget(self.submit_btn)
button_layout.addWidget(self.clear_btn)
layout.addLayout(button_layout)
# 预览区域
preview_label = QLabel("申请预览:")
preview_label.setFont(QFont("Arial", 12, QFont.Bold))
layout.addWidget(preview_label)
self.preview_text = QTextEdit()
self.preview_text.setReadOnly(True)
layout.addWidget(self.preview_text)
self.application_tab.setLayout(layout)
def setup_records_tab(self):
layout = QVBoxLayout()
# 标题
title_label = QLabel("申请记录")
title_label.setFont(QFont("Arial", 16, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
layout.addWidget(title_label)
# 记录表格
self.records_table = QTableWidget()
self.records_table.setColumnCount(5)
self.records_table.setHorizontalHeaderLabels(["申请时间", "姓名", "部门", "耗材类型", "数量"])
self.records_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
layout.addWidget(self.records_table)
# 按钮布局
button_layout = QHBoxLayout()
refresh_btn = QPushButton("刷新记录")
refresh_btn.clicked.connect(self.refresh_records)
export_btn = QPushButton("导出为Excel")
export_btn.clicked.connect(self.export_to_excel)
button_layout.addWidget(refresh_btn)
button_layout.addWidget(export_btn)
layout.addLayout(button_layout)
self.records_tab.setLayout(layout)
def setup_statistics_tab(self):
layout = QVBoxLayout()
# 标题
title_label = QLabel("统计信息")
title_label.setFont(QFont("Arial", 16, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
layout.addWidget(title_label)
# 统计显示
self.stats_text = QTextEdit()
self.stats_text.setReadOnly(True)
layout.addWidget(self.stats_text)
# 刷新按钮
refresh_btn = QPushButton("刷新统计")
refresh_btn.clicked.connect(self.refresh_statistics)
layout.addWidget(refresh_btn)
self.statistics_tab.setLayout(layout)
def preview_application(self):
"""预览申请内容"""
name = self.name_input.text().strip()
dept = self.dept_input.text().strip()
material = self.material_combo.currentText()
quantity = self.quantity_spin.value()
if not name or not dept:
QMessageBox.warning(self, "输入错误", "请填写姓名和部门信息!")
return
preview_content = f"""
===== 实验室耗材申请单 =====
申请人信息:
姓 名:{name}
部 门:{dept}
申请耗材:
耗材类型:{material}
数 量:{quantity}
申请时间:{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
============================
"""
self.preview_text.setText(preview_content)
def submit_application(self):
"""提交申请"""
name = self.name_input.text().strip()
dept = self.dept_input.text().strip()
material = self.material_combo.currentText()
quantity = self.quantity_spin.value()
if not name or not dept:
QMessageBox.warning(self, "输入错误", "请填写姓名和部门信息!")
return
# 创建记录
record = {
'timestamp': datetime.now(),
'name': name,
'department': dept,
'material': material,
'quantity': quantity
}
self.records.append(record)
# 保存到文件
self.save_record(record)
# 显示成功消息
QMessageBox.information(self, "申请成功", "耗材申请已提交成功!")
# 清空表单
self.clear_form()
# 刷新记录和统计
self.refresh_records()
self.refresh_statistics()
def clear_form(self):
"""清空表单"""
self.name_input.clear()
self.dept_input.clear()
self.material_combo.setCurrentIndex(0)
self.quantity_spin.setValue(1)
self.preview_text.clear()
def refresh_records(self):
"""刷新记录表格"""
self.records_table.setRowCount(len(self.records))
for row, record in enumerate(self.records):
self.records_table.setItem(row, 0, QTableWidgetItem(record['timestamp'].strftime("%Y-%m-%d %H:%M")))
self.records_table.setItem(row, 1, QTableWidgetItem(record['name']))
self.records_table.setItem(row, 2, QTableWidgetItem(record['department']))
self.records_table.setItem(row, 3, QTableWidgetItem(record['material']))
self.records_table.setItem(row, 4, QTableWidgetItem(str(record['quantity'])))
def refresh_statistics(self):
"""刷新统计信息"""
if not self.records:
self.stats_text.setText("暂无申请记录")
return
# 使用pandas进行统计分析
df = pd.DataFrame(self.records)
# 按人员统计
person_stats = df.groupby('name').agg({
'quantity': 'sum',
'material': 'count'
}).rename(columns={'quantity': '总数量', 'material': '申请次数'})
# 按耗材类型统计
material_stats = df.groupby('material')['quantity'].sum()
# 按部门统计
dept_stats = df.groupby('department')['quantity'].sum()
stats_text = "===== 统计信息汇总 =====\n\n"
stats_text += "1. 按人员统计:\n"
stats_text += person_stats.to_string() + "\n\n"
stats_text += "2. 按耗材类型统计:\n"
stats_text += material_stats.to_string() + "\n\n"
stats_text += "3. 按部门统计:\n"
stats_text += dept_stats.to_string() + "\n\n"
stats_text += f"总申请次数:{len(self.records)}\n"
stats_text += f"总耗材数量:{df['quantity'].sum()}\n"
self.stats_text.setText(stats_text)
def save_record(self, record):
"""保存记录到CSV文件(解决中文乱码问题)"""
filename = "material_records.csv"
# 如果文件不存在,创建文件并写入UTF-8 BOM表头
if not os.path.exists(filename):
with codecs.open(filename, 'w', encoding='utf-8-sig') as f:
f.write("时间,姓名,部门,耗材类型,数量\n")
# 追加记录(使用utf-8-sig编码解决Excel中文乱码问题)
with codecs.open(filename, 'a', encoding='utf-8-sig') as f:
f.write(f"{record['timestamp'].strftime('%Y-%m-%d %H:%M:%S')},"
f"{record['name']},{record['department']},"
f"{record['material']},{record['quantity']}\n")
def load_existing_records(self):
"""加载已有的记录(支持多种编码尝试)"""
filename = "material_records.csv"
if os.path.exists(filename):
try:
# 尝试多种编码方式读取
encodings = ['utf-8-sig', 'gbk', 'utf-8', 'latin-1']
for encoding in encodings:
try:
with codecs.open(filename, 'r', encoding=encoding) as f:
lines = f.readlines()
# 跳过表头
for line in lines[1:]:
parts = line.strip().split(',')
if len(parts) == 5:
record = {
'timestamp': datetime.strptime(parts[0], '%Y-%m-%d %H:%M:%S'),
'name': parts[1],
'department': parts[2],
'material': parts[3],
'quantity': int(parts[4])
}
self.records.append(record)
print(f"成功使用 {encoding} 编码加载记录")
break
except UnicodeDecodeError:
continue
except Exception as e:
print(f"使用 {encoding} 编码加载失败: {e}")
continue
except Exception as e:
print(f"加载记录时出错: {e}")
QMessageBox.warning(self, "加载错误", f"加载历史记录时出错: {e}")
def export_to_excel(self):
"""导出为Excel文件(解决中文乱码问题)"""
if not self.records:
QMessageBox.information(self, "导出提示", "没有记录可以导出!")
return
try:
# 创建DataFrame
df = pd.DataFrame(self.records)
# 重命名列名为中文
df = df.rename(columns={
'timestamp': '申请时间',
'name': '姓名',
'department': '部门',
'material': '耗材类型',
'quantity': '数量'
})
# 格式化时间列
df['申请时间'] = df['申请时间'].apply(lambda x: x.strftime("%Y-%m-%d %H:%M:%S"))
# 导出为Excel
excel_filename = f"耗材申请记录_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx"
df.to_excel(excel_filename, index=False, engine='openpyxl')
QMessageBox.information(self, "导出成功", f"记录已成功导出为: {excel_filename}")
except Exception as e:
QMessageBox.critical(self, "导出错误", f"导出Excel文件时出错: {e}")