尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

芯片制造CAD图纸在TinyMCE中的矢量输出与嵌入方案

芯片制造CAD图纸在TinyMCE中的矢量输出与嵌入方案 芯片制造企业的技术文档流程里CAD图纸几乎是绕不开的硬通货版图设计说明、工艺异常分析报告、设备改造验收记录、封装结构评审表……这些文档过去要么打印签字要么用Office排版后分发但近几年大家都往在线协同平台搬。搬到网页端之后问题立刻冒出来——如何把CAD图纸粘贴到TinyMCE这类富文本编辑器里还能保持矢量输出而不是变成一张放大就模糊的位图这个问题我前前后后踩了小半年坑今天把完整思路和可落地方案整理出来希望对同样在搞芯片行业在线文档系统的朋友有帮助。在展开技术细节之前先说清楚这套方案能解决什么让工程师在TinyMCE里直接插入CAD视图保存后仍然是矢量格式支持无损缩放、打印、导出Word/PDF时保持线条清晰同时兼顾图纸版本管理和内网数据安全。适合文档系统开发人员、企业IT工程师、以及所有被网页里放高清图纸折磨过的人参考。1. 为什么芯片制造企业要死磕CAD矢量输出1.1 芯片制造场景中的CAD图纸到底长什么样芯片制造企业里的CAD图纸和普通机械加工行业的零件图有很大区别。不是一张A3纸上画几个视图、标注几行尺寸那么简单而是包含大量细密图形的复合工程图。我用实际碰到的三类典型图纸来说明。第一类是版图级的Layer视图。做工艺整合或良率分析的同事经常需要在技术文档里贴出某个金属层或者多晶硅层的图形。这种DXF导出之后线宽可以细到0.05mm甚至更细图面上几十万个矩形、多边形叠在一起。你用截图工具整个框选保存成PNG可能一张图就二三十兆传上去系统直接就卡死了。第二类是工艺流程图和设备腔体结构图。比如刻蚀机的反应腔示意图、CVD设备的管路分布图。这类图纸的标注特别多有大量中文注释、引线、符号标记。截图之后只要一缩放标注文字就发虚。这个问题在评审会上特别尴尬——投到大屏幕上领导问这个尺寸标注怎么看不清。第三类是封装和测试相关的工装治具图。比如探针卡的结构图、测试座的开孔尺寸图。这类图纸尺寸标注密集往往需要放大到局部去看形状公差。如果文档里嵌入的是位图放大后完全没法做测量参考失去意义。1.2 位图和矢量图的底层差距以及为什么截图方案必然失败位图也叫栅格图本质是一个个像素点排列起来。一张300dpi的A4纸大小位图像素数量大约是2480乘3508。看起来已经很密了但一旦放大到200%甚至400%马赛克就露出来了。在芯片图纸这种线条极细的场景下一根0.05mm的线在300dpi位图里只有大约6个像素宽放大后根本看不清边缘更别说做精细的目检了。矢量图则完全不同。SVG里记录的是一条条路径、坐标点和数学曲线不管你怎么缩放渲染引擎都可以重新计算每个像素的颜色。就好比你告诉程序从坐标(10,20)到坐标(120,45)画一条直线程序永远用最新的设备分辨率去画这条线所以任意放大都保持清晰。这带来的实际差异打印A4工艺卡片和打印A0评审挂图同一份SVG源文件都能输出清晰结果而位图需要针对不同打印精度准备不同分辨率的版本。单从这一点芯片行业的知识文档就必须走矢量路线。1.3 TinyMCE默认机制为什么不适合CAD图纸TinyMCE是业界用得最广的富文本编辑器之一但它默认对图片的处理逻辑是你怎么把图片拿来我就怎么把图片存下来。从剪贴板粘贴图片时浏览器会把选择区域渲染成PNG格式的位图然后TinyMCE将其转成Base64字符串塞进img标签。在这个过程里CAD图纸原有的矢量信息被彻底丢弃只剩下平面的像素点。更麻烦的是TinyMCE默认的HTML schema里压根不允许SVG标签。就算你从某个网页复制了一段完整的SVG代码粘贴进编辑器TinyMCE也会把svg、path这些标签当作非法元素过滤掉最后只留下一堆无从渲染的路径字符串。也就是说不经过任何配置CAD图纸在TinyMCE里的宿命就是变成一张大位图或者干脆变成乱码文本。所以解决问题的核心思路很简单让TinyMCE认识并允许SVG同时在后端做好格式转换。这样CAD图纸就能够在网页端以矢量格式被编辑、保存和输出。2. TinyMCE中实现CAD矢量输出的技术路径2.1 为什么选择SVG作为统一输出格式CAD图纸的原始格式种类不少。芯片行业中常见的是DWG和DXF电子设计自动化工具EDA还经常导出GDS或OASIS另外PDF也很常见。要做统一处理必须先选一个网页端能原生渲染、又保留矢量信息的中间格式。对比之后SVG是唯一解。格式浏览器直接渲染矢量信息保留TinyMCE嵌入难易度备注DWG否是极高AutoCAD专有格式需要转换组件DXF否是高CAD交换格式较开放可直接解析PDF可显示但无法内联编辑是高可作为预览图但不适合嵌入编辑GDS/OASIS否是极高版图专用格式需要专业工具链SVG是是低纯XML文本浏览器原生支持SVG本身就是XML语法说白了就是一段有特定结构的HTML标签。它可以直接嵌入HTML文档中成为DOM的一部分也可以作为独立文件被img标签引用。更重要的是SVG支持坐标变换、图层、文字、样式和CAD的图元模型天然接近互转时信息损失最小。2.2 核心架构思路我在内部文档平台上采用的架构分四层。最底层是CAD源文件存储区存DXF/DWG原始文件只允许特定服务访问。第二层是转换服务负责把源文件转换成SVG字符串。第三层是TinyMCE编辑器经过配置后接受SVG内联内容并随文档一起保存。第四层是输出服务负责把文档导出成PDF或者Word时对SVG做进一步处理。整个链路的关键决策是转换必须在服务器端完成而不是前端。原因有两个。其一前端解析DWG这种二进制格式几乎没有靠谱的开源方案DXF解析库虽然有一些但兼容性和效率都不尽如人意。其二芯片图纸是机密程度很高的数据资产不应该把源文件下发到每个工程师的浏览器里转换在服务器完成前端只拿到渲染后的SVG视图安全边界清晰得多。2.3 TinyMCE嵌入SVG的三种方式对比把SVG弄进TinyMCE有几种方式各有利弊。我在实际项目里都试过简单对比一下。方式一SVG保存为独立文件通过img标签的src属性引用。优点是实现简单浏览器有自己的图片缓存机制加载性能好。缺点是TinyMCE编辑时看到的是图片框双击无法编辑内部图元SVG文件必须和文档一起管理迁移时容易漏掉。方式二把SVG代码作为内联HTML直接塞进TinyMCE的编辑区域。这是我最推荐的方式。SVG成为文档DOM的一部分保留全部矢量信息任意缩放也可以用简单的工具脚本修改图元属性。缺点是需要额外配置TinyMCE的valid_elements同时要做好XSS安全过滤。方式三把SVG转成Base64 data URI后塞进img标签的src。优点是编辑器不需要做任何标签放行配置当作普通图片处理即可。缺点是Base64会让体积增加大约33%而且SVG被编码成字符串后编辑和维护都不方便等于放弃了矢量格式的动态能力。综合来看芯片制造企业的文档系统里图纸是要长期维护、多次复审、反复导出的方式二最合适。2.4 不同TinyMCE版本的兼容性说明TinyMCE从4.x到现在的7.x配置API发生过不少变化。早期4.x和5.x用extended_valid_elements就能放行SVG标签但从6.x开始schema校验更严格了光配置extended_valid_elements还不够必须同时配置custom_elements否则一些SVG自闭合标签或者其他内置标签还是会被吞掉。另外粘贴事件的处理API也不同。5.x里常用paste_preprocess回调在粘贴内容进入编辑器之前拦截并修改HTML。6.x之后虽然仍然支持这个回调但推荐使用editor.on(PastePreProcess, fn)的写法。我在项目中锁定的是TinyMCE 6.x版本下面的配置示例都以6.x为准。如果还在维护老系统需要根据版本微调。3. 从CAD到SVG的转换实操3.1 工具链选型与取舍CAD文件转SVG第一步是选转换工具。我按照使用场景把工具分成三类。单张图纸少量处理最直接的办法是打开AutoCAD另存为或通过打印功能输出SVG也可以用Illustrator打开DXF后导出SVG。缺点是人工操作效率低如果每天有几十张图纸更新根本忙不过来。批量转换必须走脚本。Python生态里最成熟的库是ezdxf它对DXF格式支持非常好从R12到R2018版本都能解析而且能保留图层、线型、块引用等关键信息。Node.js环境下我试过dxf-parser做简单解析没问题但出图质量一般依赖维护也不太活跃。还有一种情况是DWG尤其老版本DWG。开源的DWG解析库很少我绕开这个问题的方法是要求上游先用AutoCAD或ODA File Converter把DWG统一转成DXF或DXF打包。ODA是免费的开源转换器可以命令行调用适合做个定时批量任务。我的经验是能用DXF解决的就别直接碰DWGDXF的文档完善也容易自动化。3.2 基于Python ezdxf的批量转换脚本ezdxf从0.16版本开始提供了SVG后端可以直接把DXF模型空间渲染成SVG。我封装了一个内部调用的转换函数核心代码很短。import ezdxf from ezdxf.addons.drawing import RenderContext, Frontend from ezdxf.addons.drawing.svg import SVGBackend def dxf_to_svg(dxf_path, svg_path, scale1.0): # 读取DXF支持R12到R2018 doc ezdxf.readfile(dxf_path) msp doc.modelspace() # 渲染上下文 ctx RenderContext(doc) backend SVGBackend() frontend Frontend(ctx, backend) # 绘制模型空间中的所有实体 frontend.draw_layout(msp) # 获取SVG字符串并写入文件 svg_content backend.get_string() with open(svg_path, w, encodingutf-8) as f: f.write(svg_content)这段代码在大多数场景下能直接跑通。RenderContext负责把DXF的图层属性、颜色、线型映射到SVG的样式属性里SVGBackend负责构建SVG DOM结构Frontend相当于一个照相机把模型空间的内容渲染到后端。如果转换大型版图建议在调用frontend.draw_layout之前用msp的查询接口按需过滤实体比如只保留需要的图层能极大降低后续SVG的复杂度。3.3 转换时的关键配置线宽、单位、字体、图层实际操作中真正影响图纸质量的不是那几行转换代码而是这几个容易被忽略的配置项。线宽映射是最容易踩的坑。DXF里每根线都可以有自己的线宽属性芯片图纸经常用到极细的线。如果转换时不开启线宽所有线条会统一使用默认宽度图面看起来就像一根根粗管子完全没有精细感。ezdxf里需要让SVG后端读取线宽可以用Frontend的配置或者对SVG做后处理。最简单的方式是遍历SVG中的path元素把stroke-width属性根据源线宽重新赋值对于0.05mm以下的线条统一映射到0.1px既能看清又不会糊成一片。单位换算也相当重要。芯片图纸常见的单位是微米和纳米而SVG默认长度单位是像素。转换前我通常会检查doc.units拿到DXF的单位设置如果是微米就乘以一个比例因子换算成px。比如1微米在屏幕上显示为0.003px这个值太小了所以一般还要额外设置一个文档级缩放倍数比如整体放大100倍或更多保证在编辑器中打开时能看到适中的图形大小。字体是另一个大头。图纸里的中文标注转换服务器上如果没有安装对应字体渲染出来的SVG就是一个个方框。我在Ubuntu服务器上执行过apt-get install fonts-noto-cjk装了Noto字体后才恢复正常。转换时最好在SVG的根节点上显式指定font-familyNoto Sans CJK SC避免浏览器用默认字体乱套。图层颜色的保留也不容忽视。芯片设计行业对图层颜色有一定约定比如金属层用金色或红色多晶硅层用绿色有源区用蓝色。转换时如果丢失了这些颜色工程师看文档会非常别扭。ezdxf的RenderContext默认会读取图层颜色但如果源文件里实体覆盖了颜色要保证那些RGB值原样进入SVG的stroke和fill属性。3.4 转换质量如何验证转换完成后不能只看一眼就说能显示就行。我在实际流程里加了两个层面的验证。第一层是程序化校验。解析原DXF统计实体数量、图层数量、标注数量再用Python的xml.etree.ElementTree解析生成的SVG统计path、text等节点数量。两者对比如果差异超过阈值就说明转换过程丢了内容需要介入检查。这个校验脚本可以接进CI流程每次批量转换后自动跑。第二层是人工抽检。把SVG在浏览器里打开缩放到500%检查线条边缘是否平滑、文字是否清晰、图层颜色是否符合预期。芯片图纸的精细度要求很高我见过不少SVG在100%缩放下看着没问题一放大就原形毕露的情况。4. 在TinyMCE中配置SVG嵌入与安全策略4.1 通过valid_elements开放SVG标签要让TinyMCE接收并保留SVG必须在初始化配置里显式放行SVG相关标签。TinyMCE 6.x的配置如下。tinymce.init({ selector: #editor, custom_elements: svg|path|g|defs|line|rect|circle|ellipse|polyline|polygon|text|tspan|use|symbol|marker|linearGradient|radialGradient, extended_valid_elements: svg[*],path[*],g[*],defs[*],line[*],rect[*],circle[*],ellipse[*],polyline[*],polygon[*],text[*],tspan[*],use[*],symbol[*],marker[*],linearGradient[*],radialGradient[*],stop[*],desc[*],title[*], valid_styles: { *: fill,stroke,stroke-width,opacity,transform,font-family,font-size,font-weight,font-style }, paste_data_images: true });这里需要注意extended_valid_elements里的[*]表示允许所有属性。如果为了安全不想放开全部属性可以写具体白名单比如svg[width|height|viewBox|xmlns]。custom_elements这行也很关键它告诉TinyMCE这些标签属于自定义元素不会套用HTML5标准schema的校验逻辑。还有一点容易忽略SVG内部有很多样式是通过CSS属性写的比如fill: #FF0000。TinyMCE默认清理模式会删掉不认识的style属性或者把内联样式重排。所以我用valid_styles开放了所有必要的CSS属性否则保存后再打开图形颜色和线条宽度可能全部丢失。4.2 拦截粘贴事件保留SVG源码工程师从内部SVG浏览器或者设计工具里复制SVG时剪贴板内容形式多种多样有些是真正的SVG HTML代码有些是渲染后的位图。为了让SVG源码能被保留我在TinyMCE初始化时增加了PastePreProcess事件处理。editor.on(PastePreProcess, function(e) { var html e.content; if (html.indexOf(svg) -1) { // 如果粘贴内容包含SVG根节点放行不做过滤 return; } // 如果不是SVG走默认处理 });这个处理逻辑的核心是检测到SVG时直接跳过TinyMCE默认的消毒清洗流程。如果不加这个判断TinyMCE会在内部把svg当作未知标签剥离掉。但注意一点放行的同时安全责任就转移到后端了。前端拦截只解决能不能保留的问题保留的内容是否安全必须在服务端判定。原理很简单SVG本质是XML可以内嵌script脚本如果直接存储并在页面回显可能触发XSS攻击。4.3 服务端存储与回显设计文档保存时editor.getContent()会返回整个HTML。我在后端用Python做了一层SVG提取和清洗。from bs4 import BeautifulSoup import re def extract_and_clean_svg(html_content): soup BeautifulSoup(html_content, html.parser) svg_nodes soup.find_all(svg) for svg in svg_nodes: # 移除所有script节点 for script in svg.find_all(script): script.decompose() # 移除所有on事件属性 for tag in svg.find_all(True): for attr in list(tag.attrs): if attr.startswith(on): del tag[attr] # 移除外部实体引用防止XXE for tag in svg.find_all(True): for attr in list(tag.attrs): if attr in [href, xlink:href]: value tag[attr] if value.startswith(http) or value.startswith(data:): pass elif not value.startswith(#): del tag[attr] return str(soup)回显时把清洗后的SVG重新组装到文档HTML里直接传给TinyMCE的setContent()方法或者作为初始内容。这里有一个额外注意点SVG里如果使用了use标签引用内部的symbolid要保持全局唯一否则同一页面有多个SVG时可能出现引用错乱。存储方案上我采用动静分离——整个HTML文档存入数据库的text字段SVG同时抽离成独立文件放入对象存储并生成一个版本号关联到文档主记录。这样既方便全文检索也方便单独做SVG的版本对比。4.4 导出Word/PDF时的矢量保真方案TinyMCE编辑器的浏览体验解决了但文档最终要交付、要打印必须导出成PDF或Word。PDF这块最简单直接用浏览器打印功能Chrome/Edge在打印时会把SVG按矢量方式渲染到PDF里效果非常好。麻烦的是Word。微软Word对SVG的原生支持很有限实际测试下来老版本Word甚至只显示一个图标。我的处理方式是后端用Pandoc或LibreOffice做HTML到DOCX的转换。转换前把HTML里的SVG先转成高分辨率PNG或者EMF格式再插入文档。EMF是Windows矢量格式Word里显示清晰度不错但生成EMF的库不太好找Linux上转EMF兼容性差一些。所以工程上我妥协为导出Word时把SVG渲染成600dpi的PNG输出DOCX清晰度足够打印需求导出PDF时直接用SVG矢量渲染保证大屏和印刷的最高质量。如果你用了TinyMCE的第三方Word导出插件也要注意它内部对SVG的处理逻辑很多插件并不认识SVG会原样输出标签或者直接丢弃。我最后放弃了插件全部走后端转换反而更可控。5. 常见问题与排查实录5.1 SVG在编辑器里显示空白这个现象非常常见解决办法却藏在细节里。最常见的原因是SVG根节点缺少xmlns属性。有些转换工具生成的SVG本身就没带命名空间浏览器在独立打开时能自动补全但作为内联HTML嵌入时没有命名空间的svg会被当作未知元素不会渲染。解决办法是在转换脚本里强制给SVG根节点加上xmlnshttp://www.w3.org/2000/svg。另一个原因是SVG的width/height为0。DXF模型空间如果原点不统一有的图纸绘制离原点特别远转换后的viewBox范围也会偏移。遇到这种图应该手动计算所有实体的包围盒用viewBoxminX minY width height去设置并给width/height一个默认值比如100%和100%。5.2 粘贴SVG代码被TinyMCE过滤得残废我曾经调试过一个诡异情况粘贴进来的SVGpath标签全部不见了只剩下一堆数字文本。查了半天发现TinyMCE的extended_valid_elements配置里写了path[*]但实际TinyMCE 6.x对于SVG子元素还有一套内部白名单需要在custom_elements里也同样放行。只写extended_valid_elements不够两个必须配合使用。还有一种情况是粘贴时浏览器把SVG转换成了data:image/svgxml;base64,...格式。这种其实是好消息说明浏览器识别了SVG但TinyMCE如果开启了paste_data_images会直接把它当作图片插入最终仍是位图效果。排查时可以打开浏览器开发者工具看到底粘贴的是什么MIME类型再有针对性地处理。5.3 中文字体乱码与缺失芯片图纸中中文标注的比例相当高。转换服务器如果是精简版Linux镜像没有中文字体渲染出来的SVG里中文全部变成方框。这个问题的隐蔽之处在于转换程序本身不报错代码正常执行SVG也能打开但图面上全是豆腐块。解决办法分两步。第一步在转换服务器上安装中文字体Ubuntu/Debian系统执行apt-get install -y fonts-noto-cjkCentOS可以安装wqy-microhei或者wqy-zenhei。第二步在SVG根节点上显式声明字体族或者在转换配置里指定字体匹配规则。否则就算服务器装了字体浏览器如果找不到对应用户电脑字体最终还是乱码。如果你的图纸标注里既有中文又有英文最好把中文字体设置为Noto Sans CJK SC英文字体设置为Arial字体回退顺序明确写在CSS里。5.4 图纸太大导致编辑器卡顿芯片全版图级别的DXF转换成SVG后DOM节点数量可能达到几十万个。TinyMCE一次渲染这么多节点浏览器直接卡死。我在项目里遇到过用户粘贴超大SVG后页面无响应的情况后来被迫做了三层优化。第一层是源头限制。转换服务在服务器端就做图层过滤默认只保留核心图层像示意图这类文档根本不需要把所有金属层都塞进去。第二层是简化路径。用简单的折线拟合算法减少路径节点把曲线和密集多边形的节点数压缩到可接受范围。第三层是前端懒加载。编辑器外先显示一张低分辨率PNG预览图用户点击加载矢量图后再把真正的SVG渲染到TinyMCE中。这样编辑器的初始加载速度提升明显也不牺牲最终输出质量。5.5 保存后再打开SVG被重排或丢失样式这个问题的根源在TinyMCE内容规范化。TinyMCE在getContent()和setContent()过程中会对HTML做一系列清洗包括重新排序属性、删减冗余样式、合并嵌套标签。SVG作为一种XML方言很多写法在TinyMCE看来是不合规的。比如fill-rule这种带连字符的属性TinyMCE可能认为它不是合法style而删除。解决办法是在valid_styles里明确列出所有会用到的SVG样式属性并且尽量把样式写成SVG属性而非CSS例如用fill、stroke、stroke-width这些XML属性而不是stylefill:...。转换脚本在生成SVG时就应该注意输出成属性形式这样经过TinyMCE多轮清洗也不容易丢失。6. 芯片制造场景下的部署建议6.1 数据安全与访问控制芯片图纸的敏感性不用多说属于企业核心资产。部署这套系统时转换服务必须放在内网严格限制访问来源绝不能暴露到公网。文档系统本身的权限模型也要做细粒度控制至少要能控制到文档目录级别甚至单张图纸级别。另外SVG文件本身可能会携带隐藏信息。DXF转SVG时如果没清理元数据绘图软件的名称、创建人、创建时间、文件路径都可能残留在SVG的metadata标签里。我建议在转换脚本最后一步统一移除这些元数据只保留图纸内容本身。还要注意SVG的XSS风险。虽然我在后端做了清洗但安全是纵深防御前端也不能完全放开。建议在TinyMCE初始化时集成DOMPurify作为额外的消毒层双重保险。6.2 版本管理与图纸一致性芯片版图一天一个版本工艺调整随时可能发生。如果文档系统里的图纸是工程师手动上传的几乎必然出现文档里的图已经过期两周的情况。我的做法是把转换服务和PDM系统打通PDM中审批通过的DWG/DXF自动触发转换生成SVG后推送到文档系统工程师在TinyMCE里只能引用这些受控的SVG不能自行上传。SVG内部也建议烙上版本标识。最简单的方式是在SVG的根节点下添加一个metadata元素写入图纸号、版本、转换时间、校对人。这样即使文档被到处复制看到图纸的人也能追溯图源和版本减少扯皮。6.3 性能监控与缓存策略批量转换服务上线后要关注三个指标单张图纸转换耗时、SVG生成体积、转换失败率。芯片版图DXF文件动辄几十上百兆转换耗时可能从几秒到几分钟不等如果并发处理服务器内存和CPU都会吃紧。我的做法是加一个任务队列转换请求先入队工作进程按队列顺序处理避免突发流量打爆服务。对于相同文件的重复转换用MD5做内容寻址缓存。同一份DXF第一次转换后缓存结果后续请求直接返回缓存的SVG大幅降低CPU占用。缓存策略要注意和PDM版本号联动文件内容变化时自动失效。6.4 多终端兼容与展示降级芯片工厂产线上工程师经常拿iPad或手机查看作业指导书。SVG本身支持触控缩放但TinyMCE编辑器在移动端的编辑体验一般。我的策略是编辑端只在桌面浏览器开放移动端全部走只读模式展示时直接渲染SVG不加载编辑器JS。这样既保证了性能又避免了移动端误操作。对于老旧浏览器尤其是内网环境还存在的旧版Edge甚至IE11内联SVG的兼容性是灾难级。遇到这种终端系统会自动降级为显示服务器预渲染的PNG大图。虽然牺牲了一部分矢量能力但至少保证图纸能看。回到最开始的问题芯片制造企业如何解决CAD图纸粘贴到TinyMCE的矢量输出我的答案就是这套服务器端转换SVG加编辑器标签放行加后端安全清洗的组合拳。这条链路里每一步看起来都不复杂但真正跑通并稳定运行需要踩掉的坑远比想象中多。我个人印象最深的是安全清洗和版本管理这两块前者关系到企业核心数据安全后者直接影响图纸交付的准确性。如果你刚起步建议先用Python加ezdxf跑通转换再改TinyMCE配置最后补安全清洗和监控一步一步来别想着一步到位。另外提个醒TinyMCE版本差异很大网上搜到的老配置别直接抄先确认自己用的是什么版本不然光无效配置就能耗掉你大半天。
返回列表