数据 (定位销/勾销缸/翻转缸/电缸 → 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>
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""
|
||
并行复制待补分类的 STEP 数模(X盘网络盘慢,串行不可行)。
|
||
复用 gen-pending-series.py 的扫描缓存 + 解析器。
|
||
用法: PYTHONUTF8=1 python copy-pending-step.py
|
||
"""
|
||
import os, sys, shutil
|
||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||
import importlib.util
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
spec = importlib.util.spec_from_file_location('gps', os.path.join(HERE, 'gen-pending-series.py'))
|
||
gps = importlib.util.module_from_spec(spec)
|
||
spec.loader.exec_module(gps)
|
||
|
||
DST = os.path.join(gps.DST, 'step')
|
||
os.makedirs(DST, exist_ok=True)
|
||
|
||
scanned = gps.load_scan()
|
||
todo = []
|
||
for sp in gps.SPECS:
|
||
records, _ = gps.collect(sp, scanned)
|
||
for m in records.values():
|
||
dst = os.path.join(DST, m['model'] + '.step')
|
||
if not os.path.exists(dst):
|
||
todo.append((m['src'], dst, m['model']))
|
||
print(f'待复制 {len(todo)} 个(已存在则跳过)')
|
||
|
||
def cp(item):
|
||
src, dst, model = item
|
||
for attempt in range(3):
|
||
try:
|
||
shutil.copy2(src, dst)
|
||
return (model, 'ok', None)
|
||
except Exception as e:
|
||
if attempt == 2:
|
||
return (model, 'err', str(e))
|
||
return (model, 'err', 'unknown')
|
||
|
||
ok = err = 0
|
||
errors = []
|
||
with ThreadPoolExecutor(max_workers=8) as ex:
|
||
futs = [ex.submit(cp, it) for it in todo]
|
||
for i, fut in enumerate(as_completed(futs), 1):
|
||
model, status, e = fut.result()
|
||
if status == 'ok':
|
||
ok += 1
|
||
else:
|
||
err += 1
|
||
errors.append(f'{model}: {e}')
|
||
if i % 100 == 0:
|
||
print(f' {i}/{len(todo)} (ok={ok} err={err})')
|
||
|
||
print(f'\n完成: 复制 {ok} 个, 失败 {err} 个')
|
||
for e in errors[:20]:
|
||
print(' !', e)
|
||
print(f'step 目录现有 {len(os.listdir(DST))} 个文件')
|