首页/新闻资讯/正文详情

Altium Designer交互式BOM插件开发:从原理图采集到PCB高亮回跳

发布时间:2026/9/25 3:52:32 来源:云帆数科 栏目:资讯中心
Altium Designer交互式BOM插件开发:从原理图采集到PCB高亮回跳
简介Altium Designer 用户常需在原理图与 PCB 设计流程中维护物料清单但软件原生并不直接提供交互式 BOM 导出能力。这款插件正是针对这一缺口设计的效率工具面向需要将 BOM 以网页化、可交互形式交付的硬件工程师与采购人员。压缩包共 35 个文件源代码规模约 94KB以 17 个 JavaScript 脚本为主体辅以工程脚本、bat 安装卸载脚本、md 使用说明、html/css 前端展示页面及配置备份文件覆盖从初始化、路径配置到 Web 渲染的完整链路。资源内含初始化与清理批处理、路径配置脚本、核心导出任务脚本和 Web 端渲染模块目录划分清晰便于按需调用或二次修改。目前已有 400 人学习下载。通过复用这套脚本用户无需从零编写导出逻辑即可在 Altium Designer 中生成包含物料编号、描述、数量、封装等信息的交互式 BOM并支持对接实时数据库与供应商交互提升物料采购的准确性和设计协同效率。1. 在 Altium Designer 里把 BOM 从静态表变成能回跳高亮的交互式清单在 Altium Designer 里导 BOMBill of Materials看起来只是菜单里点几下的事真折腾起来能让整个下午从工位上消失。默认的 Report Manager 输出就是一张静态表位号挤成一格封装和值相同的元件不合并采购拿回去还得人工拆行改一次版没人敢保证手上的 Excel 和原理图是同一份。我要说的这个插件解决的是把 BOM 从「一次性导出文件」升级成可以筛选、折叠、回跳原理图高亮的交互式清单再用 C# 把结果落成一份正规 xlsx 给供应链。适合每周要给打样厂出 BOM、又反复核对位号变更的硬件工程师也适合自己动手维护工具链的板级项目管理者。2. 先摸清 BOM 的数据流插件在哪一环发力才能不返工2.1 BOM 不是导出时才拼出来的它是原理图对象的投影先说结论AD 的 BOM 输出不是报表生成器脑补出来的底层就是原理图文档里的元件对象。原理图本身更像一个容器里面每个元件对应一个 SchComponent 对象身上挂着一堆属性位号、封装、逻辑符号、厂家料号、Description还有你自定义的扩展参数。Report Manager 做的事情本质上就是把这些属性按模板重新排列然后堆进 Excel、CSV 或者 PDF。搞清楚这一点「导出 BOM」就能拆成两层一层是拿数据一层是排数据。插件和人工的区别只在于能不能在排数据这层做更多的事。很多半成品插件在拿数据这一层就翻车了。它们遍历的是当前打开的那一张 sheet而不是整个工程。多图纸项目里只有一半元件进了 BOM最坑的是这种问题不报错等你贴片回来才发现少料。所以插件的第一个原则必须是数据源取编译后的工程而不是工作区里某个当前文档。这在代码层面差别不大但在实际交付层面是天壤之别。2.2 静态表必翻车的三个场景合并项、复用通道、改版差异把静态 BOM 升级成交互式动力主要来自三个具体场景。第一个场景是同类项聚合。同一封装、同一值的电阻在原理图里有几十个位号静态导出的分行规则完全由模板决定。用 Excel 人工合并单元格第一次还能忍受改版后又是一轮纯体力活。交互式 BOM 要把聚合规则固定住按 Footprint 加 Value 分组位号压成区间数量自动统计不再依赖任何人工编辑。第二个场景是复用模块。一张原理图里放了四个相同通道静态 BOM 会把同一颗料重复出现四次。采购拿到四行一模一样的记录大概率当成四个不同物料来询价。交互式 BOM 需要知道通道信息把跨通道同料合并成一行同时保留每个通道的位号前缀让产线能追溯到具体位置。第三个场景是改版核对。静态表没有 diff 概念改了一次工程新旧 BOM 的差异只能肉眼找。交互式 BOM 可以在插件端做 hash、版本记录和变更标记把「到底改没改」变成一行命令能回答的问题。这些都不是 Excel 模板能补的能力必须同时落在数据采集和后处理两层里。2.3 实现路线怎么选纯脚本、C# 外挂、还是脚本加 C# 混合实现路径主要集中在三条线上。纯 DelphiScript 是 AD 原生脚本语言访问原理图对象非常直接安装零依赖缺点是字符串处理、界面控件、Excel 后处理都偏弱AD 的脚本运行环境和现代 IDE 差距明显逻辑一复杂就容易把自己绕进去。C# 外挂则是另一条路脚本把数据导成中间文件C# 程序负责聚合、排序、生成 xlsx。开发体验舒服但部署成本更高。自己在单机上跑无所谓要推广给整个硬件组就得处理 .NET 运行时、路径配置、版本兼容这些问题维护精力不小。我最终落地的方案是混合结构DelphiScript 只负责 AD 擅长的三件事——遍历工程拿数据、维护交互面板、把选中位号回传给 PCB 高亮。C# 控制台程序负责一切文件层处理包括位号压缩、分组、Excel 模板填充。中间用 XML 交换数据两边不依赖额外组件。这个边界很清楚脚本层不碰文件细节C# 层不碰 AD 接口谁也不越界。选型上还有一点容易被忽略AD 升级频率不低脚本接口偶尔有变动。脚本层做得越薄升级时的维护成本就越低C# 后处理不依赖 AD完全不受版本影响。哪怕只是写给自己用的工具我也建议把后处理独立出去这算是一条后悔药。3. 交互式 BOM 落地代码采集、聚合、高亮三段式实现3.1 工程结构脚本、C# 控制台与 XML 交换层我给这套插件规划的结构不算复杂核心文件如下文件职责运行位置BomPanel.pas交互面板、采集入口、双击回跳高亮AD 脚本引擎BomProject.pas工程级元件遍历与参数读取AD 脚本引擎BomFlatten.cs位号排序、聚合、压缩、生成 xlsx外部 C# 控制台config.ini忽略参数列表、输出路径配置外部bom_raw.xml脚本生成的中间交换数据脚本生成脚本负责把 bom_raw.xml 写到约定目录然后调用 BomFlatten.exe 读取并输出。之所以用 XML 做中间格式而不是脚本直接写 Excel是因为 DelphiScript 走 Excel COM 经常因为 Office 版本差异翻车而 XML 两边读起来都没有额外依赖。这是一个踩出来的经验能不碰 COM 就不碰 COM。3.2 遍历工程元件用迭代器读参数注意回退逻辑采集部分我放在脚本里用原理图文档的 SchIterator 来遍历元件。注意遍历对象是编译后的工程文档不是单张图纸。procedure CollectFromSheet(ASheet: ISch_Document); var SchIterator: ISch_Iterator; AComponent: ISch_Component; MPN, Value, Footprint: String; begin if ASheet Nil then Exit; SchIterator : ASheet.SchIterator_Create; try SchIterator.AddFilter_ObjectSet(MkSet(eSchComponent)); AComponent : SchIterator.FirstSchObject; while AComponent Nil do begin Footprint : AComponent.Footprint; Value : AComponent.GetComponentParameter(Value); MPN : AComponent.GetComponentParameter(Manufacturer Part Number); if MPN then MPN : AComponent.GetComponentParameter(MPN); AddGridRow(AComponent.Designator.Text, Value, Footprint, MPN); AComponent : SchIterator.NextSchObject; end; finally ASheet.SchIterator_Destroy(SchIterator); end; end;逻辑上有一个点很关键迭代器创建后立刻加AddFilter_ObjectSet(MkSet(eSchComponent))过滤器。如果不加迭代器会把网络标签、端口、注释文本全部遍历一遍大图很容易卡顿。GetComponentParameter(Value)是读元件参数的常用接口不同版本对参数名大小写处理不一致所以第二个 MPN 读取做了一个回退字段为空时再试MPN。读取到的数据统一塞进面板的 Grid 行里。每次采集之前必须先清空 Grid否则连续刷新时旧行会叠加这个习惯我在后面避坑章里会再提一次。3.3 C# 侧做位号自然排序与区间压缩位号聚合是一个绕不开的问题。直接按字符串排序R10 会排在 R2 前面这是新手最容易踩的坑。C# 侧先把位号拆成前缀和数字两部分再按数字排序和压缩区间public static Liststring CompressDesignators(IEnumerablestring source) { var items source .Select(d new { Raw d, Prefix Regex.Replace(d, [0-9]$, ), Num int.Parse(Regex.Match(d, [0-9]$).Value) }) .OrderBy(x x.Prefix) .ThenBy(x x.Num) .ToList(); var result new Liststring(); int i 0; while (i items.Count) { int j i; while (j 1 items.Count items[j 1].Prefix items[i].Prefix items[j 1].Num items[j].Num 1) { j; } result.Add(j i ? items[i].Raw : ${items[i].Raw}-{items[j].Raw}); i j 1; } return result; }正则[0-9]$从位号末尾抠出数字前缀保持原样。排序键用Prefix加Num组合这样 R1、R2、R10 会排成 R1-R2、R10而不是 R1、R10、R2。压缩区间的前提是 prefix 相同且 Num 连续如果出现 R1A、R1B 这类子字母变体需要先拆出子字母再排序不要硬塞进区间。调用方把同一 Footprint 加 Value 加 MPN 的行分到一组组内位号做压缩组的 Count 就是数量。这里建议区分「记录数」和「位号数」两个概念复用通道场景下两者未必相等。3.4 点击 BOM 行回跳 PCB 高亮选择集操作交互式 BOM 的一个重要动作是双击行让 PCB 上对应元件高亮。脚本里通过 PCB 文档的 GroupIterator 遍历板级元件命中位号后置 Selectedprocedure HighlightOnPcb(ARefDesList: TStringList); var PcbDoc: IPCB_Document; Board: IPCB_Board; Iterator: IPCB_Iterator; AComp: IPCB_Component; begin PcbDoc : GetWorkspace.DM_FocusedDocument; if PcbDoc.ObjectKind eDocKind_Pcb then Exit; Board : PcbDoc.Board; Iterator : Board.GroupIterator_Create; Iterator.AddFilter_ObjectSet(MkSet(eComponentObject)); try AComp : Iterator.FirstPCBObject; while AComp Nil do begin if ARefDesList.IndexOf(AComp.Name.Text) 0 then AComp.Selected : True; AComp : Iterator.NextPCBObject; end; finally Board.GroupIterator_Destroy(Iterator); end; Board.GraphicallyInvalidate; end;GroupIterator_Create负责跑板级对象eComponentObject过滤器只留元件。命中判定用位号文本匹配选中后不自己实现原理图同步直接依赖 AD 自带的 Cross Select Mode省去大量通信代码。值得强调的是GraphicallyInvalidate这一行如果漏掉选择集已经改了但界面不刷新你会以为插件没生效。4. 部署到日常工作流脚本路径、菜单注册与 OutJob 挂载4.1 脚本目录的放法全局路径而不是版本目录AD 启动时会从若干目录搜索脚本实际行为有点玄学它不是把目录里所有 .pas 文件都搬进菜单而是把脚本工程挂载到 DXP 体系里。我的习惯是把脚本统一放在%APPDATA%\Altium\Scripts不放在带版本号的Altium Designer {版本}子目录下。这样 AD 大版本升级后脚本目录不会跟着失效重装系统也能快速找回。目录结构保持简单BomPanel.pas 和 BomProject.pas 放一起外部再由 config.ini 指定 C# 后处理路径和输出目录。路径全部用相对路径或环境变量拼接不要写死机器名。团队内部使用的话整个目录放进 Git 仓库新同事 clone 下来直接能用。4.2 加载与注册菜单、工具栏、快捷键脚本首次加载有点反直觉直接在 DXP 里运行脚本只会执行一次下次启动又找不到了。需要把脚本工程添加到 AD 的项目面板里再注册成菜单项才能变成常驻工具。注册对象操作备注脚本工程Projects → Add New to Project → Files选择 BomPanel.pas让 AD 识别脚本工程菜单挂载DXP → Customize → Toolbars → Commands → Scripts把脚本命令拖到工具栏或菜单进程调用命令行输入 RunProcess指定脚本过程名可用于快捷键绑定注册完成后建议把生成的 .Inst 文件导出并提交到版本库。这样新机器安装 AD 后直接双击 .Inst 文件就能恢复菜单项不用每家机器手动拖一遍。快捷键我习惯绑成 CtrlF12打开交互式 BOM 面板的频率很高鼠标点菜单不够快。4.3 OutJob 里挂脚本和后处理批处理链路如果只是人工打开面板点导出那还谈不上自动化。AD 的 OutJobOutput Job除了输出 PDF、Gerber还能挂脚本输出步骤。把脚本里的导出过程绑定到 OutJob 后整条生成链路可以一键触发。一个常见的配置失误是忘了把 OutJob 的目标项目设置为 Active。不设置的话脚本运行时拿不到当前焦点工程遍历结果为空但 OutJob 本身不会报错属于隐蔽坑。脚本执行完生成 bom_raw.xml 后还需要外部触发 C# 后处理这一步我会用 PowerShell 承接$raw $env:APPDATA\Altium\Scripts\bom_raw.xml $exe $env:APPDATA\Altium\Scripts\BomFlatten.exe $exe -i $raw -o .\Output\bom_final.xlsx -t .\Output\bom_template.xlsx关于 C# 部分是否要编译成 DLL 给脚本直接引用我的态度是技术上可行但别这么干。DLL 一旦初始化失败整个脚本进程会被拖垮连个像样的报错都看不到。控制台 exe 的好处是失败时你还能直接在命令行里看到异常栈这是后悔药而 DLL 不是。5. 交互式 BOM 插件避坑记录五处典型问题与对应修法这节内容不是从文档里看出来的多数是插件迭代了几轮才定位到根因。每条按现象、原因、解决三段写方便对照排查。5.1 位号重复不报警导出数量虚高现象聚合后的 Quantity 比原理图实际数量多展开明细发现两个位号完全相同的元件各算了一次。原因原理图里元件被成组粘贴AD 默认不实时校验位号唯一性。导出时两个独立对象都进入组件列表插件没有拦截。解决采集阶段用一个 TStringList 对 Designator 做唯一性检查。需要把 TStringList.Sorted 置为 True再利用 Duplicates 属性判断重复。发现重复后直接弹警告并写日志而不是默默跳过。同时在 AD 的 Schematic 编译选项里打开位号唯一性检查从源头减少这种数据。5.2 C# 读取中间 XML 中文乱码现象DelphiScript 导出的 XML 里中文元件值全部变成乱码C# 解析后 Excel 里没法看。原因DelphiScript 写文件时可能按 AnsiString 编码输出简体中文 Windows 下默认走 GBK代码页 936而 C# 的 StreamReader 默认按 UTF-8 读两边不一致必乱。解决脚本侧写 XML 时统一声明 UTF-8C# 侧读取前先探测文件编码优先识别 BOM没有 BOM 的文件按代码页 936 回退。判断逻辑如下public static Encoding DetectEncoding(string path) { using var fs File.OpenRead(path); if (fs.Length 3) return Encoding.UTF8; var head new byte[3]; fs.Read(head, 0, 3); if (head[0] 0xEF head[1] 0xBB head[2] 0xBF) return Encoding.UTF8; if (head[0] 0xFF head[1] 0xFE) return Encoding.Unicode; if (head[0] 0xFE head[1] 0xFF) return Encoding.BigEndianUnicode; return Encoding.GetEncoding(936); }提示没有 BOM 的老文件只能靠猜中文 Windows 通常就是 936。有 BOM 时优先信 BOM不要自作聪明去猜。5.3 连续导出三四次后内存暴涨、界面卡死现象第一次导出正常连续刷新几次后 AD 内存占用明显上涨面板操作开始卡顿。原因迭代器在异常分支没有被销毁面板 Grid 每次采集都在追加行没有清空旧数据。解决代码里统一用 try/finally 包裹迭代器销毁逻辑确保任何分支都会执行SchIterator_Destroy。每次采集前先调用Grid.Rows.Clear再重新填充。给采集过程加一个简单进度条也能减少用户反复点击刷新的冲动毕竟 AD 长时间运行本身就会占内存没必要让插件再添一把火。5.4 AD 升级后插件菜单消失现象AD 小版本升级后原来工具栏上的插件入口不见了脚本面板里也找不到。原因菜单注册信息写进了旧版本的 DXP 配置脚本路径往往又跟着旧版本号走。默认的%APPDATA%\Altium\Altium Designer {旧版本}\Scripts新版本根本不看。解决脚本统一放到%APPDATA%\Altium\Scripts、不带版本号的全局目录。升级后重新加载一次脚本工程再把之前导出的 .Inst 文件双击一遍恢复菜单。如果团队有多个版本共存这个做法最省心。5.5 复用模块位号被错误合并成连续区间现象同一个复用模块的 R1、R5、R12 被压缩成 R1-R12采购一看以为是一整排电阻实际只是同模块内不同位置的三个电阻。原因聚合压缩只看了位号后缀的数字忽略位号前面的模块前缀或通道标记。R1 和 R5 前缀不同但插件没拆开。解决压缩前把位号拆成两层排序键第一层是模块路径或通道前缀第二层是数字序号。前缀不同的位号不参与区间合并保留独立输出。复用模块在原理图里的路径可以从编译数据里取得不要自己解析图纸名因为通道编号往往带在对象属性里而不是文本里。6. 进阶把插件挂进 OutJob让 BOM 一键落盘并留下版本指纹到了这步插件的基本能力已经够用但离集成到项目交付流程还差最后一环。我会把插件入口拆成两个过程ShowBomPanel负责交互面板ExportBomSilent负责静默导出。前者给人用后者给 OutJob 用。在 OutJob 里新建一个脚本输出步骤绑定ExportBomSilent再把目标项目设为 Active。这样每次出工程包Gerber、PDF、BOM 会一起生成没人能再找借口说「导出 BOM 太麻烦所以没导」。版本核对的问题我会加一个哈希记录步骤。在 OutJob 生成完 bom_final.xlsx 后用 PowerShell 计算 SHA256 并追加到 bom_hash.txt$file .\Output\bom_final.xlsx $hash (Get-FileHash $file -Algorithm SHA256).Hash $hash $file | Out-File -Append -Encoding utf8 bom_hash.txt这个文件放进版本库每次对 BOM 的任何改动都会留下指纹。审板时先 diff bom_hash.txt如果 hash 没变就说明 BOM 没动过不需要重复核对hash 变了再去 diff 具体位号差异比翻文件夹找旧 Excel 靠谱得多。从那以后我每次给产线释放工程包前都强制跑一遍这条 OutJob先把 hash 记录下来才发邮件。至少「上一版 BOM 到底改没改」这种事再也不用靠记忆去猜了。希望帮到你。本文还有配套的精品资源点击获取

相关推荐

为何我不写政策解读?出租车行业四大替代选题方向
为何我不写政策解读?出租车行业四大替代选题方向

先说明一下,这篇我没有动笔的原因看到“南宁市出租汽车行业发展规划(2024-2029)”这个选题时,我没有直接按常规流程去拆解标题、搭建博文框架,而是先停下做了一轮内容合规自查。原因不复杂:这类文件属于地方… · 2026/9/25 3:52:32

gpt-5.6-sol Prompt Bank 评测指南:360 条双语提示词库、判定规则与可恢复运行机制
gpt-5.6-sol Prompt Bank 评测指南:360 条双语提示词库、判定规则与可恢复运行机制

【免费下载链接】gpt-instruct A Codex jailbreak prompt and test pack for gpt. 针对 gpt 系列的 Codex 破甲提示词与测试包。 项目地址: https://gitcode.com/gh_mirrors/gp/gpt-instruct 点击查看 免费下载 导读:本文以 docs/gpt-5.6-sol-safety-ev… · 2026/9/25 3:52:32

如何在3分钟内用VidBee搞定视频格式转换:MP4、MKV、WEBM互转新手完整指南
如何在3分钟内用VidBee搞定视频格式转换:MP4、MKV、WEBM互转新手完整指南

如何在3分钟内用VidBee搞定视频格式转换:MP4、MKV、WEBM互转新手完整指南 【免费下载链接】VidBee Download video and audio from YouTube , TikTok , Twitter , Instagram , Facebook , Twitch , Bilibili , and 1000 sites—or import local media. Create searc… · 2026/9/25 3:52:31

AI搜索GEO工程化落地:知识库、Schema与信源监测的闭环实践
AI搜索GEO工程化落地:知识库、Schema与信源监测的闭环实践

过去三个多月,我一直待在上海,帮一家做工业设备的企业客户跑AI搜索GEO工程化项目。客户预算不算大,但要求很明确:不管用户在哪个AI搜索引擎里问行业问题,品牌都要稳定出现在候选答案里,最好还能点开来源就直… · 2026/9/25 4:24:55

WarriorJS 安装指南:通过 npm 全局安装 CLI 并创建你的第一个战士
WarriorJS 安装指南:通过 npm 全局安装 CLI 并创建你的第一个战士

教育CLI 【免费下载链接】warriorjs 🏰 An exciting game of programming and Artificial Intelligence 项目地址: https://gitcode.com/gh_mirrors/wa/warriorjs 点击查看 免费下载 本篇技术指南讲解 WarriorJS(一款在 JavaScript/TypeScri… · 2026/9/25 4:24:55

Kindle Voyage不能刷安卓?用ADB调试桥解锁隐藏玩法
Kindle Voyage不能刷安卓?用ADB调试桥解锁隐藏玩法

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:24:55

CarSim安装避坑指南:从环境准备到Simulink联合仿真配置
CarSim安装避坑指南:从环境准备到Simulink联合仿真配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 4:24:55

生产级Agent沙箱设计:选型、持久化与执行协议全解析
生产级Agent沙箱设计:选型、持久化与执行协议全解析

1. 为什么本地跑通的沙箱,一上生产就翻车先说个我们踩过的场景。最开始做 Agent 的时候,团队里每个人都在自己电脑上跑代码沙箱,主要就是拿 Docker 跑个容器,把 LLM 生成的代码丢进去执行,本地看起来一切正常。但等到要… · 2026/9/25 4:24:48

ASP.NET Core 集成 MCP:让 AI 直接调用你的接口
ASP.NET Core 集成 MCP:让 AI 直接调用你的接口

1. 为什么要把 .NET 接口暴露给 AI1.1 从一个真实痛点说起去年底我接手了一个内部工单系统的维护工作,前端同事跑过来跟我说:“能不能让 AI 直接帮我查工单状态?我不想每次都在 Swagger 页面里翻接口、填参数、点 Try it out。”当时我的第一… · 2026/9/25 4:24:48

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码