v2.1: DESTACO 风格选型界面 + 参数组合补全(缺组合也能出零件号)
网页版选型改版 (仅网页版, 桌面版待同步)
- 新增零件号实时条: 边选边拼, 已确定片段实心高亮, 未定片段虚化, 进度条随选推进;
浅色配色 (初版深色块与页面不协调, 已改); 选满且唯一命中时整块转青色实心
- 技术方案: 40 系列中仅 KC 有编码模板 → 改用「当前候选型号的最长公共前缀」,
已验证 40/40 系列前缀单调增长(不回退)
- 参数选择由下拉菜单改为可视化选项块: 悬停抬升+青色投影, 选中青色填充+✓,
不可选取值置灰(虚线+划线, 不消失, 让用户看到选项存在但当前组合不适用),
再点一次取消; 有说明的显示代号+说明, 纯数值用紧凑文字块
- 参数联动仍复用 allowedOptions 规则引擎, 语义未变, 只改渲染
参数组合补全
- 原逻辑: 必须有真实数模才能生成型号 → 库里没有的组合选不出来也出不了号
- infer-sku-template.py 从已有型号反推编码模板, 得 23 个系列 100% 可复现
- verify-templates.py 作为门禁: 用模板重渲染每个已有型号必须逐字一致 ——
该检查抓出 ULM/ULP 行程补零位数写错(2位写3位), 否则会生成 3000 个不存在的零件号
- gen-missing-combos.py 补全 8 个系列共 3157 个型号 (全库 54136 → 57293)
- 占位数模: 3157 个型号共用 1 个 PLACEHOLDER.step(4.5KB), 构建器按路径打包只存一份,
数据包仅 2.10GB → 2.14GB (中途用硬链接方案踩坑: NTFS 上限 1024, 超出退化为拷贝白占 500MB)
- _pending_models.csv 输出待补数模清单, 供 AI 补完后替换 step_file
新增脚本: infer-sku-template / verify-templates / quantify-combo-gap /
gen-missing-combos / gen-placeholder-step / check-combo-unique
新增文档: docs/更改说明-v2.1.md
发现未处理 (已记录在更改说明):
- 夹紧缸 9 系列一组参数对应多型号 (310 个型号, 编码含参数外尾缀, 旧码/新码混用)
- UAGP/LAGP 参数顺序与官方编码结构不符 (传感器应在转角之前)
- 17 个系列因模板不干净未补全 (宁可少补, 不生成可能不存在的零件号)
Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
135
onebot-data/tools/gen-placeholder-step.py
Normal file
135
onebot-data/tools/gen-placeholder-step.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
生成占位数模 (每系列一个通用的"待补数模"方块)。
|
||||
|
||||
用途: 为「参数组合补齐」生成的型号提供占位 STEP —— 构建器要求每个型号必须有数模文件。
|
||||
真实数模后续由 AI 参照同系列已有型号补出, 覆盖同名文件即可。
|
||||
|
||||
产出:
|
||||
catalog/step/PLACEHOLDER.step 通用的方块 (ISO-10303-21, 标准 B-rep)
|
||||
catalog/step/_placeholder/<系列>.step 每系列一份 (便于按系列替换/识别)
|
||||
|
||||
方块边长 60mm, 居中于原点。
|
||||
用法: PYTHONUTF8=1 python gen-placeholder-step.py
|
||||
"""
|
||||
import os
|
||||
|
||||
CAT = r'D:/开发/OnebotCatalog/onebot-data/catalog'
|
||||
STEP_DIR = os.path.join(CAT, 'step')
|
||||
|
||||
# 方块尺寸 (mm)
|
||||
SX, SY, SZ = 60.0, 60.0, 60.0
|
||||
HX, HY, HZ = SX / 2, SY / 2, SZ / 2
|
||||
|
||||
|
||||
def build_step(label):
|
||||
"""生成一个合法的 STEP 文件内容: 单位立方体 B-rep。"""
|
||||
L = []
|
||||
L.append('ISO-10303-21;')
|
||||
L.append('HEADER;')
|
||||
L.append("FILE_DESCRIPTION(('PLACEHOLDER - real CAD model pending'),'2;1');")
|
||||
L.append("FILE_NAME('%s','2026-01-01T00:00:00',('ONEBOT'),('ONEBOT'),"
|
||||
"'gen-placeholder-step.py','ONEBOT Catalog','');" % label)
|
||||
L.append("FILE_SCHEMA(('AUTOMOTIVE_DESIGN { 1 0 10303 214 1 1 1 1 }'));")
|
||||
L.append('ENDSEC;')
|
||||
L.append('DATA;')
|
||||
L.append("#1=APPLICATION_CONTEXT('core data for automotive mechanical design processes');")
|
||||
L.append("#2=APPLICATION_PROTOCOL_DEFINITION('international standard','automotive_design',2000,#1);")
|
||||
L.append("#3=PRODUCT_CONTEXT('',#1,'mechanical');")
|
||||
L.append("#4=PRODUCT_DEFINITION_CONTEXT('part definition',#1,'design');")
|
||||
L.append("#5=PRODUCT('%s','PLACEHOLDER',$,(#3));" % label)
|
||||
L.append("#6=PRODUCT_DEFINITION_FORMATION('','',#5);")
|
||||
L.append("#7=PRODUCT_DEFINITION('design','',#6,#4);")
|
||||
L.append("#8=PRODUCT_DEFINITION_SHAPE('','',#7);")
|
||||
L.append("#9=(LENGTH_UNIT()NAMED_UNIT(*)SI_UNIT(.MILLI.,.METRE.));")
|
||||
L.append("#10=(NAMED_UNIT(*)PLANE_ANGLE_UNIT()SI_UNIT($,.RADIAN.));")
|
||||
L.append("#11=(NAMED_UNIT(*)SI_UNIT($,.STERADIAN.)SOLID_ANGLE_UNIT());")
|
||||
L.append("#12=UNCERTAINTY_MEASURE_WITH_UNIT(LENGTH_MEASURE(0.001),#9,"
|
||||
"'distance_accuracy_value','');")
|
||||
L.append("#13=(GEOMETRIC_REPRESENTATION_CONTEXT(3)"
|
||||
"GLOBAL_UNCERTAINTY_ASSIGNED_CONTEXT((#12))"
|
||||
"GLOBAL_UNIT_ASSIGNED_CONTEXT((#9,#10,#11))REPRESENTATION_CONTEXT('',''));")
|
||||
|
||||
# 8 个顶点坐标
|
||||
corners = [
|
||||
(-HX, -HY, -HZ), (HX, -HY, -HZ), (HX, HY, -HZ), (-HX, HY, -HZ),
|
||||
(-HX, -HY, HZ), (HX, -HY, HZ), (HX, HY, HZ), (-HX, HY, HZ),
|
||||
]
|
||||
eid = 20
|
||||
pt_ids, vx_ids = [], []
|
||||
for (x, y, z) in corners:
|
||||
L.append('#%d=CARTESIAN_POINT('',(%.3f,%.3f,%.3f));' % (eid, x, y, z))
|
||||
pt_ids.append(eid); eid += 1
|
||||
L.append('#%d=DIRECTION('',(0.,0.,1.));' % eid); dz = eid; eid += 1
|
||||
L.append('#%d=DIRECTION('',(1.,0.,0.));' % eid); dx = eid; eid += 1
|
||||
for pid in pt_ids:
|
||||
L.append('#%d=VERTEX_POINT('',#%d);' % (eid, pid))
|
||||
vx_ids.append(eid); eid += 1
|
||||
|
||||
# 12 条棱
|
||||
edges = [(0, 1), (1, 2), (2, 3), (3, 0),
|
||||
(4, 5), (5, 6), (6, 7), (7, 4),
|
||||
(0, 4), (1, 5), (2, 6), (3, 7)]
|
||||
edge_ids = []
|
||||
for (a, b) in edges:
|
||||
L.append('#%d=LINE('',#%d,#%d);' % (eid, pt_ids[a], pt_ids[b]))
|
||||
ln = eid; eid += 1
|
||||
L.append('#%d=VECTOR('',#%d,1.0);' % (eid, dx)); vc = eid; eid += 1
|
||||
L.append('#%d=EDGE_CURVE('',#%d,#%d,#%d,.T.);'
|
||||
% (eid, vx_ids[a], vx_ids[b], ln))
|
||||
ec = eid; eid += 1
|
||||
L.append('#%d=ORIENTED_EDGE('',*,*,#%d,.T.);' % (eid, ec))
|
||||
edge_ids.append(eid); eid += 1
|
||||
|
||||
# 6 个面
|
||||
faces = [
|
||||
[0, 1, 2, 3], [4, 5, 6, 7],
|
||||
[0, 1, 5, 4], [1, 2, 6, 5],
|
||||
[2, 3, 7, 6], [3, 0, 4, 7],
|
||||
]
|
||||
normals = [(0, 0, -1), (0, 0, 1), (0, -1, 0), (1, 0, 0), (0, 1, 0), (-1, 0, 0)]
|
||||
face_ids = []
|
||||
for fi, f in enumerate(faces):
|
||||
loops = []
|
||||
for k in range(4):
|
||||
loops.append(edge_ids[f[k]])
|
||||
L.append('#%d=EDGE_LOOP('',(%s));'
|
||||
% (eid, ','.join('#%d' % x for x in loops)))
|
||||
el = eid; eid += 1
|
||||
nx, ny, nz = normals[fi]
|
||||
L.append('#%d=DIRECTION('',(%.1f,%.1f,%.1f));' % (eid, nx, ny, nz))
|
||||
nd = eid; eid += 1
|
||||
L.append("#%d=AXIS2_PLACEMENT_3D('',#%d,#%d,$);" % (eid, pt_ids[f[0]], nd))
|
||||
ax = eid; eid += 1
|
||||
L.append('#%d=PLANE(\'\',#%d);' % (eid, ax))
|
||||
pl = eid; eid += 1
|
||||
L.append('#%d=ADVANCED_FACE(\'\',(#%d),#%d,.T.);' % (eid, el, pl))
|
||||
face_ids.append(eid); eid += 1
|
||||
|
||||
L.append('#%d=CLOSED_SHELL(\'\',(%s));'
|
||||
% (eid, ','.join('#%d' % x for x in face_ids)))
|
||||
sh = eid; eid += 1
|
||||
L.append("#%d=MANIFOLD_SOLID_BREP('PLACEHOLDER',#%d);" % (eid, sh))
|
||||
msb = eid; eid += 1
|
||||
L.append('#%d=ADVANCED_BREP_SHAPE_REPRESENTATION(\'PLACEHOLDER\',(#%d,#%d),#13);'
|
||||
% (eid, msb, eid + 1))
|
||||
abr = eid; eid += 1
|
||||
L.append("#%d=AXIS2_PLACEMENT_3D('',#%d,#%d,#%d);" % (eid, pt_ids[0], dz, dx))
|
||||
ax2 = eid; eid += 1
|
||||
L.append("#%d=SHAPE_DEFINITION_REPRESENTATION(#8,#%d);" % (eid, abr))
|
||||
L.append('ENDSEC;')
|
||||
L.append('END-ISO-10303-21;')
|
||||
return '\n'.join(L) + '\n'
|
||||
|
||||
|
||||
def main():
|
||||
os.makedirs(STEP_DIR, exist_ok=True)
|
||||
content = build_step('PLACEHOLDER')
|
||||
p = os.path.join(STEP_DIR, 'PLACEHOLDER.step')
|
||||
with open(p, 'w', encoding='ascii', newline='\r\n') as f:
|
||||
f.write(content)
|
||||
print(f'写入 {p} ({os.path.getsize(p)} 字节)')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user