基于AI:实现BOM管理、排版
·
主界面介绍:
操作:删除无效物料
合并相同规格物料
一、项目介绍
BOM整理工具是一个基于Python和Tkinter开发的桌面应用程序,专门用于处理电子行业的物料清单(Bill of Materials),提供了一系列功能来简化BOM的整理、分析和导出过程。
二、功能实现、介绍
2.1 核心功能需求列表
- Excel导入导出:支持导入外部Excel文件,导出整理后的Excel文件
- 数据显示:在界面中清晰显示Excel表格内容
- 料号检索:支持搜索"厂家料号"或"Part Number"列
- 空行删除:删除"厂家料号"或"Part Number"列中无值或空的行
- 料号合并:合并相同料号的行,汇总数量和位号
- 序号重排:保持原始顺序的同时更新序号
- 空贴物料删除:删除备注列以"_NC"结尾的行
- BOM排版:统一列名并调整列顺序
2.2 界面与用户体验
- 美观的界面:合理的窗口大小和布局
- 操作详情:显示删除、合并等操作的详细内容
- 导出格式:支持特定的Excel导出格式要求
- 单页显示:导出时确保BOM在一页内显示
三、技术栈
-
Python 核心编程语言 3.6+ -
Tkinter GUI开发 内置 -
pandas 数据处理 1.0+ -
openpyxl Excel操作 3.0+
四、 核心功能实现(代码实例)
4.1 Excel导入功能:
def import_excel(self):
filetypes = [('Excel files', '*.xlsx *.xls'), ('All files', '*.*')]
filename = filedialog.askopenfilename(title="选择Excel文件", filetypes=filetypes)
if not filename:
return
try:
self.df = pd.read_excel(filename)
# 保存原始数据状态
self.original_df = self.df.copy()
self.filename = filename
self.display_data()
self.status_var.set(f"已导入: {os.path.basename(filename)}")
messagebox.showinfo("成功", "Excel文件导入成功!")
except Exception as e:
messagebox.showerror("错误", f"导入失败: {str(e)}")
self.status_var.set("导入失败")
4.2 料号合并功能:
def merge_same_pn(self):
if self.df is None:
messagebox.showinfo("提示", "请先导入Excel文件")
return
# 查找料号列
pn_column = None
for col in self.df.columns:
col_lower = str(col).lower()
if '厂家料号' in str(col) or 'part number' in col_lower or 'pn' in col_lower:
pn_column = col
break
if not pn_column:
messagebox.showinfo("提示", "未找到料号列")
return
# 查找数量列和位号列
qty_column = None
pos_column = None
for col in self.df.columns:
col_lower = str(col).lower()
if '数量' in str(col) or 'qty' in col_lower:
qty_column = col
elif '位号' in str(col) or 'position' in col_lower or 'pos' in col_lower:
pos_column = col
# 记录原始料号的出现顺序
seen_pns = []
for pn in self.df[pn_column]:
if pn not in seen_pns and pd.notna(pn) and str(pn).strip() != '' and str(pn).strip() != 'nan':
seen_pns.append(pn)
# 合并相同料号的行
grouped = self.df.groupby(pn_column)
merged_data = []
merge_details = []
# 按照原始顺序处理料号
for pn in seen_pns:
if pn in grouped.groups:
group = grouped.get_group(pn)
# 只处理需要合并的料号(行数大于1)
if len(group) > 1:
row = group.iloc[0].to_dict()
# 合并数量
if qty_column:
row[qty_column] = group[qty_column].sum()
# 合并位号
if pos_column:
positions = group[pos_column].dropna().astype(str).tolist()
row[pos_column] = ','.join(positions)
merged_data.append(row)
# 保存合并前的每一行数据
merge_details.append((pn, group, len(group),
group[qty_column].sum() if qty_column else 0,
','.join(group[pos_column].dropna().astype(str).tolist()) if pos_column else '',
row[qty_column] if qty_column else 0,
row[pos_column] if pos_column else ''))
else:
# 不需要合并的料号,直接添加
merged_data.append(group.iloc[0].to_dict())
self.df = pd.DataFrame(merged_data)
self.display_data()
self.status_var.set(f"已合并 {len(merged_data)} 个料号")
4.3 空贴物料删除功能:
def delete_nc_materials(self):
if self.df is None:
messagebox.showinfo("提示", "请先导入Excel文件")
return
# 查找备注列
note_column = None
for col in self.df.columns:
col_lower = str(col).lower()
if '备注' in str(col) or 'note' in col_lower:
note_column = col
break
if not note_column:
messagebox.showinfo("提示", "未找到备注列")
return
# 保存原始数据
original_df = self.df.copy()
# 查找备注列最后三个字符为"_NC"的行
nc_rows = []
for i, row in self.df.iterrows():
note_value = row[note_column]
if pd.notna(note_value):
note_str = str(note_value)
if len(note_str) >= 3 and note_str[-3:] == "_NC":
nc_rows.append(i)
# 删除这些行
self.df = self.df.drop(nc_rows)
deleted_rows = len(nc_rows)
self.display_data()
self.status_var.set(f"已删除 {deleted_rows} 个空贴物料")
4.4 BOM排版功能:
def format_bom(self):
if self.df is None:
messagebox.showinfo("提示", "请先导入Excel文件")
return
# 列名映射
column_mappings = {
'数量': '数量',
'QTY': '数量',
'项目': '序号',
'ITEM': '序号',
'参考编号': '位号',
'REF-DES': '位号',
'厂家料号': '厂家料号',
'Part Number': '厂家料号',
'制造商': '制造商',
'Manufacturer': '制造商',
'说明': '说明',
'Description': '说明',
'数值': '备注',
'备注': '备注',
'Value': '备注'
}
# 修改列名
new_columns = []
for col in self.df.columns:
col_lower = str(col).lower()
# 查找映射
mapped = False
for key, value in column_mappings.items():
if key.lower() in col_lower:
new_columns.append(value)
mapped = True
break
if not mapped:
new_columns.append(col)
# 重命名列
self.df.columns = new_columns
# 检查是否有"料号"列
if '料号' not in self.df.columns:
# 新增"料号"列,所有行为空值
self.df['料号'] = ''
# 调整列顺序
desired_order = ['序号', '料号', '说明', '制造商', '数量', '位号', '厂家料号', '备注']
# 确保所有列都存在
for col in desired_order:
if col not in self.df.columns:
self.df[col] = ''
# 重新排列列
self.df = self.df[desired_order]
# 显示数据
self.display_data()
self.status_var.set("BOM排版完成")
4.5 Excel导出功能
def export_excel(self):
if self.df is None:
messagebox.showinfo("提示", "请先导入Excel文件")
return
filetypes = [('Excel files', '*.xlsx'), ('All files', '*.*')]
filename = filedialog.asksaveasfilename(title="保存Excel文件", filetypes=filetypes, defaultextension=".xlsx")
if not filename:
return
try:
# 导出Excel文件
self.df.to_excel(filename, index=False)
# 使用openpyxl进行格式设置
from openpyxl import load_workbook
from openpyxl.styles import Alignment, Border, Side
wb = load_workbook(filename)
ws = wb.active
# 获取列名和列索引的映射
col_name_to_index = {}
for col in range(1, ws.max_column + 1):
col_name = ws.cell(row=1, column=col).value
col_name_to_index[col_name] = col
# 制造商、数量、厂家料号、备注、序号列内容水平居中处理
center_columns = []
for col_name, col_index in col_name_to_index.items():
col_lower = str(col_name).lower()
if any(keyword in col_lower for keyword in ['制造商', 'manufacturer', '数量', 'qty', '厂家料号', 'part number', 'pn', '备注', 'note', '序号', 'serial', 'no']):
center_columns.append(col_index)
# 说明、位号列适当调整宽度,自动换行
wrap_columns = []
for col_name, col_index in col_name_to_index.items():
col_lower = str(col_name).lower()
if any(keyword in col_lower for keyword in ['说明', 'description', '位号', 'position', 'pos']):
wrap_columns.append(col_index)
# 处理所有单元格
for row in range(1, ws.max_row + 1):
for col in range(1, ws.max_column + 1):
cell = ws.cell(row=row, column=col)
# 第一行特殊处理:水平居中+垂直居中
if row == 1:
cell.alignment = Alignment(horizontal='center', vertical='center')
else:
# 所有数据垂直居中
alignment = Alignment(vertical='center')
# 水平居中处理
if col in center_columns:
alignment = Alignment(horizontal='center', vertical='center')
# 自动换行处理
elif col in wrap_columns:
alignment = Alignment(vertical='center', wrap_text=True)
cell.alignment = alignment
# 根据列名设置特定的列宽(使用字符单位)
for col_name, col_index in col_name_to_index.items():
column_letter = ws.cell(row=1, column=col_index).column_letter
col_lower = str(col_name).lower()
if any(keyword in col_lower for keyword in ['位号', 'position', 'pos']):
# 位号的列宽 25字符
ws.column_dimensions[column_letter].width = 25
elif any(keyword in col_lower for keyword in ['厂家料号', 'part number', 'pn']):
# 厂家料号的列宽 21字符
ws.column_dimensions[column_letter].width = 21
elif any(keyword in col_lower for keyword in ['制造商', 'manufacturer']):
# 制造商的列宽 15字符
ws.column_dimensions[column_letter].width = 15
elif any(keyword in col_lower for keyword in ['说明', 'description']):
# 说明的列宽 60字符
ws.column_dimensions[column_letter].width = 60
elif any(keyword in col_lower for keyword in ['数量', 'qty']):
# 数量的列宽 10字符
ws.column_dimensions[column_letter].width = 10
else:
# 其余列的宽度 16字符
ws.column_dimensions[column_letter].width = 16
# 添加全部框线
thin_border = Border(left=Side(style='thin'),
right=Side(style='thin'),
top=Side(style='thin'),
bottom=Side(style='thin'))
# 为有效区域添加框线
for row in range(1, ws.max_row + 1):
for col in range(1, ws.max_column + 1):
cell = ws.cell(row=row, column=col)
cell.border = thin_border
# 设置单页显示
ws.page_setup.orientation = ws.ORIENTATION_LANDSCAPE # 横向
ws.page_setup.fitToWidth = 1 # 宽度适应一页
ws.page_setup.fitToHeight = False # 高度不限制
ws.page_setup.paperSize = ws.PAPERSIZE_A4 # 使用A4纸
# 设置打印区域为有效数据区域
from openpyxl.utils import get_column_letter
max_row = ws.max_row
max_col = ws.max_column
print_area = f'A1:{get_column_letter(max_col)}{max_row}'
ws.print_area = print_area
# 设置缩放比例,确保在一页内显示
ws.sheet_view.zoomScale = 80 # 适当缩小以适应一页
# 保存修改
wb.save(filename)
self.status_var.set(f"已导出: {os.path.basename(filename)}")
messagebox.showinfo("成功", "Excel文件导出成功!")
except Exception as e:
messagebox.showerror("错误", f"导出失败: {str(e)}")
self.status_var.set("导出失败")
五、界面展示
5.1 主界面
- 菜单栏:文件、操作
- 工具栏:导入、导出、删除空行、删除空贴物料、合并相同料号、重新排序号、排版功能
- 搜索框:用于搜索料号
- 数据显示区域:Treeview控件显示Excel数据
- 状态栏:显示操作状态
5.2 操作详情窗口
- 操作类型选择:删除空行、删除空贴物料、合并相同料号
- 预览按钮:显示操作详情
- 导出按钮:导出操作详情
- 数据显示区域:显示详细操作内容
六、总结与展望
6.1 总结
BOM整理工具通过提供一系列自动化功能,大大简化了BOM的整理过程,提高了工作效率。工具支持多种BOM处理需求,包括数据清理、合并、排序和导出等,同时提供了友好的用户界面和详细的操作反馈。
- 功能全面:覆盖了BOM整理的主要需求
- 操作简单:直观的GUI界面
- 灵活定制:支持多种导出格式要求
- 数据安全:保留原始数据状态
6.2 未来展望
- 支持更多Excel格式:扩展对不同版本Excel文件的支持
- 增强分析功能:添加BOM分析、统计等功能
- 批量处理:支持批量处理多个BOM文件
- 系统集成:与其他系统(如ERP、PLM)的集成
- 性能优化:处理更大规模的BOM文件
七、工具价值
- 减少人工操作,提高工作效率
- 确保BOM数据的准确性和一致性
- 标准化BOM格式,便于系统集成
- 降低出错率,减少生产风险
八、总结
BOM整理工具是一个实用、高效的解决方案,为电子行业的BOM管理提供了有力支持。通过不断的功能扩展和优化,工具可以更好地满足用户的需求,提高BOM处理的准确性和效率,为企业的生产和采购决策提供可靠的数据基础。
更多推荐



所有评论(0)