#:一线业务场景里,最耗时间的往往不是"高大上"的算法,而是那些重复的数据搬运:从系统里导出一张表,手工拆字段、填模板、核对、打印。本文分享一个真实落地的方案——用 Python + openpyxl 把车间工单整理工作全自动化,每天节省约3 小时,且零额外成本运行。
我们公司的业务流程是这样的:采购系统(OA)里会不断产生加工打样订单,每条订单包含零件名称、数量、交期、申请人等信息。我的工作是:
DY-2609-2100,年月 + 4 位流水号);纯手工做,一单平均 5~10 分钟,遇到单数较多的时间,一天 20~30 个订单,半天时间就搭进去了。而且手工分配流水号特别容易出错——重号、跳号都出过事故。
这种活的特征是:规则固定、重复度高、但数据源格式不可控(OA 导出的表格偶尔多一列、少一列,日期格式还会变)。这正是 Python 自动化的甜点区。
一开始我也考虑过 pandas,但很快放弃了,原因是:
ws.add_image() 可以直接把本地图片钉到指定单元格。pip install openpyxl 就完事,内网机器也能装。整体架构非常朴素:
```
OA 导出的明细 Excel
│
▼
打样订单整理.py
├─ 读取明细 → 解析/校验字段
├─ 打开模板 → 填充数据 + 插入零件图
├─ 读取单号进度.json → 分配流水号 → 回写进度
├─ 另存为工单 Excel(本地输出目录)
└─ 归档到共享盘 Z:\ + 追加年度总案表(可失败,静默跳过)
│
▼
打印 → 下发车间
```不要用代码"画"表格,直接维护一个 .xlsx 模板文件,业务格式变了改模板就行,代码一行不用动:
```python
from openpyxl import load_workbook
from copy import copy
TEMPLATE = r"E:\AI\模板\订单铣样清单.xlsx"
def build_work_order(rows, out_path):
wb = load_workbook(TEMPLATE)
ws = wb.active
# 填表头字段
ws["B2"] = rows[0]["order_no"] # 订单号
ws["F2"] = rows[0]["owner"] # 负责人
ws["H2"] = rows[0]["date_str"] # 日期
# 填明细行:从模板里的"第一行明细"往下复制样式
start = 6
tpl_row = ws[start]
for i, r in enumerate(rows):
cur = start + i
if cur > start: # 复制上一行样式到新行
for col in range(1, 9):
src, dst = ws.cell(cur-1, col), ws.cell(cur, col)
dst._style = copy(src._style)
ws.cell(cur, 1, i + 1) # 序号
ws.cell(cur, 2, r["part_name"]) # 零件名称
ws.cell(cur, 3, r["qty"]) # 数量
ws.cell(cur, 4, r["deadline"]) # 交期
wb.save(out_path)
```两个细节值得说:
9月3日 这种口语化写法再填入,车间师傅看着舒服,这一步纯属用户体验,但落地时很加分。流水号是最容易出错的地方,解法简单粗暴——用一个小 JSON 文件记录当前进度,每次分配后立即回写:
```python
import json, os
PROGRESS = r"E:\AI\内部单号进度.json"
def next_serial(count=1):
"""批量分配 count 个流水号,原子性回写进度"""
with open(PROGRESS, encoding="utf-8") as f:
prog = json.load(f)
key = time.strftime("%y%m") # 如 "2609"
cur = prog.get(key, 1988) + 1
nums = list(range(cur, cur + count))
prog[key] = cur + count - 1
tmp = PROGRESS + ".tmp" # 先写临时文件再替换,防中途断电写坏
with open(tmp, "w", encoding="utf-8") as f:
json.dump(prog, f, ensure_ascii=False)
os.replace(tmp, PROGRESS)
return nums
```要点有两个:
2609、2610……),跨月自动从起始号重新计数,符合内部单号 DY-{年月}-{流水} 的规则;os.replace(),替换操作是原子的,哪怕程序中途崩了,进度文件也不会写坏——这一招在所有"记录状态"的场景都适用。归档环节要写共享盘 Z:\ 并追加年度总案表。共享盘偶尔掉线/没权限,如果直接写,脚本一崩,前面生成的工单还在但流程中断,最烦人。
我的处理原则是:主产物(本地工单)必须成功,旁路产物(归档)允许失败:
```python
def safe_archive(files):
try:
if not os.path.exists(r"Z:\CNCtudang"):
raise OSError("共享盘不可用")
month_dir = rf"Z:\CNCtudang\订单图档\{time.strftime('%Y.%m')}"
os.makedirs(month_dir, exist_ok=True)
for f in files:
shutil.copy2(f, month_dir)
append_master_table(files) # 追加年度总案表
except OSError as e:
# 归档失败不报错、不中断,只记日志,等盘恢复后补归档
log.warning(f"归档跳过:{e}")
```这是全项目里我认为最"值钱"的一段设计——自动化工具想在一群不懂技术的人手里活下去,就必须比手工操作更不怕出错。宁可降级运行(本地产物照常生成),也不要让用户看到一堆红色报错然后弃用。
零件图没有独立文件,嵌在 OA 导出的旧 Excel 里。openpyxl 读不了嵌入图片,这里用了个冷门但好用的操作——xlsx 本质是 zip 包,xl/media/ 目录下就是所有嵌入图片:
```python
import zipfile, shutil
def extract_images(xlsx_path, out_dir):
os.makedirs(out_dir, exist_ok=True)
paths = []
with zipfile.ZipFile(xlsx_path) as z:
for name in z.namelist():
if name.startswith("xl/media/"):
dst = os.path.join(out_dir, os.path.basename(name))
with z.open(name) as src, open(dst, "wb") as f:
shutil.copyfileobj(src, f)
paths.append(dst)
return paths
```拿到图片路径后,用 openpyxl.drawing.image.Image 加上 ws.add_image(img, "B8") 钉进工单即可。注意 add_image 需要 Pillow 支持(pip install pillow),且锚点单元格要提前留好行高。
最后一步,让不会 Python 的同事也能用。把脚本做成免安装启动器:
```bat
@echo off
chcp 65001 >nul
cd /d "%~dp0"
"C:\Python313\python.exe" "打样订单整理.py" %*
pause
```双击 bat → 弹出交互提示 → 选订单文件 → 自动出工单。没有环境变量、没有命令行、没有打包 exe 的体积和杀软误报问题。源码即程序,改需求时直接改 .py 文件,bat 永远不用动。
指标 | 手工 | 自动化后 |
|---|---|---|
单张工单耗时 | 5~10 分钟 | 约 3 秒 |
30个订单整单耗时 | 约 3小时 | 约 10 分钟(含打印) |
流水号错误 | 偶发重号/跳号 | 0(JSON 进度保障) |
归档遗漏 | 忘记归档时有发生 | 自动执行,盘故障时降级跳过 |
更重要的是稳定性:上线一个多月,处理了几百条订单记录,期间经历了共享盘掉线、OA 导出格式微调、跨月重置流水号,脚本都平稳扛过来了。
这类"表格搬运"自动化没有技术门槛,唯一的门槛是愿不愿意花一个下午把第一版写出来。希望这个案例能给同样被重复劳动困住的朋友一个起点——如果你手上也有一张每天都要手工整理的表,今天就可以动手了。
环境:Windows 11 + Python 3.13 + openpyxl 3.1 + Pillow。文中代码均可直接复用,欢迎交流。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。