数据 (定位销/勾销缸/翻转缸/电缸 → Univer 真实数模)
- 新增 19 系列 1124 型号 (PIN 303 / HOK 73 / ROT 741 / ELEC 9)
- 命名规则取自官方图册 CODIFICATION KEY (pdftotext 提取), 非推测
- 解析用「官方值域校验 + 左对齐 DFS 填空」, 可处理省略空位的型号
- 参数组合唯一性门禁: 1124 型号全部通过 (避免选型静默错配)
- 占位/测试文件 (如 USP50J_0___K0 销径为空) 在解析阶段丢弃
- catalog.json 分类系列表同步; crossref 失效引用清理
手册页
- 全部 42 系列改为彩色 (此前脚本误写死 csGRAY 转灰度), 346 页
- 修复 UCBT 附图只有 1 页 (筛选条件写死 UCBT40 且漏 CLAMPING ARMS)
- gen-pending-series.py 改为扫描 manual 目录自动生成附件清单,
避免重跑脚本把多页附件覆盖回单页
网页版
- 首页改为系列缩略图网格 (40 张: 27 张真实产品图 + 13 张占位图),
按大类分组; 图放 web/series/<系列码>.webp, 覆盖同名文件即可替换
- 左侧树改手风琴 (默认收起, 一次展开一个), 父级带 SVG 图标,
悬停放大动画, 按钮间距随高度均匀分布; 可收起为图标窄条
- 修复分隔条被拖出容器后无法找回 (上限改为容器感知 + resize 重夹取
+ 双击复位); 同时阻止图片原生拖拽
- 购物车打包改取 .step.gz 副档 (传输量降至约 1/4.5), 无副档自动回退
- 修复搜索到型号后点结果内容区空白 (switchTab('dim') 已失效)
- OpcPackage 超大包 (>1.5GB) 改走临时文件, 绕过 MemoryStream 2GB 上限
工具
- gen-pending-series/manual, copy-pending-step, gen-step-gz,
gen-series-thumbs, scan-pending-series 等 11 个脚本
Co-Authored-By: Claude Code <noreply@anthropic.com>
133 lines
5.3 KiB
Python
133 lines
5.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
为夹紧缸 11 个系列生成附图(多页尺寸图 + 裁剪版数据表 PDF)。
|
||
来源:Univer 官方图册 PDF(X 盘)。
|
||
用法: PYTHONUTF8=1 python gen-clamp-manual.py [--clean]
|
||
--clean 先清空各系列 manual 目录再生成(避免旧页残留)
|
||
输出: manual/<系列>/p<NN>.png + <系列>_manual.pdf(裁成该系列的页)
|
||
"""
|
||
import fitz, os, shutil, sys
|
||
|
||
SRC = r'X:/新开发产品-Research and Development/2_产品资料/Univer资料/官方图册'
|
||
DST = r'D:/开发/OnebotCatalog/onebot-data/catalog/manual'
|
||
DPI = 110
|
||
CLEAN = '--clean' in sys.argv
|
||
MAIN_CATALOG = 'katalog-pneumatische-spanner-univer-13032019-en.pdf'
|
||
|
||
# 系列 -> 官方 PDF 列表(多缸径系列合并成一个系列的图,按缸径顺序)
|
||
SERIES_PDFS = {
|
||
'UCBP': ['ucbp25cten_en380', 'ucbp40en_en382', 'ucbp50cten_en391', 'ucbp63cten_en401', 'ucbp80cten_en392'],
|
||
'UCBM': ['ucbm32cten_en432', 'ucbm50cten_en394', 'ucbm63cten_en395', 'ucbm80cten_en414'],
|
||
'UCBH': ['ucbh63cten_en393'],
|
||
'UCBQ': ['ucbq63cten_en397'],
|
||
'UCDP': ['ucdp40cten_en417', 'ucdp63cten_en418'],
|
||
'UCIM': ['ucim40cten_en415'],
|
||
'UCIP': ['ucip40cten_en402'],
|
||
'UCNM': ['ucnm50cten_en387', 'ucnm63cten_en389', 'ucnm80cten_en429'],
|
||
'UCNP': ['ucnp50cten_en385', 'ucnp63cten_en403', 'ucnp80cten_en388'],
|
||
# UFL450/UHL463 实为官方 UCBL(Manual power clamps Ø50/Ø63)
|
||
'UFL': ['ucbl450cten_en398', 'ucbl463cten_en478'],
|
||
}
|
||
UCBT_FROM_MAIN = True # UCBT 无独立图册,从主目录提取
|
||
|
||
|
||
def classify(page):
|
||
"""按内容标记归类页面: char(特性) / dim(尺寸) / arm(夹臂配件) / other"""
|
||
t = page.get_text().upper()
|
||
if 'CLAMPING ARMS' in t or 'ACCESSORIES' in t:
|
||
return 'arm'
|
||
if 'DIMENSIONS' in t:
|
||
return 'dim'
|
||
if 'CHARACTERISTICS' in t or 'CODIFICATION' in t:
|
||
return 'char'
|
||
return 'other'
|
||
|
||
|
||
def render(pages, out_dir, start_no):
|
||
"""pages = [(doc, page_idx), ...] 渲染为 p<NN>.png,返回下一个编号"""
|
||
n = start_no
|
||
for doc, i in pages:
|
||
# 彩色输出 (官方图册本身是彩色的; 早期版本误用 csGRAY 转灰度)
|
||
pix = doc[i].get_pixmap(dpi=DPI)
|
||
pix.save(os.path.join(out_dir, f'p{n:02d}.png'))
|
||
n += 1
|
||
return n
|
||
|
||
|
||
def main():
|
||
os.makedirs(DST, exist_ok=True)
|
||
for series, pdfs in SERIES_PDFS.items():
|
||
d = os.path.join(DST, series)
|
||
if CLEAN and os.path.isdir(d):
|
||
shutil.rmtree(d)
|
||
os.makedirs(d, exist_ok=True)
|
||
|
||
all_pages = [] # (doc, page_idx, kind)
|
||
src_docs = []
|
||
for name in pdfs:
|
||
p = os.path.join(SRC, name + '.pdf')
|
||
if not os.path.exists(p):
|
||
print(f'[{series}] 源缺失: {name}')
|
||
continue
|
||
doc = fitz.open(p)
|
||
src_docs.append((name, doc))
|
||
for i in range(doc.page_count):
|
||
all_pages.append((doc, i, classify(doc[i])))
|
||
|
||
if not all_pages:
|
||
print(f'[{series}] 无可用源 PDF')
|
||
continue
|
||
|
||
# 渲染顺序: 特性页 -> 尺寸页 -> 夹臂页(稳定顺序,便于对照)
|
||
order = {'char': 0, 'dim': 1, 'arm': 2, 'other': 3}
|
||
all_pages.sort(key=lambda x: order[x[2]])
|
||
n = render([(doc, i) for doc, i, k in all_pages], d, 1)
|
||
kinds = [k for _, _, k in all_pages]
|
||
print(f'[{series}] {len(all_pages)} 页 -> {kinds}')
|
||
|
||
# 数据表 PDF: 只保留该系列的页(合并多缸径 PDF)
|
||
out_pdf = fitz.open()
|
||
for name, doc in src_docs:
|
||
out_pdf.insert_pdf(doc)
|
||
out_path = os.path.join(d, series + '_manual.pdf')
|
||
out_pdf.save(out_path, garbage=3, deflate=True)
|
||
out_pdf.close()
|
||
print(f'[{series}] datasheet <- {len(pdfs)} 个PDF合并 ({os.path.getsize(out_path)/1024:.0f}KB)')
|
||
|
||
# UCBT: 从主目录提取
|
||
if UCBT_FROM_MAIN:
|
||
d = os.path.join(DST, 'UCBT')
|
||
if CLEAN and os.path.isdir(d):
|
||
shutil.rmtree(d)
|
||
os.makedirs(d, exist_ok=True)
|
||
main_pdf = os.path.join(SRC, MAIN_CATALOG)
|
||
doc = fitz.open(main_pdf)
|
||
# 找 UCBT 相关页(数据页 + 夹臂页)
|
||
# 注: 早期版本用 'UCBT40' 精确匹配 + 漏了 CLAMPING ARMS, 3 页只抓到 1 页。
|
||
# 主目录里 UCBT 占连续 3 页 (idx 40/41/42), 前后分别是 UCBM 与新章节, 故按 UCBT 匹配即准确。
|
||
idxs = []
|
||
for i in range(doc.page_count):
|
||
t = doc[i].get_text().upper()
|
||
if 'UCBT' in t and any(m in t for m in (
|
||
'DIMENSIONS', 'CODIFICATION', 'CHARACTERISTICS', 'CLAMPING ARMS')):
|
||
idxs.append(i)
|
||
if idxs:
|
||
n = render([(doc, i) for i in idxs], d, 1)
|
||
print(f'[UCBT] {len(idxs)} 页 <- 主目录 idx={idxs}')
|
||
# datasheet: 只裁 UCBT 那几页
|
||
out_pdf = fitz.open()
|
||
for i in idxs:
|
||
out_pdf.insert_pdf(doc, from_page=i, to_page=i)
|
||
out_path = os.path.join(d, 'UCBT_manual.pdf')
|
||
out_pdf.save(out_path, garbage=3, deflate=True)
|
||
out_pdf.close()
|
||
print(f'[UCBT] datasheet <- 裁剪 {len(idxs)} 页 ({os.path.getsize(out_path)/1024:.0f}KB)')
|
||
else:
|
||
print('[UCBT] 未找到数据页')
|
||
|
||
print('完成')
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|