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>
This commit is contained in:
@@ -21,19 +21,38 @@ namespace Ounibo.Catalog.Core
|
||||
|
||||
private ZipArchive _zip;
|
||||
private Stream _stream;
|
||||
private string _tempCopy; // 超大包走临时文件副本时的路径 (Dispose 时删除)
|
||||
|
||||
/// <summary>内存直读上限: 超过则改走临时文件副本 (MemoryStream 上限 2GB, 见 Open)。</summary>
|
||||
const long InMemoryLimit = 1500L * 1024 * 1024;
|
||||
|
||||
public static OpcPackage Open(string path)
|
||||
{
|
||||
var p = new OpcPackage { Path = path };
|
||||
// 整包读入内存, 立即释放文件句柄: 软件运行中仍可重建/覆盖同一 .opc (踩坑 #19)
|
||||
byte[] bytes;
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
// 立即释放源文件句柄: 软件运行中仍可重建/覆盖同一 .opc (踩坑 #19)。
|
||||
// 小包读入内存; 超大包(含全部数模可超 2GB)改用临时文件副本 —
|
||||
// MemoryStream 受 int.MaxValue 限制会抛"流太长"。
|
||||
var fi = new FileInfo(path);
|
||||
if (fi.Length <= InMemoryLimit)
|
||||
{
|
||||
var ms = new MemoryStream();
|
||||
fs.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
byte[] bytes;
|
||||
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
var ms = new MemoryStream((int)fi.Length);
|
||||
fs.CopyTo(ms);
|
||||
bytes = ms.ToArray();
|
||||
}
|
||||
p._stream = new MemoryStream(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 复制到临时文件后打开, 同样不占用源文件句柄
|
||||
p._tempCopy = System.IO.Path.Combine(
|
||||
System.IO.Path.GetTempPath(), "opc_" + Guid.NewGuid().ToString("N") + ".tmp");
|
||||
File.Copy(path, p._tempCopy, true);
|
||||
p._stream = new FileStream(p._tempCopy, FileMode.Open, FileAccess.Read,
|
||||
FileShare.ReadWrite);
|
||||
}
|
||||
p._stream = new MemoryStream(bytes);
|
||||
p._zip = new ZipArchive(p._stream, ZipArchiveMode.Read);
|
||||
p.LoadCatalog();
|
||||
return p;
|
||||
@@ -140,6 +159,11 @@ namespace Ounibo.Catalog.Core
|
||||
_stream.Dispose();
|
||||
_stream = null;
|
||||
}
|
||||
if (_tempCopy != null)
|
||||
{
|
||||
try { File.Delete(_tempCopy); } catch { /* 临时文件删除失败不影响退出 */ }
|
||||
_tempCopy = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user