Files
OnebotCatalog/onebot-data/tools/gen-pending-manual.py
wangruiguo 3c4f236cba v2.0: 4 分类真实数据替换 + 手册彩色重做 + 网页版改版
数据 (定位销/勾销缸/翻转缸/电缸 → 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>
2026-09-15 01:05:41 +08:00

117 lines
4.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
为待补分类(定位销/勾销缸/翻转缸/电缸)生成附图。
来源: Univer 官方图册 PDF(X盘 官方图册 / 选型表/spanner)。
输出: manual/<系列>/p<NN>.png + <系列>_manual.pdf
用法: PYTHONUTF8=1 python gen-pending-manual.py [--clean]
"""
import fitz, os, shutil, sys
SRC = r'X:/新开发产品-Research and Development/2_产品资料/Univer资料/官方图册'
SPANNER = r'X:/新开发产品-Research and Development/2_产品资料/Univer资料/选型表/spanner'
DST = r'D:/开发/OnebotCatalog/onebot-data/catalog/manual'
DPI = 110
CLEAN = '--clean' in sys.argv
# 系列 -> (目录, [pdf 名]);pdf 名不含扩展名
SPECS = {
# ---- 定位销 ----
'ULA': (SRC, ['ula40cten_en419', 'ula63cten_en407']),
'ULB': (SRC, ['ulb32cten_en423']),
'ULL': (SRC, ['ull50cten_en411']),
'ULM': (SRC, ['ulm50cten_en410']),
'ULO': (SRC, ['ulo50cten_en413']),
'ULP': (SRC, ['ulp32cten_en404', 'ulp50cten_en405', 'ulp63cten_en406']),
'ULR': (SRC, ['ulr50nken_en476', 'ulr63cten_en477']),
'ULT': (SRC, ['ult50cten_en408']),
'ULX': (SRC, ['ulx50cten_en425']),
'ULY': (SRC, ['uly40cten_en426']),
'ULZ': (SRC, ['ulz40cten_en428']),
# ---- 勾销缸 ----
'USP': (SRC, ['usp32cten_en355', 'usp50cten_en437', 'usp50ucten_en168']),
'USL': (SRC, ['usl50cten_en171']),
'USR': (SRC, ['usr40cten_en436']),
'USS': (SRC, ['uss50cten_en433', 'uss63cten_en434']),
'USSL': (SRC, ['ussl50cten_en358']),
# ---- 翻转缸 ----
'UAGP': (SRC, ['uagp075wcten_en580', 'uagp075bcten_en181', 'uagp080wcten_en174',
'uagp080wcten_en573', 'uagp120bcten_en175', 'uagp120wcten_en574',
'uagp150bcten_en178', 'uagp150wcten_en577', 'uagp155wcten_en583',
'uagp170bnken_en176', 'uagp170wcten_en575', 'uagp210bcten_en182',
'uagp210wcten_en581', 'uagp215bcten_en373', 'uagp215wcten_en584',
'uagp300bcten_en177', 'uagp300wcten_en576', 'uagp350bcten_en183',
'uagp350wcten_en582', 'uagp355bcten_en374', 'uagp355wcten_en585',
'uagp600bcten_en179', 'uagp600wcten_en578', 'uagp605bcten_en180',
'uagp605wcten_en579']),
# LAGP 官方已改名 UAGP,图册在选型表/spanner(老版)
'LAGP': (SPANNER, ['lagp075_en_c181', 'lagp120_en_c175', 'lagp150_en_c178',
'lagp155_en_c350', 'lagp170_en_c176', 'lagp210_en_c182',
'lagp215nwrev-00-0119en_en373', 'lagp300_en_c177']),
# ---- 电缸 ----
'LAE': (SRC, ['lae140_en_c220', 'lae225_en_c221', 'lae350_en_c222']),
}
def classify(page):
t = page.get_text().upper()
if 'ACCESSORIES' in t or 'CLAMPING ARMS' in t or 'BLADE ARMS' in t:
return 'arm'
if 'DIMENSIONS' in t:
return 'dim'
if 'CHARACTERISTICS' in t or 'CODIFICATION' in t:
return 'char'
return 'other'
def main():
os.makedirs(DST, exist_ok=True)
missing = []
for series, (srcdir, pdfs) in SPECS.items():
d = os.path.join(DST, series)
if CLEAN and os.path.isdir(d):
shutil.rmtree(d)
os.makedirs(d, exist_ok=True)
docs, all_pages = [], []
for name in pdfs:
p = os.path.join(srcdir, name + '.pdf')
if not os.path.exists(p):
missing.append(f'{series}: {name}')
continue
doc = fitz.open(p)
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 = 1
for doc, i, _k in all_pages:
# 彩色输出 (官方图册本身是彩色的; 早期版本误用 csGRAY 转灰度,
# 体积约翻倍但相对整个数据包可忽略)
doc[i].get_pixmap(dpi=DPI).save(
os.path.join(d, f'p{n:02d}.png'))
n += 1
out_pdf = fitz.open()
for _name, doc in docs:
out_pdf.insert_pdf(doc)
outp = os.path.join(d, series + '_manual.pdf')
out_pdf.save(outp, garbage=3, deflate=True)
out_pdf.close()
print(f'[{series}] {len(all_pages)} 页 / {len(pdfs)} PDF -> '
f'{os.path.getsize(outp)/1024:.0f}KB')
if missing:
print('\n源缺失:')
for m in missing:
print(' ', m)
print('完成')
if __name__ == '__main__':
main()