2025-07-25 13:28:47 +08:00
< template >
< div class = "editor-container" >
2025-09-15 09:58:52 +08:00
<!-- 左侧操作框 -- >
< div class = "leftDiv" v -if = ' isLoadXml ' :style = "{'maxHeight':leftHeight+'px','minHeight':'100px'}" >
< div id = 'navMain' >
<!-- 操作栏 -- >
< div class = "operation-buttons" >
<!-- 节点搜索框 -- >
< div style = "margin:10px auto;" >
< el-input
placeholder = "输入节点名称搜索"
v - model = "searchText"
class = "search-input"
clearable
@ clear = "handleSearchClear"
@ keyup . enter = "handleSearch" >
< el-button slot = "append" icon = "el-icon-search" @click ="handleSearch" > < / el -button >
< / el-input >
< / div >
<!-- 操作栏按钮 -- >
< img class = 'iconImg' title = '新建' src = "../assets/addIcon.png" @click ="showAddDialog('create')" v -if = ' isLoadXml ' alt = "" >
< img class = 'iconImg' title = '编辑' src = "../assets/editIcon.png" @click ="showAddDialog('edit')" v -if = ' currentNode ' alt = "" >
< img class = 'iconImg' title = '保存' src = "../assets/saveIcon.png" @click ="saveNowDmcClick" v -if = ' currentNode ' alt = "" >
< img class = 'iconImg' title = '删除' src = "../assets/delIcon.png" @click ="deleteDialog" v -if = ' currentNode ' alt = "" >
<!-- < el-button title = '新建' class = 'el-icon-circle-plus-outline' type = "primary" size = "medium" : disabled = '!isLoadXml' @click ="showAddDialog('create')" > < / el -button >
< el-button title = '编辑' class = 'el-icon-edit' type = "primary" size = "medium" @click ="showAddDialog('edit')" :disabled = "!currentNode" > < / el-button >
< el-button title = '保存' class = 'el-icon-files' type = "primary" size = "medium" @click ="saveNowDmcClick" :disabled = "!currentNode" > < / el-button >
< el-button title = '删除' class = 'el-icon-delete' type = "danger" size = "medium" @click ="deleteDialog" :disabled = "!currentNode" > < / el-button > -- >
<!-- < el-button type = "primary" @click ="draggableVis = true" > 打开可拖拽对话框 < / el -button > -- >
2025-07-28 17:01:13 +08:00
2025-09-15 09:58:52 +08:00
<!-- < el-button type = "danger" @click ="queryMaxId" > 查询当前最大ID < / el -button > -- >
< / div >
< div class = "tree-container" >
<!-- < router-link to = "/wangG3" > Wang2 2 页面 < / router-link > -- >
<!-- < button
@ click = "openWangG2InNewWindow"
class = "bg-primary text-white px-4 py-2 rounded-md hover:bg-primary/90 transition-colors"
>
打开wangG2页面
< / button > -- >
<!-- 1. 添加触发按钮 -- >
<!-- < button
class = "check-version-btn"
@ click = "handleCheckVersion"
>
检查版本并显示修改按钮
< / button > -- >
<!-- < button @click ="GetPreviewDataFun" >
全屏的蒙版
< / button > -- >
< div style = " text -align : left ;
font - size : 20 px ;
font - weight : bold ; " @ click = 'clearNodeState' > 目录 < / div >
<!-- < el-button @click ="test" > 替1换 < / el -button > -- >
<!-- < el-tree
class = "elTree"
ref = "tree"
: data = "treeData"
node - key = "id"
highlight - current
: props = "defaultProps"
: filter - node - method = "filterNode"
@ node - click = "handleNodeClick"
@ node - contextmenu = "handleRightClick"
: expand - on - click - node = "false" >
< span class = "custom-tree-node" slot -scope = " { node , data } " >
< span : class = "{ 'highlight': isHighlight(data) }" > { { node . label } } < / span >
< / span >
< / el-tree > -- >
<!-- : props = "defaultProps" -- >
<!-- : default - checked - keys = "[5]" -- >
<!-- < el-tree
class = "elTree"
ref = "tree"
: data = "treeData"
node - key = "id"
icon - class = "el-icon-arrow-right"
: default - expand - all = "true"
: props = "defaultProps"
: filter - node - method = "filterNode"
@ node - click = "handleNodeClick"
@ node - contextmenu = "handleNodeContextMenu"
: expand - on - click - node = "false"
: highlight - current = "true"
>
< span slot -scope = " { data } " >
< template v-if = "data.children" >
< div v-if = "data.children.length > 0" >
< i class = "el-icon-folder" : style = "'font-size: 14px; padding: 0 5px 0 5px'" / >
< span : title = 'data.id+"-"+data.name' : class = "{ 'highlight': isHighlight(data) }" >
{ { data . name } } < / span >
< / div >
< div v-else >
< i class = "leaf-node-line" > < / i >
< i class = "el-icon-document" : style = "'padding: 0 5px 0 5px'" / >
< span : title = 'data.id+"-"+data.name' : class = "{ 'highlight': isHighlight(data) }" >
{ { data . name } } < / span >
< / div >
< / template >
< template v-else >
< div style = "margin-left: 0px;" >
< i class = "leaf-node-line" > < / i >
< i class = "el-icon-document" : style = "'padding: 0 5px 0 5px'" > < / i >
< i : style = "'font-size: 13px; padding: 0 5px 0 5px'" > < svg viewBox = "64 64 896 896" data -icon = " deployment -unit " width = "1em" height = "1em" fill = "currentColor" aria -hidden = " true " focusable = "false" class = "" > < path d = "M888.3 693.2c-42.5-24.6-94.3-18-129.2 12.8l-53-30.7V523.6c0-15.7-8.4-30.3-22-38.1l-136-78.3v-67.1c44.2-15 76-56.8 76-106.1 0-61.9-50.1-112-112-112s-112 50.1-112 112c0 49.3 31.8 91.1 76 106.1v67.1l-136 78.3c-13.6 7.8-22 22.4-22 38.1v151.6l-53 30.7c-34.9-30.8-86.8-37.4-129.2-12.8-53.5 31-71.7 99.4-41 152.9 30.8 53.5 98.9 71.9 152.2 41 42.5-24.6 62.7-73 53.6-118.8l48.7-28.3 140.6 81c6.8 3.9 14.4 5.9 22 5.9s15.2-2 22-5.9L674.5 740l48.7 28.3c-9.1 45.7 11.2 94.2 53.6 118.8 53.3 30.9 121.5 12.6 152.2-41 30.8-53.6 12.6-122-40.7-152.9zm-673 138.4a47.6 47.6 0 0 1-65.2-17.6c-13.2-22.9-5.4-52.3 17.5-65.5a47.6 47.6 0 0 1 65.2 17.6c13.2 22.9 5.4 52.3-17.5 65.5zM522 463.8zM464 234a48.01 48.01 0 0 1 96 0 48.01 48.01 0 0 1-96 0zm170 446.2l-122 70.3-122-70.3V539.8l122-70.3 122 70.3v140.4zm239.9 133.9c-13.2 22.9-42.4 30.8-65.2 17.6-22.8-13.2-30.7-42.6-17.5-65.5s42.4-30.8 65.2-17.6c22.9 13.2 30.7 42.5 17.5 65.5z" > < / path > < / svg > < / i >
< span : title = 'data.id+"-"+data.name' : class = "{ 'highlight': isHighlight(data) }" >
{ { data . name } } < / span >
< / div >
< / template >
< / span >
< / el-tree > -- >
<!-- 2. 树组件 ( 修改节点渲染逻辑 ) -- >
< el-tree
class = "elTree"
ref = "tree"
: data = "treeData"
node - key = "id"
icon - class = "el-icon-arrow-right"
: default - expand - all = "true"
: props = "defaultProps"
: filter - node - method = "filterNode"
@ node - click = "handleNodeClick"
@ node - contextmenu = "handleNodeContextMenu"
: expand - on - click - node = "false"
: highlight - current = "true"
>
<!-- 节点自定义渲染插槽 -- >
< span slot -scope = " { data } " >
<!-- ( 1 ) 原有节点图标 + 名称渲染逻辑 -- >
< template v-if = "data.children && data.children.length > 0" >
<!-- 父节点 ( 有子节点 ) -- >
< div >
< i class = "el-icon-folder" : style = "'font-size: 14px; padding: 0 5px 0 5px'" / >
< i class = "el-icon-warning changeState" @click.stop ="handleModify(data)" v-if = "showModifyBtn && hasMinorVersion01(data)" :style="'font-size: 14px; padding: 0 5px 0 5px'" />
< span : title = "data.id + '-' + data.name" : class = "{ 'highlight': isHighlight(data) }" >
{ { data . name } }
< / span >
<!-- ( 关键 ) 条件显示 【 修改 】 : 检查状态开启 + 当前节点 / 子节点有minorVersion : 01 -- >
<!-- < span
class = "modify-btn"
v - if = "showModifyBtn && hasMinorVersion01(data)"
@ click . stop = "handleModify(data)"
>
【 修改 】
< / span > -- >
< / div >
< / template >
< template v-else >
<!-- 叶子节点 ( 无子节点 ) -- >
< div style = "margin-left: 0px;" >
< i class = "leaf-node-line" > < / i >
< i class = "el-icon-document" : style = "'padding: 0 5px 0 5px'" > < / i >
<!-- < svg viewBox = "64 64 896 896" data -icon = " deployment -unit " width = "1em" height = "1em" fill = "currentColor" aria -hidden = " true " focusable = "false" class = "" >
< path d = "M888.3 693.2c-42.5-24.6-94.3-18-129.2 12.8l-53-30.7V523.6c0-15.7-8.4-30.3-22-38.1l-136-78.3v-67.1c44.2-15 76-56.8 76-106.1 0-61.9-50.1-112-112-112s-112 50.1-112 112c0 49.3 31.8 91.1 76 106.1v67.1l-136 78.3c-13.6 7.8-22 22.4-22 38.1v151.6l-53 30.7c-34.9-30.8-86.8-37.4-129.2-12.8-53.5 31-71.7 99.4-41 152.9 30.8 53.5 98.9 71.9 152.2 41 42.5-24.6 62.7-73 53.6-118.8l48.7-28.3 140.6 81c6.8 3.9 14.4 5.9 22 5.9s15.2-2 22-5.9L674.5 740l48.7 28.3c-9.1 45.7 11.2 94.2 53.6 118.8 53.3 30.9 121.5 12.6 152.2-41 30.8-53.6 12.6-122-40.7-152.9zm-673 138.4a47.6 47.6 0 0 1-65.2-17.6c-13.2-22.9-5.4-52.3 17.5-65.5a47.6 47.6 0 0 1 65.2 17.6c13.2 22.9 5.4 52.3-17.5 65.5zM522 463.8zM464 234a48.01 48.01 0 0 1 96 0 48.01 48.01 0 0 1-96 0zm170 446.2l-122 70.3-122-70.3V539.8l122-70.3 122 70.3v140.4zm239.9 133.9c-13.2 22.9-42.4 30.8-65.2 17.6-22.8-13.2-30.7-42.6-17.5-65.5s42.4-30.8 65.2-17.6c22.9 13.2 30.7 42.5 17.5 65.5z" > < / path >
< / svg > -- >
<!-- < i : style = "'font-size: 13px; padding: 0 5px 0 5px'" >
< / i > -- >
< i class = "el-icon-warning changeState" @click.stop ="handleModify(data)" v-if = "showModifyBtn && hasMinorVersion01(data)" :style="'font-size: 14px; padding: 0 5px 0 5px'" />
< span : title = "data.id + '-' + data.name" : class = "{ 'highlight': isHighlight(data) }" >
{ { data . name } }
< / span >
<!-- ( 关键 ) 叶子节点同样条件显示 【 修改 】 -- >
<!-- < span
class = "modify-btn"
v - if = "showModifyBtn && hasMinorVersion01(data)"
@ click . stop = "handleModify(data)"
>
【 修改 】
< / span > -- >
< / div >
< / template >
< / span >
< / el-tree >
< div class = "mask" v -if = ' dmcChangeState ' > < / div >
< / div >
< / div >
<!-- < div id = 'nav' >
< nav-temp / >
< / div > -- >
< / div >
< div class = "rightDiv" >
< div class = "toolbar" style = "display:none;" >
< button @ click = 'dmcIsChange' > 判断富文本内容是否更改 < / button >
< button @click ="ceshi()" > 测试拼接地址 < / button >
< button @ click = 'jzml' > 加载目录 < / button >
< button @ click = 'catalogueAnalysis(treeData)' > 存目录 < / button >
<!-- < button @ click = 'catalogueAnalysis(treeData)' > 拼接目录字符串 < / button > -- >
< input type = "text" v-model = "val1" >
< button @ click = 'loadFWBFile' > 读取富文本 < / button >
< button @click ="insertImage()" > 上传图片4 < / button >
< button @click ="insertVideo()" > 上传视频 < / button >
< button @click ="insertAudio()" > 上传音频 < / button >
< button @click ="loadAllContent" > 加载所有内容 < / button >
< button @click ="processHeadingIds" > 生成目录 < / button >
< button @click ="openDialog" > 查看图片 < / button >
<!-- generateTOC -- >
< button @click ="enableContextMenu" > 启用右键菜单功能 < / button >
< button @click ="logTocItems" > 打印目录数据 < / button >
<!-- < input type = "color" v-model = "colors" > - - >
<!-- < button @click ="deleteAllVideos" > 删除所有视频 < / button > - - >
< button @click ="loadFwb" > 加载到富文本框内 < / button >
<!-- < button @ click = 'test' > 测试 < / button > -- >
2025-07-28 17:01:13 +08:00
< / div >
2025-09-15 09:58:52 +08:00
< div class = "button-group" style = "display:none;" >
< button @click ="generateXml(false)" > 保存内容到XML < / button >
< button @click ="navXml" > 保存目录到XML < / button >
< button @click ="loadXml" > Load XML < / button >
< input type = "file" ref = "fileInput" @change ="handleFileUpload" style = "display: none" accept = ".xml" / >
< / div >
< div class = "s1000d-editor-container" >
<!-- 工具栏 -- >
< div class = "toolbar" style = "display:none;" >
< button @click ="exportToS1000D" class = "tool-btn" > 导出S1000D XML < / button >
< label for = "xml-upload" class = "tool-btn" > 导入S1000D XML < / label >
< input
id = "xml-upload"
type = "file"
accept = ".xml"
@ change = "handleS1000DUpload"
style = "display: none"
/ >
< button @click ="validateCurrentXml" class = "tool-btn" > 验证XML < / button >
< / div >
<!-- 编辑器区域 -- >
< div class = "editor-area" style = "display:none;" >
< div ref = "editor" class = "editor" > < / div >
< div class = "xml-preview" style = "display: none" >
< h3 > XML预览 < / h3 >
< pre > { { formattedXmlPreview } } < / pre >
< / div >
< / div >
< / div >
< div id = "main" class = "content-preview" style = "display:none;" > { { editorHeight } } < / div >
<!-- v - show = 'currentNode' -- >
< div id = "editor" v -show = ' currentNode ' :style = "{height:editorHeight+'px'}" ref = "editor" : class = "{ editor2Opacity: dialogVisibleNav||dialogVisibleNavDel|| dialogVisible||dialogVisibleImg||dialogVisibleRight||dialogVisibleTips||dialogVisibleBland||dialogVisibleHistory||dialogVisibleTips2 }" > < / div >
< div v-show = "!currentNode && isLoadXml" > 请打开所要编辑的的章节目录 < / div >
< div v-show = "!isLoadXml" > 请加载所要编辑的文档目录 < / div >
<!-- < div > { { tempDivData . innerHTML } } < / div >
< div id = "editor2" ref = "editor2" > < / div > -- >
<!-- < input type = "text" v-model = "val2" > - - >
<!-- < button @click ="sendMessageToHost('李四','张三')" > 传递 < / button > - - >
< / div >
< el-dialog
title = "弹窗操作"
: visible . sync = "dialogVisibleRight"
width = '580px'
class = "custom-dialog"
: before - close = "handleClose" >
< div class = "attribute-selection" >
< el-button @click ="showAddDialog('edit')" > 编辑目录 < / el -button >
< el-button @ click = 'showBand' > 绑定资源 < / el-button >
< el-button @click ="showHistory" > 历史版本 < / el -button >
< el-button @click ="deleteDialog" type = "danger" > 删除目录 < / el-button >
< / div >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisibleRight = false" > 关闭 < / el -button >
<!-- < el-button type = "primary" @click ="catalogueAnalysis(treeData)" > 选择绑定资源 < / el -button > -- >
< / span >
< / el-dialog >
< el-dialog
title = "历史版本"
: visible . sync = "dialogVisibleHistory"
width = '80%'
class = "custom-dialog"
: before - close = "handleClose" >
< div class = "attribute-selection" v -if = ' historyData ' >
< div class = 'zyBox' style = "text-align: left;" v-for = "(item,index) in historyData" :key="index" >
< p > 版本名称 : { { item . Name } } < / p >
< p > 修改时间 : { { timeChange ( item . CreationTime ) } } < / p >
< p > 文件路径 : { { item . Path } } < / p >
< el-button @ click = 'lookHistoryFile(item.Path)' > 查看历史版本 < / el-button >
2025-07-28 17:01:13 +08:00
< / div >
2025-09-15 09:58:52 +08:00
< / div >
< div class = "attribute-selection" v -if = ' historyData.length = = 0 ' >
暂无历史版本
< / div >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisibleHistory = false" > 关闭 < / el -button >
<!-- < el-button type = "primary" @click ="catalogueAnalysis(treeData)" > 选择绑定资源 < / el -button > -- >
< / span >
< / el-dialog >
<!-- 右键菜单弹窗 -- >
< el-dialog
title = "绑定资源"
class = "custom-dialog"
: visible . sync = "dialogVisibleBland"
width = "50%"
: before - close = "handleClose" >
< div class = "attribute-selection" v-if = "currentNode&¤tNode.attributes.length > 0" >
< p > 已绑资源 : < / p >
<!-- 属性展示区域 -- >
< div v -if = ' currentNode ' class = 'bindMain' >
< div class = "zyBox" v-for = "(item,index) in currentNode.attributes" :key="index" >
< p > { { item } } < / p >
< el-button type = "danger" size = "mini" @click ="deleteAttr(item,index)" :disabled = "!currentNode" > 删除 < / el-button >
< / div >
< / div >
< / div >
< div v-else > 暂未绑定资源 < / div >
< span slot = "footer" class = "dialog-footer" >
< el-button @ click = 'saveAttributes' > 选择绑定资源 < / el-button >
< el-button @click ="dialogVisibleBland = false" > 关闭 < / el -button >
<!-- < el-button type = "primary" @click ="catalogueAnalysis(treeData)" > 选择绑定资源 < / el -button > -- >
< / span >
< / el-dialog >
<!-- < div
v - if = "contextMenu.visible"
class = "context-menu"
: style = " {
left : ` ${ contextMenu . x } px ` ,
top : ` ${ contextMenu . y } px `
} "
@ click . stop
>
< div
v - for = "option in menuOptions"
: key = "option"
class = "menu-item"
: class = "{ active: contextMenu.selectedParam === option }"
@ click = "selectMenuOption(option)"
>
{ { option } }
< / div >
< / div > -- >
< el-dialog
title = "自定义标题"
: visible . sync = "dialogVisible"
class = "custom-dialog"
width = "50%" >
< div >
< h3 > 自定义内容 < / h3 >
2025-07-28 17:01:13 +08:00
< / div >
2025-09-15 09:58:52 +08:00
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisible = false" > 关闭 < / el -button >
< / span >
< / el-dialog >
< el-dialog
: visible . sync = "dialogVisibleImg"
fullscreen
class = "custom-dialog"
custom - class = "image-preview-dialog"
: show - close = "false"
>
<!-- 图片容器 -- >
< div class = "image-container" : style = "{height: containerHeight}" >
< img
ref = "previewImage"
: src = "currentImage"
: style = " {
transform : ` scale( ${ scale } ) rotate( ${ rotation } deg) ` ,
cursor : 'pointer' ,
transition : 'transform 0.3s ease' ,
maxWidth : '100%' ,
width : '50%'
} "
@ mousedown = "startDrag"
>
< / div >
<!-- 固定控制栏 -- >
< div class = "control-bar" >
< button @click ="zoomIn" class = "action-btn" >
< i class = "el-icon-zoom-in" > < / i >
< span > 放大 < / span >
< div class = "liquid-effect" > < / div >
< / button >
< button @click ="zoomOut" class = "action-btn" >
< i class = "el-icon-zoom-out" > < / i >
< span > 缩小 < / span >
< div class = "liquid-effect" > < / div >
< / button >
< button @click ="rotate" class = "action-btn" >
< i class = "el-icon-zoom-out" > < / i >
< span > 旋转图片 < / span >
< div class = "liquid-effect" > < / div >
< / button >
< button @click ="reset" class = "action-btn" >
< i class = "el-icon-zoom-out" > < / i >
< span > 重置图片 < / span >
< div class = "liquid-effect" > < / div >
< / button >
< button @click ="dialogVisibleImg = false" class = "action-btn" >
< i class = "el-icon-zoom-out" > < / i >
< span > 关闭 < / span >
< div class = "liquid-effect" > < / div >
< / button >
< div class = "scale-display" >
缩放 : { { ( scale * 100 ) . toFixed ( 0 ) } } %
< / div >
< / div >
< / el-dialog >
< el-dialog
: title = "navIsAdd=='create'?'新建目录':'编辑目录'"
: visible . sync = "dialogVisibleNav"
width = "80%"
class = "custom-dialog"
: before - close = "handleClose"
>
< el-form :model = "form" :rules = "rules" ref = "form" >
< el-button type = "primary" v -if = ' navIsAdd = = " create " ' @click ="loadFileBtn" > 加载文件 < / el -button >
< el-button type = "primary" v -if = ' showView ' @click ="viewLoadDMFile" > 预览文件 < / el -button >
< el-row :gutter = "20" >
< el-form-item label = "目录名称" prop = "name" >
< el-input v-model = "form.name" autocomplete="off" > < / el -input >
< / el-form-item >
< / el-row >
< el-row :gutter = "20" >
< el-col :span = "12" >
< el-form-item label = "责任合作单位" >
< el-input v-model = "form.contributor" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "创作单位" >
< el-input v-model = "form.creator" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "适用性信息" >
< el-input v-model = "form.applicabilityInformation" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "质量验证" >
< el-input v-model = "form.qualityVerification" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "权限" >
< el-input v-model = "form.permission" autocomplete="off" > < / el -input >
< / el-form-item >
< / el-col >
< el-col :span = "12" >
< el-form-item label = "版本信息" >
< el-input v-model = "form.version" disabled autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "发布时间" >
< el-input v-model = "form.date" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "语言" >
< el-input v-model = "form.language" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "密级" >
< el-input v-model = "form.level" autocomplete="off" > < / el -input >
< / el-form-item >
< el-form-item label = "是否使用加载原文档数据" v -if = ' showView ' >
< el-radio v-model = "isLoadOldDmc" label="1" > 使用 < / el -radio >
< el-radio v-model = "isLoadOldDmc" label="2" > 不使用 < / el -radio >
< / el-form-item >
< / el-col >
< / el-row >
< / el-form >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisibleNav = false" > 取 消 < / el -button >
< el-button type = "primary" v -if = ' isLoadOldDmc = = " 1 " ' @click ="confirmAdd(false)" > 加载确定 < / el -button >
< el-button v -if = ' navIsAdd = = " create " & & isLoadOldDmc = = " 2 " ' type = "primary" @click ="confirmAdd(true)" > 确 定 < / el -button >
< el-button v -if = ' navIsAdd = = " edit " ' type = "primary" @click ="confirmEdit()" > 确 定 < / el -button >
< / span >
< / el-dialog >
< el-dialog
title = "删除章节"
: visible . sync = "dialogVisibleNavDel"
width = "30%"
class = "custom-dialog"
>
< div >
是否确定删除 【 { { currentNode ? currentNode . name : '' } } 】 ?
< / div >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisibleNavDel = false" > 取 消 < / el -button >
< el-button type = "primary" @click ="deleteNode" > 确 定 < / el -button >
< / span >
< / el-dialog >
< el-dialog
title = "删除资源"
: visible . sync = "dialogVisibleAttrDel"
width = "30%"
class = "custom-dialog"
>
< div >
是否确定删除 【 { { nowAttr . name } } 】 的绑定 ?
< / div >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="dialogVisibleAttrDel = false" > 取 消 < / el -button >
< el-button type = "primary" @click ="deleteAttrSure" > 确 定 < / el -button >
< / span >
< / el-dialog >
< el-dialog
title = "提示"
: visible . sync = "dialogVisibleTips"
width = "30%"
class = "custom-dialog"
: before - close = "handleClose2" >
< span > 是否保存当前编辑内容1 < / span >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="saveNowDmc('noSave')" > 不保存 < / el -button >
< el-button type = "primary" @click ="saveNowDmc('save')" > 保存 < / el -button >
< / span >
< / el-dialog >
< el-dialog
title = "提示"
: visible . sync = "dialogVisibleTips2"
width = "30%"
class = "custom-dialog"
: before - close = "saveNowDmc2" >
< span > 是否保存当前编辑内容2 < / span >
< span slot = "footer" class = "dialog-footer" >
< el-button @click ="saveNowDmc2('noSave')" > 不保存 < / el -button >
< el-button type = "primary" @click ="saveNowDmc2('save')" > 保存 < / el -button >
< / span >
< / el-dialog >
< div
v - if = "contextMenuVisible"
class = "custom-context-menu"
: style = "{ left: contextMenuLeft + 'px', top: contextMenuTop + 'px' }"
>
< div class = "menu-item" @click ="handleMenuClick('a')" > 编辑目录 < / div >
< div class = "menu-item" @click ="handleMenuClick('b')" > 绑定资源 < / div >
< div class = "menu-item" @click ="handleMenuClick('c')" > 版本定稿 < / div >
< div class = "menu-item" @click ="handleMenuClick('d')" > 历史版本 < / div >
< div class = "menu-item" @click ="handleMenuClick('e')" > 删除目录 < / div >
< div class = "menu-divider" > < / div >
< div class = "menu-item" @click ="contextMenuVisible = false" > 关闭 < / div >
< / div >
< el-dialog
title = "文件预览"
: visible . sync = "maskViewShow"
width = "90%"
class = "custom-dialog viewDialog"
: before - close = "handleCloseMask"
>
< div class = "loadContent" v-html = "neirong" >
< / div >
< / el-dialog >
<!-- < div class = "maskView" v -if = ' maskViewShow ' :style = "{width:windowW+'px',height:windowH+'px','backgroundColor':'grba(0,0,0,.5)'}" >
< div >
screen高度 : { { screenHeight } }
screen宽度 : { { screenWidth } }
< / div >
< div >
window高度 : { { windowH } }
window宽度 : { { windowW } }
< / div >
< el-button @ click = 'maskViewShow = false' style = "right: 0px;position: absolute;top: 0;" > 关闭 < / el-button >
< / div > -- >
2025-07-25 13:28:47 +08:00
< / div >
< / template >
< script >
2025-09-15 09:58:52 +08:00
import WangEditor from 'wangeditor' ;
// import icon1 from '@/assets/jgIcon.png' // 第一个按钮的图标
// import icon2 from '@/assets/jsIcon.png' // 第二个按钮的图标
// import navTemp from './navTemp.vue';
2025-07-28 17:01:13 +08:00
// import '@yaireo/colorpicker/dist/colorpicker.min.css';
2025-09-15 09:58:52 +08:00
// import '@yaireo/colorpickehandleMessageFromDotNetr'
2025-07-25 13:28:47 +08:00
// import axios from 'axios';
// window.handleMessageFromDotNet = function(msg) {
// alert("Received message from C#: " + msg);
// }
export default {
name : 'RichTextEditor' ,
2025-09-15 09:58:52 +08:00
components : {
// navTemp
} ,
2025-07-25 13:28:47 +08:00
data ( ) {
return {
2025-09-15 09:58:52 +08:00
imgUrlJg : require ( '../assets/jgIcon.png' ) ,
imgUrlJs : require ( '../assets/jsIcon.png' ) ,
editorHeight : '' ,
historyVsPath : '' ,
leftHeight : '0' ,
isLoadXml : false , //是否加载DMC
neirong : '' , //预览内容
isLoadOldDmc : "1" , // 初始值需与 options 中的 value 类型一致
options : [
{ value : 1 , label : '使用' } ,
{ value : 2 , label : '不使用' }
] ,
showView : false , //是否显加载原文档
tempDivData1 : '' ,
viewLis : '' ,
viewXml : '' ,
viewXmlContent : '' ,
maskViewShow : false ,
// 屏幕整体尺寸(设备屏幕尺寸)
screenWidth : 0 ,
screenHeight : 0 ,
// 浏览器窗口尺寸
windowW : 0 ,
windowH : 0 ,
// 用于防抖的定时器
resizeTimer : null ,
// 要传递的数据
dataToSend : {
id : 1001 ,
name : '测试数据' ,
timestamp : new Date ( ) . getTime ( ) ,
content : '这是从主页面传递到wangG2.vue的数据' ,
status : 'active' ,
details : {
author : '系统管理员' ,
priority : 'high'
}
} ,
// 保存对新窗口的引用
wangG2Window : null ,
// 用于检查窗口状态的定时器
checkWindowTimer : null ,
draggableVis : false ,
showModifyBtn : false , // 控制是否显示【修改】的开关( 按钮点击后设为true)
mId : '' ,
isClick : true ,
loadFileDMC : '' , //加载的DMC文件里面的content内容
loadFileXML : '' , //加载的DMC文件内容
historyData : [ ] , //历史版本列表信息
contextMenuVisible : false , // 右键菜单是否可见
contextMenuLeft : 0 , // 右键菜单left位置
contextMenuTop : 0 , // 右键菜单top位置
contextMenuNode : null , // 右键点击的节点数据
dmcChangeState : false ,
windowHeight : '' ,
windowWidth : '' ,
nowAttr : { //当前操作的资源
name : '' ,
index : ''
} ,
dialogVisibleAttrDel : false , //删除弹窗
dialogVisibleTips2 : false , //
dialogVisibleTips : false , //删除提示弹窗
contentXmlStr : '' , //当前富文本字符串
getDmName : '' , //当前DM文件名。
isNavEdit : false , //是否在目录编辑状态。
allImgType : //暂定当前的图片类型
new Set ( [
"bmp" , "jpg" , "jpeg" , "png" , "tif" , "gif" , "pcx" , "tga" , "exif" , "fpx" , "svg" , "psd" , "cdr" , "pcd" , "dxf" , "ufo" , "eps" , "ai" , "raw" , "WMF" , "webp" , "avif" , "apng"
] ) ,
allMusicType : new Set ( [ //暂定当前的音频类型
"mp3" , "aac" , "wav" , "flac" , "alac" , "wma"
] ) ,
allVideoType : new Set ( [ //暂定当前的视频类型
"mp4" , "avi" , "mkv" , "mov" , "flv" , "wmv" , "webm" , "mpeg"
] ) ,
otherType : new Set ( [ 'wrl' , 'jltf' ] ) ,
lisenPath : '' , //当前内置服务器端口
//目录
domNameStr : [ //拼接文档名
'DMC-' , 'test2' , '-A-P4-20-00-00A-' , 'A-A_000_00' , '_zh_cn'
] ,
lastClick : '' , //上一次点击的目录id
nowClick : '' , //当前点击的目录id
nowMaxId : '' , //最大文档id
catalogueString : '' , //目录字符串
navIsAdd : '' , //判断当前目录操作类型
searchText : '' , //搜索目录章节
dialogVisibleNav : false , //目录弹窗
dialogVisibleRight : false , //右键绑定弹窗
dialogVisibleBland : false , //绑定源弹窗
dialogVisibleHistory : false , //历史版本弹窗
dialogVisibleNavDel : false , //删除弹窗
selectedAttributes : [ ] , // 当前选中的属性
treeData : [ //基础目录数据
// { id: '00001', name: '根节点1根节点1根节点1根节点1根节点1根节点1', children: [
// {
// id: '00003', name: '根节点3根节点3根节点3根节点3根节点3', children: [{
// id: '00004', name: '根节点4根节点4根节点4根节点4根节点4', children: [],
// attributes: [] // 示例:已绑定的属性
// }]
// }
// ], attributes: [] // 示例:已绑定的属性
// },
// { id:'00002', name: '根节点2根节点2根节点2根节点2根节点2', children: [
// {id: '00005', name: '根节点5根节点5根节点5根节点5根节点5', children: [ { id:'00002', name: '根节点2根节点2根节点2根节点2根节点2', children: [
// {id: '00005', name: '根节点5根节点5根节点5根节点5根节点5', children: [ { id:'00002', name: '根节点2根节点2根节点2根节点2根节点2', children: [
// {id: '00005', name: '根节点5根节点5根节点5根节点5根节点5', children: [ { id:'00002', name: '根节点2根节点2根节点2根节点2根节点2', children: [
// {id: '00005', name: '根节点5根节点5根节点5根节点5根节点5', children: []}
// ] }]}
// ] }]}
// ] }]}
// ] }
] ,
treeData2 : [
{
id : '00001' ,
name : '装备概况' ,
attributes : [ '金' , '木' , '水' ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [
{
id : '00002' ,
name : '方舱概述' ,
attributes : [ ] ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [
{
id : '00003' ,
name : '功能介绍' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00004' ,
name : '规格介绍' ,
attributes : [ '水' ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
}
]
} ,
{
id : '00005' ,
name : '舱体' ,
attributes : [ '火' , '土' ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00006' ,
name : '机身转运小车' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00007' ,
name : '无人机部件存储装置' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00008' ,
name : '机身转运小车' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00009' ,
name : '附件及工具' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [
{
id : '00010' ,
name : '灭火器' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00011' ,
name : '应急灯' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00012' ,
name : '土木工具' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00013' ,
name : '机械工具' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
}
]
}
]
} ,
{
id : '00013' ,
name : '使用说明' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [
{
id : '00014' ,
name : '无人机出舱' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00015' ,
name : '无人机入舱' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
} ,
{
id : '00016' ,
name : '灭火器使用' ,
attributes : [ ] ,
formMes : { } ,
lagreVersion : '001' ,
minorVersion : '01' ,
children : [ ]
}
]
}
] ,
defaultProps : { //树结构
children : 'children' ,
label : 'name'
} ,
currentNode : null , //当前节点
form : { //默认目录信息
name : '' ,
version : '000' ,
date : '' ,
language : '' ,
level : '' ,
contributor : '' ,
creator : '' ,
applicabilityInformation : '' ,
qualityVerification : '' ,
permission : ''
// version:'001',
// date:'2046-12-12',
// language:'zn_cn',
// level:'公开',
// contributor:'责任合作单位',
// creator:'创作单位',
// applicabilityInformation:'适用性信息',
// qualityVerification:'质量验证',
// permission:'10'
} ,
rules : {
name : [
{ required : true , message : '请输入节点名称' , trigger : 'blur' } ,
{ min : 1 , max : 40 , message : '长度在 1 到 40 个字符' , trigger : 'blur' }
]
} ,
//弹窗
dialogVisible : false , //自定义弹窗
idLength : 10 , //暂无用
contextMenu : { //暂无用
visible : false ,
x : 0 ,
y : 0 ,
selectedElement : null ,
selectedParam : ''
} ,
isContextMenuEnabled : false , //暂无用
itemParams : { } , //暂无用
// 存储元素的参数 {elementId: param}
// 模拟弹框参数
//查看图片begin
dialogVisibleImg : false , //暂无用
images : [ //暂无用
'https://ww2.sinaimg.cn/mw690/007ut4Uhly1hx4v37mpxcj30u017cgrv.jpg' ,
'https://example.com/image2.jpg'
] ,
currentImage : '' , //暂无用
scale : 1 , //暂无用
rotation : 0 , //暂无用
isDragging : false , //暂无用
startX : 0 , //暂无用
startY : 0 , //暂无用
translateX : 0 , //暂无用
translateY : 0 , //暂无用
containerHeight : '90vh' , //暂无用 动态控制高度
//查看图片end
oldSelector : [ //基础标签模块
'div' , 'code' , 'hr' , 'br' , 'h1,h2,h3,h4' , 'p' , 'img' , 'table' , 'a' , 'ul' , 'ol' , 'blockquote' , 'pre' ,
] ,
newSelector : [ //替换后的标签模块
'pDiv' , 'pCode' , 'pHr' , 'pBr' , 'pTitle' , 'pDiv' , 'pImg' , 'pTable' , 'pA' , 'pUl' , 'pOl' , 'pBlockquote' , 'pPre' ,
] ,
tempDivData : { //当前富文本str
innerHTML : '五'
} ,
colors : '' , //暂无用
val1 : '' , //暂无用
val2 : '' , //暂无用
message : '' , //暂无用
2025-07-25 13:28:47 +08:00
editor : null ,
editor2 : null ,
2025-09-15 09:58:52 +08:00
editorContent : '' , //富文本内容
editorContent2 : '' ,
xmlPreview : '' ,
2025-07-28 17:01:13 +08:00
validationResult : {
valid : false ,
message : '' ,
details : ''
} ,
// 简单的S1000D模板配置
dmConfig : {
dmc : {
modelIdentCode : 'AAA' ,
systemDiffCode : 'BBB' ,
systemCode : 'CCC' ,
subSystemCode : 'DDD' ,
subSubSystemCode : 'EEE' ,
assyCode : 'FFF' ,
disassyCode : 'GGG' ,
disassyCodeVariant : 'HHH' ,
infoCode : 'III' ,
infoCodeVariant : 'JJJ' ,
itemLocationCode : 'KKK'
} ,
issueInfo : {
2025-09-15 09:58:52 +08:00
issueNumber : '000' ,
inWork : '00' ,
2025-07-28 17:01:13 +08:00
issueDate : new Date ( ) . toISOString ( ) . split ( 'T' ) [ 0 ]
} ,
language : 'zh-CN'
}
}
} ,
2025-09-15 09:58:52 +08:00
computed : {
2025-07-28 17:01:13 +08:00
formattedXmlPreview ( ) {
if ( ! this . xmlPreview ) return '暂无XML预览' ;
// 简单格式化XML显示
return this . xmlPreview
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /\n/g , '<br>' )
. replace ( /\s/g , ' ' ) ;
2025-07-25 13:28:47 +08:00
}
} ,
mounted ( ) {
2025-09-15 09:58:52 +08:00
// 初始化尺寸
this . getWindowSize ( )
// 绑定 resize 事件
window . addEventListener ( 'resize' , this . handleResize )
// 确保DOM已加载
this . $nextTick ( ( ) => {
this . initEditor ( )
} )
// this.initEditor()
2025-07-25 13:28:47 +08:00
// this.initEditor2();
// window.receiveMessageFromWpf = this.receiveMessageFromWpf;
console . log ( 'chrome对象是否存在:' , ! ! window . chrome ) ;
console . log ( 'webview对象是否存在:' , ! ! window . chrome ? . webview ) ;
2025-09-15 09:58:52 +08:00
window . removeEventListener ( 'SelectFilePathSend' , this . handleFilePathSend ) ;
// 再绑定新的监听器
window . addEventListener ( 'SelectFilePathSend' , this . handleFilePathSend ) ;
window . addEventListener ( 'SelectFilePathSend' , this . SendLisentPathFun ) ;
2025-07-25 13:28:47 +08:00
} ,
beforeDestroy ( ) {
// 销毁编辑器
if ( this . editor ) {
this . editor . destroy ( )
}
2025-09-15 09:58:52 +08:00
// 清理定时器
if ( this . checkWindowTimer ) {
clearInterval ( this . checkWindowTimer )
}
console . log ( '监听器开始移除:' , Date . now ( ) ) // 打印移除时间戳
window . removeEventListener ( 'resize' , this . handleResize )
window . removeEventListener ( 'FrontLoadDM' , this . FrontLoadDM _g1 )
window . removeEventListener ( 'handleMessageFromDotNet' , this . fun1 )
window . removeEventListener ( 'SelectFilePathSend' , this . SendLisentPathFun )
2025-07-25 13:28:47 +08:00
} ,
2025-09-15 09:58:52 +08:00
methods : {
//清除节点选中
clearNodeState ( ) {
// 通过ref获取el-tree实例
const tree = this . $refs . tree ;
if ( tree ) {
// 取消当前选中状态
tree . setCurrentKey ( null ) ;
// 如果需要清除所有节点的选中状态(包括多选情况)
// 先获取所有选中的节点
const selectedNodes = tree . getCheckedNodes ( ) ;
// 取消所有节点的选中状态
selectedNodes . forEach ( node => {
tree . setChecked ( node . id , false ) ;
} ) ;
// 可选: 触发节点点击事件的回调, 传递null表示无选中节点
// this.handleNodeClick(null);
}
} ,
// 测试接收数据
fun1 ( e ) {
console . log ( "方法1" , e , e . detail )
} ,
// 获取服务端口地址
SendLisentPathFun ( e ) {
console . log ( '服务端口地址信息1:' , e , e . detail )
this . lisenPath = e . detail ;
} ,
//接收富文本内容信息
FrontLoadDM _g1 ( e ) {
console . log ( "加载文档数据 1111" )
console . log ( 'FrontLoadDM 参数接收111:' , e , e . detail )
// this.editorShow = true;
let xmlContent = e . detail . trim ( ) ;
if ( xmlContent . startsWith ( '"' ) ) {
xmlContent = xmlContent . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( xmlContent . endsWith ( '"' ) ) {
xmlContent = xmlContent . substring ( 0 , xmlContent . length - 1 ) ;
}
// console.log("xmlContent",xmlContent)
const parser = new DOMParser ( )
const xmlDoc = parser . parseFromString ( xmlContent , "text/xml" )
console . log ( "xmlDoc" , xmlDoc )
const contentNodes = xmlDoc . getElementsByTagName ( 'content' ) [ 0 ] ;
console . log ( "xmlDoc.getElementsByTagName('content')" , xmlDoc . getElementsByTagName ( 'content' ) )
console . log ( "contentNodes" , contentNodes )
const rdfDescription = xmlDoc . querySelector ( 'rdf\\:Description, Description' ) ;
if ( rdfDescription ) {
// 填充表单数据 - 映射关系: form字段 -> XML标签
this . form = {
name : this . getNodeValue ( rdfDescription , 'dc\\:title, title' ) ,
version : this . getNodeValue ( rdfDescription , 'dc\\:version, version' ) ,
date : this . getNodeValue ( rdfDescription , 'dc\\:date, date' ) ,
language : this . getNodeValue ( rdfDescription , 'dc\\:language, language' ) ,
level : this . getNodeValue ( rdfDescription , 'dc\\:level, level' ) ,
contributor : this . getNodeValue ( rdfDescription , 'dc\\:contributor, contributor' ) ,
creator : this . getNodeValue ( rdfDescription , 'dc\\:creator, creator' ) ,
applicabilityInformation : this . getNodeValue ( rdfDescription , 'dc\\:applicabilityInformation, applicabilityInformation' ) ,
qualityVerification : this . getNodeValue ( rdfDescription , 'dc\\:qualityVerification, qualityVerification' ) ,
permission : this . getNodeValue ( rdfDescription , 'dc\\:permission, permission' )
} ;
console . log ( 'XML解析成功' , this . form ) ;
} else {
this . form = {
name : '' ,
version : '' ,
date : '' ,
language : '' ,
level : '' ,
contributor : '' ,
creator : '' ,
applicabilityInformation : '' ,
qualityVerification : '' ,
} ;
console . log ( "目录解析不成功 置空" , this . form )
}
if ( contentNodes ) {
console . log ( "处理前" , contentNodes . innerHTML )
let htmlContent = this . convertXmlContentToHtml ( contentNodes . innerHTML )
let htmlContent2 = this . completeModel3DTags ( htmlContent )
console . log ( "处理后" , htmlContent2 )
const htmlContent3 = this . replaceModel3dToImg ( htmlContent2 ) ;
// this.editor.txt.html(htmlContent)
//处理过后再导入
// this.restoreContent(htmlContent)
this . restoreContentXh ( htmlContent3 )
}
} ,
2025-07-25 13:28:47 +08:00
test ( ) {
2025-09-15 09:58:52 +08:00
let a = '<pdiv id="divid"><p id="id"><pimg id="imgid"><img src="4.jpg" style="max-width: 100%;" alt="图片" id="imgid_1"></img></pimg><pimg id="imgid_2"><img src="zw.jpg" class="model3d" alt="图片" style="max-width: 100%;" id="imgid_3"></img></pimg></p></pdiv>' ;
let b = this . replacemodel3dImages ( a ) ;
console . log ( "替换的结果" , b )
2025-07-25 13:28:47 +08:00
} ,
2025-09-15 09:58:52 +08:00
//测试发送给后端信息
2025-07-25 13:28:47 +08:00
sendMessageToHost ( ) {
2025-09-15 09:58:52 +08:00
//调用后端 sendToDotNet
2025-07-25 13:28:47 +08:00
this . $sendToDotNet ( this . val1 , this . val2 ) ;
} ,
2025-09-15 09:58:52 +08:00
//加载富文本
loadFwb ( ) {
2025-07-25 13:28:47 +08:00
this . editor2 . txt . html ( this . editorContent )
} ,
2025-09-15 09:58:52 +08:00
initEditor ( ) { //初始化编辑器配置
2025-07-25 13:28:47 +08:00
this . editor = new WangEditor ( this . $refs . editor )
// 配置编辑器
this . editor . config . uploadImgShowBase64 = true // 使用 base64 保存图片
this . editor . config . onchange = ( html ) => {
2025-09-15 09:58:52 +08:00
this . editorContent = html ;
2025-07-25 13:28:47 +08:00
}
let dm = this . editor . config . menus ;
console . log ( "默认菜单" , dm )
2025-09-15 09:58:52 +08:00
2025-07-25 13:28:47 +08:00
2025-07-28 17:01:13 +08:00
// 启用颜色选择功能
this . editor . config . colors = [
'#000000' , '#ffffff' , '#eeeef1' ,
'#ff0000' , '#ff5e5e' , '#ffbbbb' ,
'#0033ff' , '#0055ff' , '#3d7eff' ,
'red' , "#096" , "#9cf"
]
2025-07-25 13:28:47 +08:00
// 完全自定义菜单
this . editor . config . menus = [
'image' , // 图片
'video' , // 视频
2025-09-15 09:58:52 +08:00
// 'head', // 标题
2025-07-25 13:28:47 +08:00
'bold' , // 粗体
2025-09-15 09:58:52 +08:00
'fontSize' , //字号
2025-07-25 13:28:47 +08:00
// 'fontName',//字体
'italic' , // 斜体
'underline' , // 下划线
'strikeThrough' , // 删除线
// 'line',//行高
'lineHeight' , //
2025-07-28 17:01:13 +08:00
'foreColor' , // 文字颜色
'backColor' , // 背景颜色
2025-09-15 09:58:52 +08:00
'link' , // 链接
2025-07-25 13:28:47 +08:00
'list' , // 列表
// 'todo',//
'justify' , // 对齐方式
2025-09-15 09:58:52 +08:00
'quote' , // 引用
2025-07-25 13:28:47 +08:00
// 'emoticon',//表情
'table' , // 表格
2025-09-15 09:58:52 +08:00
'code' , // 代码
2025-07-25 13:28:47 +08:00
'splitLine' , //分割线
'undo' , // 撤销
2025-07-28 17:01:13 +08:00
'redo' , // 重做
2025-07-25 13:28:47 +08:00
]
2025-09-15 09:58:52 +08:00
console . log ( "自定义菜单" , this . editor . config )
// 自定义处理拖拽事件
this . editor . config . customUpload = true
// 监听拖拽事件
this . editor . config . uploadImgShowBase64 = false
this . editor . config . uploadVideoShowBase64 = false
this . editor . config . uploadAudioShowBase64 = false
// 设置自定义拖拽处理
// this.setupDragHandler()
// 保存原始的创建方法
const originalCreate = this . editor . create
// 重写创建方法,在创建完成后立即添加按钮
this . editor . create = ( ) => {
// 执行原始创建方法
originalCreate . call ( this . editor )
// 尝试获取工具栏
// 📌🔖
//
this . addCustomButton ( '警示' , '<img src="' + this . imgUrlJs + '" alt="按钮图标" style="width: 20px; height: 20px; object-fit: contain;">' , 2 ) // 第一个按钮, 弹出123, 使用图钉图标
this . addCustomButton ( '警告' , '<img src="' + this . imgUrlJg + '" alt="按钮图标" style="width: 20px; height: 20px; object-fit: contain;">' , 2 ) // 第一个按钮, 弹出123, 使用图钉图标
}
2025-07-25 13:28:47 +08:00
// 创建编辑器
this . editor . create ( ) ;
2025-09-15 09:58:52 +08:00
// 特别注意:需要在编辑器创建完成后绑定事件
this . $nextTick ( ( ) => {
console . log ( "初始化 setupDragHandler" )
this . setupDragHandler ( )
} )
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// this.editor2 = new WangEditor(this.$refs.editor2)
// // 配置编辑器
// this.editor2.config.uploadImgShowBase64 = true // 使用 base64 保存图片
// this.editor2.config.onchange = (html) => {
// console.log("22222",html)
// // this.editorContent2 = html
// }
// this.editor2.create()
2025-07-25 13:28:47 +08:00
} ,
2025-09-15 09:58:52 +08:00
// 通用的添加自定义按钮方法,接收两个参数:提示内容和图标
addCustomButton ( alertContent , icon , type ) {
let toolbarElem = null
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 方式1: 通过编辑器内部属性获取工具栏
if ( this . editor . $toolbarElem && this . editor . $toolbarElem [ 0 ] ) {
toolbarElem = this . editor . $toolbarElem [ 0 ]
console . log ( '通过$toolbarElem获取到工具栏' )
}
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 方式2: 直接通过容器查找
if ( ! toolbarElem ) {
toolbarElem = this . $refs . editor . querySelector ( '.w-e-toolbar' )
if ( toolbarElem ) {
console . log ( '通过容器查询获取到工具栏' )
}
}
// 方式3: 全局查找
if ( ! toolbarElem ) {
toolbarElem = document . querySelector ( '.w-e-toolbar' )
if ( toolbarElem ) {
console . log ( '通过全局查询获取到工具栏' )
}
}
// 如果还是找不到工具栏,直接创建一个简单的按钮放在编辑器上方
if ( ! toolbarElem ) {
console . warn ( '仍然未找到工具栏,创建独立按钮' )
this . createFallbackButton ( alertContent , icon , type )
return
}
// 查找或创建菜单容器
let menuBar = toolbarElem . querySelector ( '.w-e-menu-bar' )
if ( ! menuBar ) {
menuBar = document . createElement ( 'div' )
menuBar . className = 'w-e-menu-bar'
menuBar . style . cssText = 'padding: 5px; border-bottom: 1px solid #e8e8e8;'
toolbarElem . appendChild ( menuBar )
}
// 创建自定义按钮
const customBtn = document . createElement ( 'div' )
customBtn . className = 'w-e-menu'
customBtn . style . cssText = `
width : 32 px ;
height : 32 px ;
display : inline - flex ;
align - items : center ;
justify - content : center ;
cursor : pointer ;
margin : 0 2 px ;
background : # fff ;
border - radius : 2 px ;
color : # 333 ;
font - size : 18 px ;
`
customBtn . innerHTML = icon
customBtn . title = ` ${ alertContent } `
// 绑定点击事件,使用传入的提示内容
customBtn . onclick = ( ) => {
console . log ( "点击了111" , type )
switch ( type ) {
case 1 :
case '1' :
this . editor . cmd . do ( 'insertHTML' , ` <p data-we-empty-p><div style='margin: 50px auto;
padding : 20 px ;
border : 12 px solid ;
border - image : linear - gradient ( 45 deg ,
# ffcc00 0 % , # ffcc00 10 % ,
# 000000 10 % , # 000000 20 % ,
# ffcc00 20 % , # ffcc00 30 % ,
# 000000 30 % , # 000000 40 % ,
# ffcc00 40 % , # ffcc00 50 % ,
# 000000 50 % , # 000000 60 % ,
# ffcc00 60 % , # ffcc00 70 % ,
# 000000 70 % , # 000000 80 % ,
# ffcc00 80 % , # ffcc00 90 % ,
# 000000 90 % , # 000000 100 %
) 1 ; ' > < / div > < / p > ` )
break ;
case 2 :
case '2' :
this . editor . cmd . do ( 'insertHTML' , ` <p data-we-empty-p><div style="margin: 50px auto;
padding : 20 px ;
border : 12 px solid ;
border - image : linear - gradient ( 45 deg ,
# ff0000 0 % , # ff0000 10 % ,
# 000000 10 % , # 000000 20 % ,
# ff0000 20 % , # ff0000 30 % ,
# 000000 30 % , # 000000 40 % ,
# ff0000 40 % , # ff0000 50 % ,
# 000000 50 % , # 000000 60 % ,
# ff0000 60 % , # ff0000 70 % ,
# 000000 70 % , # 000000 80 % ,
# ff0000 80 % , # ff0000 90 % ,
# 000000 90 % , # 000000 100 %
) 1 ; " > < / div > < / p > ` )
break ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
}
// 添加悬停效果
customBtn . onmouseover = ( ) => {
customBtn . style . background = '#f0f0f0'
}
customBtn . onmouseout = ( ) => {
customBtn . style . background = '#fff'
}
// 添加到菜单最前面
menuBar . insertBefore ( customBtn , menuBar . firstChild )
console . log ( ` 自定义按钮(弹出 ${ alertContent } )已成功添加到菜单栏 ` )
} ,
// 备用方案:如果找不到工具栏,直接在编辑器上方创建一个按钮
createFallbackButton ( alertContent , icon , type ) {
const fallbackBtn = document . createElement ( 'div' )
fallbackBtn . style . cssText = `
padding : 8 px 15 px ;
background : # 409 eff ;
color : white ;
border - radius : 4 px ;
cursor : pointer ;
display : inline - block ;
margin : 0 5 px 10 px 0 ;
`
fallbackBtn . innerHTML = ` ${ icon } 点击弹出 ${ alertContent } `
fallbackBtn . onclick = ( ) => {
console . log ( "点击了222" , type )
switch ( type ) {
case 1 :
this . editor . cmd . do ( 'insertHTML' , ` <p class="fine-stripe-border1"></p> ` )
break ;
case 2 :
this . editor . cmd . do ( 'insertHTML' , ` <p class="fine-stripe-border2"></p> ` )
break ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
}
// 添加到编辑器容器的最前面
this . $refs . editor . insertBefore ( fallbackBtn , this . $refs . editor . firstChild )
console . log ( ` 已创建备用按钮(弹出 ${ alertContent } ) ` )
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
setupDragHandler ( ) {
console . log ( "进入setupDragHandler" )
const editor = this . editor
const editorContainer = editor . $textElem . elems [ 0 ]
let that = this ;
// console.log("进入参数",editor,editorContainer)
// // 阻止默认拖拽行为
editorContainer . addEventListener ( 'dragover' , ( e ) => {
// console.log("进入 dragover",e)
e . preventDefault ( )
e . stopPropagation ( )
2025-07-25 13:28:47 +08:00
} )
2025-09-15 09:58:52 +08:00
editorContainer . addEventListener ( 'drop' , ( e ) => {
// console.log("进入 drop",)
e . preventDefault ( )
e . stopPropagation ( )
that . $sendToDotNet ( 'GetMaterialPath' ) ;
// // 检查拖拽的文件类型
// const items = e.dataTransfer.items
// for (let i = 0; i < items.length; i++) {
// const item = items[i]
// if (item.kind === 'file') {
// const file = item.getAsFile()
// const fileType = file.type.split('/')[0]
// // 根据文件类型显示不同的提示
// switch(fileType) {
// case 'image':
// alert('检测到图片文件,已阻止上传')
// break
// case 'video':
// alert('检测到视频文件,已阻止上传')
// break
// case 'audio':
// alert('检测到音频文件,已阻止上传')
// break
// default:
// alert(`检测到${fileType}类型文件,已阻止上传`)
// }
// }
// }
2025-07-25 13:28:47 +08:00
} )
2025-09-15 09:58:52 +08:00
} ,
// 上传图片
insertImage ( src ) {
// src = 'http://localhost:54610/a1.jpg';
// const imgUrl = 'http://youneed.top:10017/uploads/1.jpg'
// const imgUrl = 'https://ww2.sinaimg.cn/mw690/007ut4Uhly1hx4v37mpxcj30u017cgrv.jpg';
const imgUrl = src ? src : 'http://localhost:5432/DM_Material/a1.jpg' ;
console . log ( "地址" , src , imgUrl )
this . editor . cmd . do ( 'insertHTML' , ` <img src=" ${ imgUrl } " style="max-width: 100%;" alt="图片"> ` )
} ,
// 上传3D资源模拟占位
insert3d ( imgUrl ) {
this . editor . cmd . do ( 'insertHTML' , ` <img src=" ${ imgUrl } " class='model3d' style="max-width: 100%;" alt="图片"> ` )
// this.editor.cmd.do('insertHTML', `<div>3D模型<model3d src="http://www.baidu.com" controls="controls" style="max-width: 100%"></model3d></div>`)
} ,
//上传3D资源模设置标识
replacemodel3dImages ( htmlString ) {
if ( ! htmlString ) return '' ;
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
const regex = /<img([^>]*?)class="model3d"([^>]*?)\/?>/gi ;
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
return htmlString . replace ( regex , ( match , prefix , suffix ) => {
const attributes = ( prefix || '' ) + ( suffix || '' ) ;
return ` <model3d class="model3d" ${ attributes } ></model3d> ` ;
} ) ;
2025-07-25 13:28:47 +08:00
} ,
2025-09-15 09:58:52 +08:00
//解析3d资源标识
modelToImg ( htmlString ) {
// 匹配<model3d>标签且class中包含model3d
const regex = /<model3d([^>]*?)class="([^"]*?)model3d([^"]*?)"([^>]*?)>/gi ;
// 替换标签名,保留所有属性
return htmlString . replace ( regex , '<img$1class="$2model3d$3"$4>' ) ;
} ,
// // 插入视频
// insertVideo() {
// // const videoUrl = 'http://youneed.top:10017/uploads/video.mp4'
// const videoUrl = 'https://r1.realme.net/general/20250530/17485780109181ed6767541a64e7d90626e0a3fd1aaae.mp4?type=video/mp4';
// const videoId = `video-${Date.now()}`
// // 创建视频HTML
// const videoHtml = `
// <div class="video-wrapper" data-video-id="${videoId}">
// <video controls width="50%" style='margin:auto' data-video-id="${videoId}">
// <source src="${videoUrl}" type="video/mp4">
// </video>
// <div class="video-controls" style='display:none;'>
// <span class="video-delete" data-video-id="${videoId}">× 删除</span>
// </div>
// </div>
// <p><br></p>
// `
// // 使用编辑器命令插入
// this.editor.cmd.do('insertHTML', videoHtml)
// // 添加删除事件监听
// this.$nextTick(() => {
// const btn = document.querySelector(`button[data-video-id="${videoId}"]`)
// if (btn) {
// btn.onclick = (e) => {
// e.preventDefault()
// this.deleteVideoById(videoId)
// }
// }
// })
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// },
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// // 根据ID删除视频( 修正版)
// deleteVideoById(videoId) {
// const container = document.querySelector(`.video-container[data-video-id="${videoId}"]`)
// if (container) {
// container.remove()
// this.editor.txt.html(this.editor.txt.html()) // 刷新编辑器
// }
// },
// 插入视频
insertVideo ( src ) {
// const videoUrl = src?src:'https://r1.realme.net/general/20250530/17485780109181ed6767541a64e7d90626e0a3fd1aaae.mp4?type=video/mp4'
const videoUrl = src ? src : 'http://localhost:5432/DM_Material/video.mp4'
// 使用 editor.cmd.do 执行插入操作,支持撤销/重做
this . editor . cmd . do ( 'insertHTML' , ` <div><video src=" ${ videoUrl } " controls="controls" style="max-width: 100%"></video></div> ` )
// 或者使用更简单的插入方式
// this.editor.txt.append(`<video src="${videoUrl}" controls="controls" style="max-width: 100%"></video>`)
2025-07-25 13:28:47 +08:00
} ,
2025-09-15 09:58:52 +08:00
// 插入音频
insertAudio ( src ) {
// let audioUrl = 'https://m801.music.126.net/20250805103535/df94bdfa3bc8c3a07de64531c4925895/jdymusic/obj/wo3DlMOGwrbDjj7DisKw/14096444542/bafc/a068/39f8/9a9e06e5634410b5e7e81df24749e656.mp3?vuutv=6WGmbU7+iXWmpSMnJs8FQEYWEieNRcA9S4YcUYOjmx36NJRHK0ASi7jhIJz0R9gxcmMcAUDn9rf1k08lFtqC9TQYcOlc8ZofqvCCJho3eeBGH/hwnjUlaQHe2GQFyJ32rhYAydM3bCBfIg+ZnpfZTw==';
let audioUrl = src ? src : 'http://localhost:5432/DM_Material/music.mp3' ;
// 使用预设音频URL
// const audioHtml = `
// <div class="audio-container" style="margin: 10px 0;">
// <audio controls src="${audioUrl}" style="width: 100%;"></audio>
// <div style="text-align: center; color: #999; font-size: 12px;">音频文件</div>
// </div>
// `;
const audioHtml = `
< audio controls src = "${audioUrl}" style = "width: 100%;" > < / audio >
` ;
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 插入到编辑器
this . editor . cmd . do ( 'insertHTML' , audioHtml ) ;
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 或者使用更简单的方式
// this.editor.txt.append(audioHtml)
} ,
//循环处理标签
xh ( oldSt , newSt , type , saveId ) {
let times = oldSt . length ;
// const ht1 = this.tempDivData.innerHTML;
// console.log("3d转换之后2",ht1)
for ( let i = 0 ; i < times ; i + + ) {
const headings = this . tempDivData . querySelectorAll ( oldSt [ i ] )
headings . forEach ( heading => {
const dmTitle = document . createElement ( newSt [ i ] )
heading . parentNode . insertBefore ( dmTitle , heading )
console . log ( "内容替换" , dmTitle , heading )
dmTitle . appendChild ( heading )
} )
}
this . createXmlSt ( type , saveId ) ;
} ,
// 先清除已有的ID, 确保干净的基础
removeAllIds ( htmlString ) {
// 创建临时容器解析HTML
const tempContainer = document . createElement ( 'div' ) ;
tempContainer . innerHTML = htmlString ;
// 递归移除所有元素的id属性
const removeIdsFromElement = ( element ) => {
if ( ! element || element . nodeType !== 1 ) return ;
// 移除当前元素的id
element . removeAttribute ( 'id' ) ;
// 递归处理子元素
Array . from ( element . children ) . forEach ( child => {
removeIdsFromElement ( child ) ;
} ) ;
} ;
// 处理所有子元素
Array . from ( tempContainer . children ) . forEach ( child => {
removeIdsFromElement ( child ) ;
} ) ;
return tempContainer . innerHTML ;
} ,
// 删除Colgroup
removeColgroup ( str ) {
// 1. 校验入参( 防止传入null/undefined导致报错)
if ( ! str || typeof str !== 'string' ) {
console . warn ( '传入的内容不是有效字符串' ) ;
return str ; // 入参无效时,直接返回原内容
}
// 2. 定义正则( 匹配colgroup标签, 不区分大小写、全局匹配)
const colgroupReg = /<colgroup[\s\S]*?<\/colgroup>/gi ;
// 3. 判断是否包含colgroup标签
const hasColgroupTag = colgroupReg . test ( str ) ;
// 4. 处理逻辑:包含则移除,不包含则返回原字符串
let processedStr ;
if ( hasColgroupTag ) {
processedStr = str . replace ( colgroupReg , '' ) ;
console . log ( '检测到colgroup标签, 已移除' ) ;
} else {
processedStr = str ; // 关键: 不包含时返回原字符串, 而非null
console . log ( '未检测到colgroup标签, 返回原字符串' ) ;
}
// 5. 打印日志(便于调试)
console . log ( '解析前:' , str ) ;
console . log ( '解析后:' , processedStr ) ;
return processedStr ;
} ,
/ * *
* 为HTML字符串中的所有标签添加唯一ID
* @ param { string } htmlString - 原始HTML字符串
* @ returns { string } 处理后的HTML字符串
* /
addUniqueIds ( htmlString ) {
// 先清除已有的ID, 确保干净的基础
const cleanHtml = this . removeAllIds ( htmlString ) ;
console . log ( "当前的所有html内容2" , cleanHtml )
const tempContainer = document . createElement ( 'div' ) ;
tempContainer . innerHTML = cleanHtml ;
const usedIds = new Set ( ) ;
// 生成唯一ID
const generateUniqueId = ( tagName , content = '' ) => {
const pureTagName = tagName . toLowerCase ( ) . replace ( /^p/ , '' ) ;
const semanticSuffix = content . trim ( )
. replace ( /\s+/g , '_' )
. replace ( /[^a-z0-9-]/g , '' )
. slice ( 0 , 10 ) ;
console . log ( '循环数据semanticSuffix' , semanticSuffix )
let baseId = pureTagName + ( semanticSuffix ? ` id_ ${ semanticSuffix } ` : 'id' ) ;
let finalId = baseId ;
let counter = 1 ;
console . log ( '循环数据counter' , counter )
console . log ( '循环数据baseId' , baseId )
while ( usedIds . has ( finalId ) ) {
finalId = ` ${ baseId } _ ${ counter } ` ;
counter ++ ;
}
usedIds . add ( finalId ) ;
return finalId ;
} ;
// 递归添加ID
const addIdsToElement = ( element ) => {
if ( ! element || element . nodeType !== 1 ) return ;
const elementText = element . textContent || '' ;
const elementId = generateUniqueId ( element . tagName , elementText ) ;
element . setAttribute ( 'id' , elementId ) ;
Array . from ( element . children ) . forEach ( child => {
addIdsToElement ( child ) ;
} ) ;
} ;
// 处理所有元素
Array . from ( tempContainer . children ) . forEach ( child => {
addIdsToElement ( child ) ;
} ) ;
return tempContainer . innerHTML ;
} ,
/ * *
* 完整处理流程 : 清除现有ID - > 添加新的唯一ID
* @ param { string } originalHtml - 原始HTML字符串
* /
processHtmlWithIds ( originalHtml ) {
console . log ( "当前的所有html内容1" , originalHtml )
let processedHtml = this . addUniqueIds ( originalHtml ) ;
console . log ( "添加完的富文本" , processedHtml )
return processedHtml ;
} ,
// 创建XML字符串
createXmlSt ( type , saveId ) {
let desStr = this . form ;
// if(type||this.isNavEdit){
// desStr = this.form;
// this.isNavEdit = false;
// }else{
// desStr = '';
// }
console . log ( "当前" , this . navIsAdd )
// const ht3 = this.tempDivData.innerHTML;
// console.log("3d转换之后3",ht3)
switch ( this . navIsAdd ) {
case "create" :
this . tempDivData . innerHTML = '' ;
break ;
case "edit" :
// this.tempDivData.innerHTML = this.tempDivData.innerHTML;
break ;
case "other" :
// this.tempDivData.innerHTML = this.tempDivData.innerHTML;
this . navIsAdd = 'create' ;
break ;
default :
// this.tempDivData.innerHTML = '';
break ;
}
// this.tempDivData.innerHTML = this.navIsAdd?"":this.tempDivData.innerHTML;
this . tempDivData . innerHTML = this . clearNbsp ( this . tempDivData . innerHTML )
// const ht4 = this.tempDivData.innerHTML;
// console.log("3d转换之后4",ht4)
console . log ( "当前的所有html内容3" , this . tempDivData . innerHTML )
let newDST = this . processHtmlWithIds ( this . tempDivData . innerHTML )
// const ht5 = this.tempDivData.innerHTML;
// console.log("3d转换之后5",ht5)
console . log ( "结果cleanedStr 然后赋值" , this . tempDivData . innerHTML )
console . log ( "加ID后的" , newDST )
//去掉table里面的东西
newDST = this . removeColgroup ( newDST )
// const ht6 = this.tempDivData.innerHTML;
// console.log("3d转换之后6",ht6)
if ( this . loadFileDMC ) {
newDST = this . loadFileDMC ;
}
console . log ( "解析出来后的" , newDST )
const xmlString = ` <?xml version="1.0" encoding="UTF-8"?>
< dmodule xmlns :xlink = "http://www.w3.org/1999/xlink" xmlns :rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns :dc = "http://purl.org/dc/elements/1.1/" >
< rdf : Description >
< dc : title > ` +desStr.name+ ` < / d c : t i t l e >
< dc : creator > ` +desStr.creator+ ` < / d c : c r e a t o r >
< dc : permission > ` +desStr.permission+ ` < / d c : p e r m i s s i o n >
< dc : subject / >
< dc : publisher > ` +desStr.creator+ ` < / d c : p u b l i s h e r >
< dc : contributor > ` +desStr.contributor+ ` < / d c : c o n t r i b u t o r >
< dc : version > ` +desStr.version+ ` < / d c : v e r s i o n >
< dc : level > ` +desStr.level+ ` < / d c : l e v e l >
< dc : date > ` +desStr.date+ ` < / d c : d a t e >
< dc : applicabilityInformation > ` +desStr.applicabilityInformation+ ` < / d c : a p p l i c a b i l i t y I n f o r m a t i o n >
< dc : qualityVerification > ` +desStr.qualityVerification+ ` < / d c : q u a l i t y V e r i f i c a t i o n >
< dc : type > text < / d c : t y p e >
< dc : format > text / xml < / d c : f o r m a t >
< dc : identifier > ` +this.getDmName+ ` < / d c : i d e n t i f i e r >
< dc : language > ` +desStr.language+ ` < / d c : l a n g u a g e >
< dc : rights > 01 < / d c : r i g h t s >
< / r d f : D e s c r i p t i o n >
< identAndStatusSection >
< dmAddress >
< dmIdent >
< dmCode
modelIdentCode = "EXAMPLE01"
systemDiffCode = "A1"
systemCode = "SYS"
subSystemCode = "A"
subSubSystemCode = "B"
assyCode = "AS01"
disassyCode = "DS"
disassyCodeVariant = "001"
infoCode = "INF"
infoCodeVariant = "1"
itemLocationCode = "A"
/ >
< language languageIsoCode = "en" countryIsoCode = "US" / >
< issueInfo issueNumber = "001" inWork = "01" / >
< / dmIdent >
< dmAddressItems >
< issueDate year = "2023" month = "06" day = "15" / >
< dmTitle >
< techName > Example Technical Document < / techName >
< / dmTitle >
< / dmAddressItems >
< / dmAddress >
< dmStatus >
< security securityClassification = "01" / >
< responsiblePartnerCompany enterpriseCode = "COMP001" >
< enterpriseName > Example Company < / enterpriseName >
< / responsiblePartnerCompany >
< originator > John Doe < / originator >
< brexDmRef > BREX001 < / brexDmRef >
< qualityAssurance > QA passed < / qualityAssurance >
< / dmStatus >
< / identAndStatusSection >
< content > `
+ newDST +
` </content>
< / dmodule > `
// this.tempDivData.innerHTML
// ${this.convertHtmlToXmlContent(this.editorContent)}
console . log ( "${tempDiv.innerHTML}" , this . tempDivData . innerHTML )
console . log ( "${tempDiv}" , this . tempDivData )
let xmlData = this . fixHrTagsInContent ( this . fixBrTagsInContent ( this . fixImgTagsInContent ( xmlString , false ) , false ) , false ) ;
//存富文本信息
// const ht7 = this.tempDivData.innerHTML;
// console.log("3d转换之后7",ht7)
// const ht8 = xmlData;
// console.log("3d转换之后8",ht8)
// xmlData = this.replacemodel3dImages(xmlData);
if ( type ) {
console . log ( "存富文本内容时候1" , type , this . nowMaxId , xmlData )
this . $sendToDotNet ( 'SaveFile' , 'DMC' , this . nowMaxId , xmlData , '000' ) ;
} else {
console . log ( "存富文本内容时候2" , type , saveId , this . currentNode , xmlData )
this . $sendToDotNet ( 'SaveFile' , 'DMC' , saveId ? saveId : this . currentNode . id , xmlData , this . currentNode . lagreVersion ) ;
this . lastClick = this . currentNode . id ;
}
if ( this . navIsAdd == 'create' ) {
// this.currentNode = '';
// this.getDmName = this.domNameStr[0]+this.domNameStr[1]+this.domNameStr[2]+this.nowMaxId+this.domNameStr[3]+this.domNameStr[4];
// console.log("新建目录以后调到新的DMC",this.getDmName)
// this.loadFWBFile(this.getDmName);
}
// this.successTips('目录保存完成')
// 处理content标签内的img标签
// this.xmlDownload(xmlData)
// this.xmlDownload(this.fixImgTagsInContent(xmlString, false))
} ,
// 创建XML文件然后下载
xmlDownload ( xmlString ) {
// Create download link
const blob = new Blob ( [ xmlString ] , { type : 'text/xml' } )
const url = URL . createObjectURL ( blob )
const a = document . createElement ( 'a' )
a . href = url
a . download = 'document.xml'
document . body . appendChild ( a )
a . click ( )
document . body . removeChild ( a )
URL . revokeObjectURL ( url )
} ,
// // XML文件标签剔除
// restoreContent(html) {
// console.log("XML初始内容: ",html)
// if (html) {
// const tempDiv = document.createElement('div')
// tempDiv.innerHTML = html
// // 处理所有dmTitle标签
// const dmTitles = tempDiv.querySelectorAll('dmTitle')
// dmTitles.forEach(dmTitle => {
// // 获取dmTitle的子节点
// const children = Array.from(dmTitle.childNodes)
// // 在dmTitle之前插入所有子节点
// children.forEach(child => {
// dmTitle.parentNode.insertBefore(child.cloneNode(true), dmTitle)
// })
// // 移除dmTitle
// dmTitle.parentNode.removeChild(dmTitle)
// })
// console.log('内容还原完成! dmTitle标签已被移除')
// console.log("tempDiv.innerHTML",tempDiv.innerHTML)
// this.editor.txt.html(tempDiv.innerHTML)
// }else{
// console.log("空白文档")
// this.editor.txt.html('')
// }
// this.editor.txt.html(tempDiv.innerHTML)
// },
//删除视频
deleteAllVideos ( ) {
const videoWrappers = document . querySelectorAll ( '.video-wrapper' )
if ( videoWrappers . length === 0 ) {
console . log ( '没有找到可删除的视频' )
return
}
videoWrappers . forEach ( wrapper => {
wrapper . remove ( )
} )
// 删除可能残留的空段落
const editor = this . $refs . editor
const paragraphs = editor . querySelectorAll ( 'p' )
paragraphs . forEach ( p => {
if ( p . textContent . trim ( ) === '' && p . children . length === 0 ) {
p . remove ( )
}
} )
// 使用正确的方式通知内容变更
if ( this . editor . txt ) {
this . editor . txt . html ( this . editor . txt . html ( ) ) // 强制更新编辑器内容
}
console . log ( ` 已删除 ${ videoWrappers . length } 个视频 ` )
} ,
// 加载所有内容到 main 容器
loadAllContent ( ) {
const mainContainer = document . getElementById ( 'main' )
mainContainer . innerHTML = this . editorContent ;
console . log ( "this.editorContent" , this . editorContent )
// 为main容器中的标题添加ID
this . addHeadingIds ( mainContainer )
} ,
// 为标题元素添加ID
addHeadingIds ( container ) {
const headings = container . querySelectorAll ( 'h1, h2, h3, h4, h5, h6' )
headings . forEach ( ( heading , index ) => {
if ( ! heading . id ) {
heading . id = ` heading- ${ index } - ${ Date . now ( ) } `
console . log ( "Date.now" , Date . now ( ) )
}
} )
} ,
// 生成带锚点的目录
generateTOC ( ) {
const navContainer = document . getElementById ( 'nav' )
navContainer . innerHTML = '' // 清空原有目录
// 确保main容器已加载内容
// if (!document.getElementById('main').innerHTML) {
this . loadAllContent ( )
// }
const mainContainer = document . getElementById ( 'main' )
const headings = mainContainer . querySelectorAll ( 'h1, h2, h3, h4, h5, h6' )
console . log ( "headings.length" , headings . length )
if ( headings . length === 0 ) {
2025-07-25 13:28:47 +08:00
navContainer . innerHTML = '<p>没有找到标题元素,无法生成目录。</p>'
return
}
const tocList = document . createElement ( 'ul' )
tocList . style . listStyleType = 'none'
tocList . style . paddingLeft = '0'
headings . forEach ( heading => {
2025-09-15 09:58:52 +08:00
console . log ( "heading" , )
2025-07-25 13:28:47 +08:00
const level = parseInt ( heading . tagName . substring ( 1 ) )
const listItem = document . createElement ( 'li' )
2025-09-15 09:58:52 +08:00
listItem . style . marginLeft = ` ${ ( level - 1 ) * 1.2 } rem ` ;
listItem . style . marginBottom = '5px' ;
let fontSize = '12px'
switch ( level ) {
case 1 :
fontSize = '30px'
break ;
case 2 :
fontSize = '26px'
break ;
case 3 :
fontSize = '22px'
break ;
case 4 :
fontSize = '18px'
break ;
case 5 :
fontSize = '20px'
break ;
}
listItem . style . fontSize = fontSize ;
2025-07-25 13:28:47 +08:00
const link = document . createElement ( 'a' )
link . href = ` # ${ heading . id } `
link . textContent = heading . textContent
link . style . textDecoration = 'none'
link . style . color = '#333'
// 添加平滑滚动效果
link . addEventListener ( 'click' , ( e ) => {
e . preventDefault ( )
document . getElementById ( heading . id ) . scrollIntoView ( {
behavior : 'smooth'
} )
} )
listItem . appendChild ( link )
2025-09-15 09:58:52 +08:00
tocList . appendChild ( listItem )
2025-07-25 13:28:47 +08:00
} )
const tocContainer = document . createElement ( 'div' )
tocContainer . style . border = '1px solid #ddd'
tocContainer . style . padding = '15px'
tocContainer . style . marginBottom = '20px'
tocContainer . style . background = '#f9f9f9'
tocContainer . style . borderRadius = '4px'
const tocTitle = document . createElement ( 'h2' )
tocTitle . textContent = '目录'
tocTitle . style . marginTop = '0'
tocContainer . appendChild ( tocTitle )
tocContainer . appendChild ( tocList )
navContainer . appendChild ( tocContainer )
2025-07-28 17:01:13 +08:00
} ,
2025-09-15 09:58:52 +08:00
// 处理所有标题元素的ID
processHeadingIds ( ) {
if ( ! this . editor ) return
// 获取当前时间戳( 简化版, 只取后8位)
const timestamp = Date . now ( ) . toString ( ) . slice ( - 8 ) ;
let timestamps = parseInt ( Date . now ( ) . toString ( ) . slice ( - 8 ) ) ;
console . log ( "时间戳" , timestamp , timestamps )
// 获取编辑器内容
const editorHtml = this . editor . txt . html ( )
if ( ! editorHtml ) return
// 创建一个临时div来操作DOM
const tempDiv = document . createElement ( 'div' )
tempDiv . innerHTML = editorHtml
// 获取所有标题元素
const headings = tempDiv . querySelectorAll ( 'h1, h2, h3, h4, h5, h6' )
headings . forEach ( ( heading , index ) => {
console . log ( "index" , index )
// 生成3个随机字母 + 时间戳后8位
// const newId = `heading-${randomLetters}-${timestamp}`
const randomLetters = this . getRandomLetters ( this . idLength )
// const newId = `${heading.id}${randomLetters}${timestamps}`
timestamps ++ ;
console . log ( "timestamp" , timestamps )
const newId = ` ${ randomLetters } `
if ( heading . id . length < this .idLength ) {
heading . id = newId
}
} )
// 将修改后的HTML设置回编辑器
this . editor . txt . html ( tempDiv . innerHTML ) ;
setTimeout ( ( ) => {
this . generateTOC ( )
} , 200 ) ;
} ,
// 生成随机字母
getRandomLetter ( ) {
const letters = 'abcdefghijklmnopqrstuvwxyz1234567890'
return letters . charAt ( Math . floor ( Math . random ( ) * letters . length ) )
} ,
// 生成随机字母组合
getRandomLetters ( length ) {
let result = ''
for ( let i = 0 ; i < length ; i ++ ) {
result += this . getRandomLetter ( )
}
return result
} ,
2025-07-28 17:01:13 +08:00
// 生成S1000D XML模板
generateS1000DTemplate ( content ) {
const { dmc , issueInfo , language } = this . dmConfig ;
return ` <?xml version="1.0" encoding="UTF-8"?>
< ! DOCTYPE dmodule [
< ! ENTITY % ISOEntities PUBLIC "ISO 8879-1986//ENTITIES ISO Character Entities 20030531//EN//XML" "http://www.s1000d.org/S1000D_4-1/ent/ISOEntities" >
% ISOEntities ;
] >
< dmodule xmlns :xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi :noNamespaceSchemaLocation = "http://www.s1000d.org/S1000D_4-1/xml_schema_flat/descript.xsd" >
< idstatus >
< dmaddress >
< dmc >
< avee > $ { dmc . modelIdentCode } - $ { dmc . systemDiffCode } - $ { dmc . systemCode } - $ { dmc . subSystemCode } - $ { dmc . subSubSystemCode } - $ { dmc . assyCode } - $ { dmc . disassyCode } - $ { dmc . disassyCodeVariant } < / avee >
< avee > $ { dmc . infoCode } - $ { dmc . infoCodeVariant } - $ { dmc . itemLocationCode } < / avee >
< / dmc >
< / dmaddress >
< issueinfo >
< issue number = "${issueInfo.issueNumber}" inwork = "${issueInfo.inWork}" date = "${issueInfo.issueDate}" / >
< language country = "${language.split('-')[1]}" language = "${language.split('-')[0]}" / >
< / issueinfo >
< / idstatus >
< content >
< description >
$ { this . escapeXml ( content ) }
< / description >
< / content >
< / dmodule > ` ;
} ,
// XML特殊字符转义
escapeXml ( unsafe ) {
return unsafe . replace ( /[<>&'"]/g , ( c ) => {
switch ( c ) {
case '<' : return '<' ;
case '>' : return '>' ;
case '&' : return '&' ;
case '\'' : return ''' ;
case '"' : return '"' ;
default : return c ;
}
} ) ;
} ,
// 更新XML预览
updateXmlPreview ( html ) {
try {
this . xmlPreview = this . generateS1000DTemplate ( html ) ;
} catch ( e ) {
console . error ( '生成XML预览失败:' , e ) ;
this . xmlPreview = ` 生成XML预览时出错: ${ e . message } ` ;
}
} ,
// 导出为S1000D XML文件
exportToS1000D ( ) {
const html = this . editor . txt . html ( ) ;
const xmlContent = this . generateS1000DTemplate ( html ) ;
// 下载文件
const blob = new Blob ( [ xmlContent ] , { type : 'application/xml' } ) ;
const link = document . createElement ( 'a' ) ;
link . href = URL . createObjectURL ( blob ) ;
link . download = ` s1000d- ${ this . dmConfig . dmc . modelIdentCode } - ${ this . dmConfig . issueInfo . issueNumber } .xml ` ;
link . click ( ) ;
URL . revokeObjectURL ( link . href ) ;
} ,
// 从S1000D XML导入
handleS1000DUpload ( event ) {
const file = event . target . files [ 0 ] ;
if ( ! file ) return ;
const reader = new FileReader ( ) ;
reader . onload = ( e ) => {
const xmlString = e . target . result ;
const html = this . extractContentFromS1000D ( xmlString ) ;
2025-09-15 09:58:52 +08:00
// const parser = new DOMParser();
// const xmlDoc = parser.parseFromString(html, 'text/xml');
// 获取 content 元素
const contentElement = html . querySelector ( 'content' ) ;
console . log ( "contentElement" , contentElement )
if ( contentElement ) {
// 提取 content 内部的所有子节点并转换为字符串
let innerHtml = '' ;
Array . from ( contentElement . childNodes ) . forEach ( node => {
innerHtml += new XMLSerializer ( ) . serializeToString ( node ) ;
} ) ;
console . log ( "innerHtml" , innerHtml )
this . editor . txt . html ( innerHtml )
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
// if (html) {
// this.editor.txt.html(html);
// // this.updateXmlPreview(html);
// }
2025-07-28 17:01:13 +08:00
// 重置input值, 允许重复选择同一文件
event . target . value = '' ;
} ;
reader . readAsText ( file ) ;
} ,
// 从S1000D XML提取内容
extractContentFromS1000D ( xmlString ) {
try {
// 简单提取description内容
const descriptionMatch = xmlString . match ( /<description>([\s\S]*?)<\/description>/i ) ;
if ( ! descriptionMatch || ! descriptionMatch [ 1 ] ) {
throw new Error ( '未找到description内容' ) ;
}
// 反转义XML特殊字符
let content = descriptionMatch [ 1 ]
. replace ( /</g , '<' )
. replace ( />/g , '>' )
. replace ( /&/g , '&' )
. replace ( /'/g , "'" )
. replace ( /"/g , '"' ) ;
// 移除可能的多余空格和换行
content = content . trim ( ) ;
return content ;
} catch ( e ) {
console . error ( 'S1000D导入错误:' , e ) ;
alert ( ` 导入S1000D XML失败: ${ e . message } ` ) ;
return '' ;
}
} ,
2025-09-15 09:58:52 +08:00
rgbToHex ( r , g , b ) { //色号转换
console . log ( "colors" , this . colors )
return ` # ${ [ r , g , b ] . map ( x => x . toString ( 16 ) . padStart ( 2 , '0' ) ) . join ( '' ) } ` ;
} ,
2025-07-28 17:01:13 +08:00
// 验证当前XML
validateCurrentXml ( ) {
2025-09-15 09:58:52 +08:00
2025-07-28 17:01:13 +08:00
const validationResult = this . validateS1000DXml ( this . xmlPreview ) ;
this . validationResult = validationResult ;
} ,
// 基本S1000D XML验证
validateS1000DXml ( xmlString ) {
try {
// 检查基本结构
const hasDmodule = xmlString . includes ( '<dmodule' ) ;
const hasIdstatus = xmlString . includes ( '<idstatus' ) ;
const hasContent = xmlString . includes ( '<content' ) ;
if ( ! hasDmodule ) {
return {
valid : false ,
message : '无效的S1000D文档: 缺少dmodule根元素'
} ;
}
if ( ! hasIdstatus ) {
return {
valid : false ,
message : '缺少必需的S1000D元素: idstatus'
} ;
}
if ( ! hasContent ) {
return {
valid : false ,
message : '缺少必需的S1000D元素: content'
} ;
}
// 检查dmc结构
const hasDmc = xmlString . includes ( '<dmc>' ) ;
const hasAvee = xmlString . includes ( '<avee>' ) ;
if ( ! hasDmc || ! hasAvee ) {
return {
valid : false ,
message : '无效的dmc结构: 缺少dmc或avee元素'
} ;
}
return {
valid : true ,
message : 'XML文档符合S1000D基本结构要求'
} ;
} catch ( e ) {
return {
valid : false ,
message : ` 验证过程中发生错误: ${ e . message } `
} ;
}
2025-09-15 09:58:52 +08:00
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
//保存内容到XML
generateXml ( type , saveId ) {
this . dataXmlProcessing ( type , saveId ) ;
} ,
//测试 保存目录到XML
navXml ( ) {
const xmlString = ` <?xml version="1.0" encoding="UTF-8"?>
< dmodule xmlns :xlink = "http://www.w3.org/1999/xlink" xmlns :rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" >
< identAndStatusSection >
< dmAddress >
< dmIdent >
< dmCode
modelIdentCode = "EXAMPLE01"
systemDiffCode = "A1"
systemCode = "SYS"
subSystemCode = "A"
subSubSystemCode = "B"
assyCode = "AS01"
disassyCode = "DS"
disassyCodeVariant = "001"
infoCode = "INF"
infoCodeVariant = "1"
itemLocationCode = "A"
/ >
< language languageIsoCode = "en" countryIsoCode = "US" / >
< issueInfo issueNumber = "001" inWork = "01" / >
< / dmIdent >
< dmAddressItems >
< issueDate year = "2023" month = "06" day = "15" / >
< dmTitle >
< techName > Example Technical Document < / techName >
< / dmTitle >
< / dmAddressItems >
< / dmAddress >
< dmStatus >
< security securityClassification = "01" / >
< responsiblePartnerCompany enterpriseCode = "COMP001" >
< enterpriseName > Example Company < / enterpriseName >
< / responsiblePartnerCompany >
< originator > John Doe < / originator >
< brexDmRef > BREX001 < / brexDmRef >
< qualityAssurance > QA passed < / qualityAssurance >
< / dmStatus >
< / identAndStatusSection >
< content > < infoCode > `
+ JSON . stringify ( this . treeData ) +
` </infoCode></content>
< / dmodule > ` ;
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
const blob = new Blob ( [ xmlString ] , { type : 'text/xml' } )
const url = URL . createObjectURL ( blob )
const a = document . createElement ( 'a' )
a . href = url
a . download = 'mulu.xml'
document . body . appendChild ( a )
a . click ( )
document . body . removeChild ( a )
URL . revokeObjectURL ( url )
} ,
//测试 加载XML
loadXml ( ) {
this . $refs . fileInput . click ( )
} ,
//测试 选择文件
handleFileUpload ( event ) {
const file = event . target . files [ 0 ]
if ( ! file ) return
const reader = new FileReader ( )
reader . onload = ( e ) => {
const xmlContent = e . target . result
// console.log("xmlContent",xmlContent)
const parser = new DOMParser ( )
const xmlDoc = parser . parseFromString ( xmlContent , "text/xml" )
console . log ( "xmlDoc" , xmlDoc )
const contentNodes = xmlDoc . getElementsByTagName ( 'content' ) [ 0 ] ;
console . log ( "xmlDoc.getElementsByTagName('content')" , xmlDoc . getElementsByTagName ( 'content' ) )
console . log ( "contentNodes" , contentNodes )
if ( contentNodes ) {
const htmlContent = this . convertXmlContentToHtml ( contentNodes . innerHTML )
// this.editor.txt.html(htmlContent)
//处理过后再导入
// this.restoreContent(htmlContent)
this . restoreContentXh ( htmlContent )
}
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
reader . readAsText ( file )
} ,
completeModel3DTags ( htmlString ) {
// 处理自闭合的model3d标签, 替换为完整的闭合标签
return htmlString . replace ( /<model3d([^>]*?)\/>/g , ( match , attributes ) => {
// 返回带有相同属性的完整闭合标签
return ` <model3d ${ attributes } ></model3d> ` ;
} ) ;
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 解析xml里面 content内容
convertXmlContentToHtml ( xmlContent ) {
return xmlContent
. replace ( /<para>/g , '<p>' )
. replace ( /<\/para>/g , '</p>' )
. replace ( /<emphasis emphasisType="bold">/g , '<strong>' )
. replace ( /<\/emphasis>/g , '</strong>' )
. replace ( /<emphasis emphasisType="italic">/g , '<em>' )
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
/ * *
* 修复content标签内的img标签闭合符
* @ param { string } inputStr 输入HTML
* @ param { boolean } useSlash 是否使用自闭合
* @ returns { string } 修正后的HTML
* /
fixImgTagsInContent ( inputStr , useSlash ) {
const contentRegex = /<content>([\s\S]*?)<\/content>/g
return inputStr . replace ( contentRegex , ( contentMatch , innerContent ) => {
const fixedInnerContent = innerContent . replace (
/<img\b([^>]*)>/g ,
( imgMatch , imgAttributes ) => {
// 已有闭合符则不处理
if ( imgMatch . endsWith ( '/>' ) || imgMatch . includes ( '</img>' ) ) {
return imgMatch
}
// 根据参数决定闭合方式
return useSlash
? ` <img ${ imgAttributes } /> `
: ` <img ${ imgAttributes } ></img> `
}
)
return ` <content> ${ fixedInnerContent } </content> `
} )
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 检测hr标签是否闭合
fixHrTagsInContent ( inputStr , useSlash ) {
const contentRegex = /<content>([\s\S]*?)<\/content>/g
return inputStr . replace ( contentRegex , ( contentMatch , innerContent ) => {
const fixedInnerContent = innerContent . replace (
/<hr\b([^>]*)>/g ,
( imgMatch ) => {
// 已有闭合符则不处理
if ( imgMatch . endsWith ( '/>' ) || imgMatch . includes ( '</hr>' ) ) {
return imgMatch
}
// 根据参数决定闭合方式
return useSlash
? ` <hr/> `
: ` <hr></hr> `
}
)
return ` <content> ${ fixedInnerContent } </content> `
} )
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// 检测br标签是否闭合
fixBrTagsInContent ( inputStr , useSlash ) {
const contentRegex = /<content>([\s\S]*?)<\/content>/g
return inputStr . replace ( contentRegex , ( contentMatch , innerContent ) => {
const fixedInnerContent = innerContent . replace (
/<br\b([^>]*)>/g ,
( imgMatch , imgAttributes ) => {
// 已有闭合符则不处理
if ( imgMatch . endsWith ( '/>' ) || imgMatch . includes ( '</br>' ) ) {
return imgMatch
}
// 根据参数决定闭合方式
return useSlash
? ` <br ${ imgAttributes } /> `
: ` <br ${ imgAttributes } ></br> `
}
)
return ` <content> ${ fixedInnerContent } </content> `
} )
} ,
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
//富文本内容打标签
dataXmlProcessing ( type , saveId ) {
let html = this . editor . txt . html ( )
console . log ( '保存内容' , html ) ;
// 正则表达式: 匹配img、audio、video标签的src属性
// 支持三种标签:<img ...>、<audio ...>、<video ...>
// 捕获组1: 标签名和src="之前的部分
// 捕获组2: 提取文件名(最后一个/后面的内容)
// 捕获组3: 保留"及之后的部分
const reg = /(<(img|audio|video)[^>]+src=")[^"]+\/([^"]+)("[^>]*>)/gi ;
// 替换为: src="文件名"
let html _1 = html . replace ( reg , '$1$3$4' ) ;
console . log ( '解析地址:' , html _1 )
2025-07-25 13:28:47 +08:00
2025-09-15 09:58:52 +08:00
// const reg2 = /(<(img|audio|video)[^>]+src=")(?!http:\/\/)([^"]+)("[^>]*>)/gi;
// let jc = 'http://localhost:5432/';
// // 替换为: src="基础URL+文件名"
// // 这里假设原路径可能包含DM_Material目录, 如果不需要可以去掉
// let html_2 = html_1.replace(reg2, `$1${jc}$3$4`);
// console.log('还原地址:',html_2)
this . tempDivData = document . createElement ( 'div' )
html _1 = this . replacemodel3dImages ( html _1 ) ;
// const ht1 = html_1;
// console.log("3d转换之后1",ht1)
this . tempDivData . innerHTML = html _1 ;
this . xh ( this . oldSelector , this . newSelector , type , saveId ) ;
} ,
// XML文件标签剔除
restoreContentXh ( html ) {
console . log ( "XML初始内容: " , html )
if ( html ) {
this . tempDivData = document . createElement ( 'div' )
this . tempDivData . innerHTML = html
let times = this . oldSelector . length ;
for ( let i = 0 ; i < times ; i + + ) {
// 处理所有dmTitle标签
const dmTitles = this . tempDivData . querySelectorAll ( this . newSelector [ i ] )
dmTitles . forEach ( dmTitle => {
// 获取dmTitle的子节点
const children = Array . from ( dmTitle . childNodes )
console . log ( "剔除标签:" , dmTitles , children )
// 在dmTitle之前插入所有子节点
children . forEach ( child => {
dmTitle . parentNode . insertBefore ( child . cloneNode ( true ) , dmTitle )
} )
// 移除dmTitle
dmTitle . parentNode . removeChild ( dmTitle )
console . log ( "剔除标签移除:" , dmTitle , '替换成' , dmTitle )
} )
}
console . log ( '内容还原完成! dmTitle标签已被移除' )
console . log ( "tempDiv.innerHTML" , this . tempDivData . innerHTML )
const reg2 = /(<(img|audio|video)[^>]+src=")(?!http:\/\/)([^"]+)("[^>]*>)/gi ;
let jc = this . lisenPath ;
// 检查并去除开头的双引号
if ( jc . startsWith ( '"' ) ) {
jc = jc . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( jc . endsWith ( '"' ) ) {
jc = jc . substring ( 0 , jc . length - 1 ) ;
}
// 替换为: src="基础URL+文件名"
// 这里假设原路径可能包含DM_Material目录, 如果不需要可以去掉
let html _2 = this . tempDivData . innerHTML . replace ( reg2 , ` $ 1 ${ jc } $ 3 $ 4 ` ) ;
// html_2 = this.modelToImg(html_2);
console . log ( '还原地址:' , html _2 )
this . editor . txt . html ( html _2 )
this . contentXmlStr = this . editor . txt . html ( ) ;
} else {
console . log ( "空白文档" )
this . editor . txt . html ( '' )
this . contentXmlStr = this . editor . txt . html ( ) ;
}
} ,
// XML文件标签剔除
restoreContentXh2 ( html ) {
console . log ( "XML初始内容: " , html )
if ( html ) {
this . tempDivData1 = document . createElement ( 'div' )
this . tempDivData1 . innerHTML = html
let times = this . oldSelector . length ;
for ( let i = 0 ; i < times ; i + + ) {
// 处理所有dmTitle标签
const dmTitles = this . tempDivData1 . querySelectorAll ( this . newSelector [ i ] )
dmTitles . forEach ( dmTitle => {
// 获取dmTitle的子节点
const children = Array . from ( dmTitle . childNodes )
console . log ( "剔除标签:" , dmTitles , children )
// 在dmTitle之前插入所有子节点
children . forEach ( child => {
dmTitle . parentNode . insertBefore ( child . cloneNode ( true ) , dmTitle )
} )
// 移除dmTitle
dmTitle . parentNode . removeChild ( dmTitle )
console . log ( "剔除标签移除:" , dmTitle , '替换成' , dmTitle )
} )
}
console . log ( '内容还原完成! dmTitle标签已被移除' )
console . log ( "tempDiv.innerHTML" , this . tempDivData1 . innerHTML )
const reg2 = /(<(model3d|img|audio|video)[^>]+src=")(?!http:\/\/)([^"]+)("[^>]*>)/gi ;
let jc = this . viewLis ;
// 检查并去除开头的双引号
if ( jc . startsWith ( '"' ) ) {
jc = jc . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( jc . endsWith ( '"' ) ) {
jc = jc . substring ( 0 , jc . length - 1 ) ;
}
if ( ! this . dialogVisibleNav ) {
jc = jc + this . historyVsPath + '/' ;
}
// 替换为: src="基础URL+文件名"
// 这里假设原路径可能包含DM_Material目录, 如果不需要可以去掉
const html _2 = this . tempDivData1 . innerHTML . replace ( reg2 , ` $ 1 ${ jc } $ 3 $ 4 ` ) ;
// html_2 = this.modelToImg(html_2);
console . log ( '加载还原地址:' , html _2 )
this . neirong = this . modelToImg ( html _2 ) ;
// document.getElementsByClassName("loadContent")[0].innerHTML=html_2;
// document.getElementsByClassName("loadContent1")[0].innerHTML=html_2;
console . log ( '加载还原地址:' , html _2 )
// this.editor.txt.html(html_2)
// this.contentXmlStr = this.editor.txt.html();
} else {
console . log ( "空白文档" )
// this.editor.txt.html('')
// this.contentXmlStr = this.editor.txt.html();
}
} ,
//处理 3d模型标签
replaceModel3dToImg ( htmlString ) {
// 创建临时DOM元素处理HTML
const tempDiv = document . createElement ( 'div' ) ;
tempDiv . innerHTML = htmlString ;
// 查找所有model3d标签
const model3dElements = tempDiv . querySelectorAll ( 'model3d' ) ;
model3dElements . forEach ( model3d => {
// 创建新的img元素
const img = document . createElement ( 'img' ) ;
// 复制所有属性
Array . from ( model3d . attributes ) . forEach ( attr => {
img . setAttribute ( attr . name , attr . value ) ;
} ) ;
// 替换元素
model3d . parentNode . replaceChild ( img , model3d ) ;
} ) ;
return tempDiv . innerHTML ;
} ,
//判断富文本内容是否更改
dmcIsChange ( ) {
console . log ( "this.editor.txt.html()" , this . editor . txt . html ( ) )
console . log ( "this.contentXmlStr" , this . contentXmlStr )
console . log ( "验证结果" , this . editor . txt . html ( ) == this . contentXmlStr )
return this . editor . txt . html ( ) == this . contentXmlStr ;
} ,
//测试 启用右键功能
enableContextMenu ( ) {
console . log ( "进入isContextMenuEnabled" , this . isContextMenuEnabled )
if ( this . isContextMenuEnabled ) return ;
this . isContextMenuEnabled = true ;
// 获取#nav下的所有li元素
const tocItems = document . querySelectorAll ( '.elTree .el-tree-node__content' ) ;
// 为每个li元素绑定右键事件
tocItems . forEach ( ( item , index ) => {
// 为元素设置唯一ID
const elementId = ` toc-item- ${ index } ` ;
item . id = elementId ;
// 初始化参数存储
if ( ! this . itemParams [ elementId ] ) {
this . $set ( this . itemParams , elementId , '' ) ;
}
item . addEventListener ( 'contextmenu' , ( e ) => {
e . preventDefault ( ) ;
this . showContextMenu ( e , item ) ;
} ) ;
item . addEventListener ( 'click' , ( e ) => {
console . log ( "左键" , e , item )
this . dialogVisible = true ;
} ) ;
} ) ;
// alert('右键菜单功能已启用!');
} ,
//测试 显示右键菜单
showContextMenu ( e , element ) {
console . log ( "ID" , element )
// 获取该 <a> 元素
// const linkElement = element.querySelector('#toc-item-0 a');
// 提取 # 后面的参数
// const hashValue = linkElement.getAttribute('href');
// const hashValue2 = hashValue.split('#')[1];
// console.log(hashValue,hashValue2);
if ( ! this . isContextMenuEnabled ) return ;
// 设置右键菜单位置和当前选中元素
this . contextMenu = {
visible : true ,
x : e . clientX ,
y : e . clientY ,
selectedElement : element ,
selectedParam : this . itemParams [ element . id ] || ''
}
// 点击其他地方关闭菜单
document . addEventListener ( 'click' , this . closeContextMenu , { once : true } ) ;
} ,
//测试 关闭右键菜单
closeContextMenu ( ) {
this . contextMenu . visible = false ;
} ,
//测试 选择右键菜单选项
selectMenuOption ( option ) {
if ( this . contextMenu . selectedElement ) {
const element = this . contextMenu . selectedElement ;
// 更新元素的参数
this . $set ( this . itemParams , element . id , option ) ;
// 在元素上显示参数(可选)
const paramSpan = element . querySelector ( '.param-display' ) ;
if ( paramSpan ) {
paramSpan . textContent = ` ( ${ option } ) ` ;
} else {
const span = document . createElement ( 'span' ) ;
span . className = 'param-display' ;
span . style . cssText = 'color: #f00; margin-left: 10px;' ;
span . textContent = ` ( ${ option } ) ` ;
element . appendChild ( span ) ;
}
this . closeContextMenu ( ) ;
}
} ,
// 新增方法: 打印nav内容
logTocItems ( ) {
const navElement = document . getElementById ( 'nav' ) ;
if ( ! navElement ) {
console . error ( '未找到ID为"nav"的容器' ) ;
return ;
}
// 获取nav内的HTML内容
const navHtml = navElement . innerHTML ;
// 获取nav内的文本内容
const navText = navElement . innerText || navElement . textContent ;
// 获取结构化数据(包括参数)
const structuredData = this . getStructuredNavData ( ) ;
console . log ( '====== nav的HTML内容 ======' ) ;
console . log ( navHtml ) ;
console . log ( '====== nav的文本内容 ======' ) ;
console . log ( navText ) ;
console . log ( '====== nav的结构化数据 ======' ) ;
console . log ( structuredData ) ;
} ,
// 获取结构化数据
getStructuredNavData ( ) {
const items = document . querySelectorAll ( '#nav ul li' ) ;
return Array . from ( items ) . map ( item => {
return {
id : item . id ,
text : item . innerText . trim ( ) ,
html : item . innerHTML ,
param : this . itemParams [ item . id ] || '未设置'
} ;
} ) ;
} ,
//测试 查看图片
openDialog ( ) {
// this.imageStyle();
const imgItems = document . querySelectorAll ( '#main img' ) ;
console . log ( "imgItems" , imgItems )
imgItems . forEach ( ( item , index ) => {
item . addEventListener ( 'click' , ( e ) => {
console . log ( "左键" , e , item , index , item . src )
// 通过选择器获取
// let imgSrc = e.src;
this . scale = 1 ;
this . rotation = 0 ;
this . currentImage = item . src ;
this . dialogVisibleImg = true ;
} ) ;
} ) ;
// this.currentImage = this.images[index]
// this.dialogVisible = true
// this.reset() // 每次打开重置状态
} ,
//测试 放大
zoomIn ( ) {
console . log ( "放大" )
this . scale = 1.1 * this . scale
} ,
//测试 缩小
zoomOut ( ) {
if ( this . scale > 0.5 ) {
this . scale -= 0.2
}
} ,
//测试 旋转
rotate ( ) {
this . rotation += 90
} ,
//测试 重置
reset ( ) {
this . scale = 1
this . rotation = 0
this . translateX = 0
this . translateY = 0
} ,
//测试 开始拖动
startDrag ( e ) {
this . isDragging = true
this . startX = e . type === 'mousedown' ? e . clientX : e . touches [ 0 ] . clientX
this . startY = e . type === 'mousedown' ? e . clientY : e . touches [ 0 ] . clientY
document . addEventListener ( 'mousemove' , this . dragImage )
document . addEventListener ( 'touchmove' , this . dragImage )
document . addEventListener ( 'mouseup' , this . endDrag )
document . addEventListener ( 'touchend' , this . endDrag )
} ,
//测试 拖动图片
dragImage ( e ) {
if ( ! this . isDragging ) return
const clientX = e . type === 'mousemove' ? e . clientX : e . touches [ 0 ] . clientX
const clientY = e . type === 'mousemove' ? e . clientY : e . touches [ 0 ] . clientY
this . translateX += ( clientX - this . startX ) / this . scale
this . translateY += ( clientY - this . startY ) / this . scale
this . startX = clientX
this . startY = clientY
} ,
//测试 停止拖动
endDrag ( ) {
this . isDragging = false
document . removeEventListener ( 'mousemove' , this . dragImage )
document . removeEventListener ( 'touchmove' , this . dragImage )
document . removeEventListener ( 'mouseup' , this . endDrag )
document . removeEventListener ( 'touchend' , this . endDrag )
} ,
//测试 图片样式
imageStyle ( ) {
return {
transform : `
scale ( $ { this . scale } )
rotate ( $ { this . rotation } deg )
translate ( $ { this . translateX } px , $ { this . translateY } px )
` ,
cursor : this . isDragging ? 'grabbing' : 'grab'
}
} ,
gengxin ( ) {
document . getElementsByClassName ( 'w-e-text-container' ) [ 0 ] . style . height = ( window . innerHeight - 240 ) + 'px' ;
document . getElementsByClassName ( 'w-e-text-container' ) [ 1 ] . style . height = ( window . innerHeight - 240 ) + 'px' ;
} ,
//获取屏幕尺寸
getWindowSize ( ) {
// this.windowW = window.innerWidth
// this.windowH = window.innerHeigh
// t
this . leftHeight = window . innerHeight - 200 ;
this . editorHeight = window . innerHeight - 200 ;
} ,
// 尺寸变化时的处理函数
handleResize ( ) {
// 使用节流优化性能(频繁触发时限制执行频率)
if ( this . resizeTimer ) clearTimeout ( this . resizeTimer )
this . resizeTimer = setTimeout ( ( ) => {
this . getWindowSize ( )
console . log ( '窗口尺寸变化:' , this . windowW , this . windowH )
// 在这里可以添加尺寸变化后的业务逻辑
// 例如:调整组件布局、重新计算元素位置等
} , 100 ) // 100ms 节流延迟,可根据需求调整
} ,
// 加载XML文件 dmc
loadFileBtn ( ) {
this . $sendToDotNet ( 'GetExistenceDMContent' )
} ,
// 获取屏幕和窗口尺寸
getScreenSize ( ) {
// 屏幕整体尺寸(设备的屏幕尺寸)
this . screenWidth = window . screen . width ;
this . screenHeight = window . screen . height ;
// 浏览器窗口尺寸(可视区域尺寸)
this . windowW = window . innerWidth ;
this . windowH = window . innerHeight ;
console . log ( "屏幕变化的尺寸" , window . screen . width , window . screen . height , window . innerWidth , window . innerHeight )
// 可以在这里添加需要根据尺寸执行的逻辑
this . handleSizeChange ( ) ;
} ,
// 处理窗口大小变化(使用防抖优化性能)
// handleResize() {
// // 清除之前的定时器
// if (this.resizeTimer) {
// clearTimeout(this.resizeTimer);
// }
// // 防抖: 50ms后再执行, 避免频繁触发
// this.resizeTimer = setTimeout(() => {
// this.getScreenSize();
// this.resizeTimer = null;
// }, 50);
// },
// 根据尺寸变化执行的逻辑
handleSizeChange ( ) {
// 这里可以添加尺寸变化时需要执行的操作
console . log ( '尺寸变化:' , {
screenWidth : this . screenWidth ,
screenHeight : this . screenHeight ,
windowWidth : this . windowW ,
windowHeight : this . windowH
} ) ;
} ,
//预览加载的XML
viewLoadDMFile ( ) {
this . maskViewShow = true ;
// this.draggableVis = true;
// localStorage.setItem("fileName",'dassad')
this . $sendToDotNet ( 'DMPreview' , 'UserLocalDMPreview' )
} ,
//解析加载的DMC
parseXmlDmc ( ) {
try {
// 解析XML字符串
const parser = new DOMParser ( ) ;
const xmlDoc = parser . parseFromString ( this . loadFileXML , "text/xml" ) ;
// 检查解析错误
const errorNode = xmlDoc . querySelector ( "parsererror" ) ;
if ( errorNode ) {
throw new Error ( "XML解析错误: " + errorNode . textContent ) ;
}
// 提取content标签内容
this . extractContent ( xmlDoc ) ;
// 解析rdf:Description
this . parseRdfDescription ( xmlDoc ) ;
} catch ( error ) {
console . error ( "解析失败:" , error ) ;
// alert("解析XML失败: " + error.message);
}
} ,
//解析新建目录时候的DMC文件
parseXmlDmc _loadFile ( ) {
try {
// 解析XML字符串
const parser = new DOMParser ( ) ;
const xmlDoc = parser . parseFromString ( this . viewXml , "text/xml" ) ;
// 检查解析错误
const errorNode = xmlDoc . querySelector ( "parsererror" ) ;
if ( errorNode ) {
throw new Error ( "XML解析错误: " + errorNode . textContent ) ;
}
// 提取content标签内容
this . extractContent2 ( xmlDoc ) ;
} catch ( error ) {
console . error ( "解析失败:" , error ) ;
// alert("解析XML失败: " + error.message);
}
} ,
//验证是否修改过的dmc文件
handleCheckVersion ( ) {
this . showModifyBtn = true ;
// 可选: 若需高亮有01版本的节点, 可在此处触发树重渲染
this . $nextTick ( ( ) => {
this . $refs . tree . updateKeyChildren ( ) ; // 强制树更新节点
} ) ;
} ,
// 3. 递归判断: 当前节点或其所有子节点是否存在minorVersion: '01'
hasMinorVersion01 ( node ) {
// 边界条件: 节点不存在则返回false
if ( ! node ) return false ;
// 第一步: 检查当前节点是否为01版本
if ( node . minorVersion === '01' ) {
return true ;
}
// 第二步:若有子节点,递归检查所有子节点
if ( node . children && node . children . length > 0 ) {
// 只要有一个子节点满足, 就返回true
return node . children . some ( child => this . hasMinorVersion01 ( child ) ) ;
}
// 第三步: 无子孙节点且当前节点不是01版本, 返回false
return false ;
} ,
// 4. 【修改】文字点击事件(可根据需求扩展修改逻辑)
handleModify ( node ) {
console . log ( '当前需要修改的节点:' , node ) ;
// 示例:可打开修改弹窗、跳转修改页面等
// this.$emit('openModifyDialog', node);
} ,
// 提取content标签内的内容
extractContent ( xmlDoc ) {
const contentNodes = xmlDoc . getElementsByTagName ( "content" ) ;
if ( contentNodes . length === 0 ) {
this . contentResult = "未找到content标签" ;
return ;
}
const contentNode = contentNodes [ 0 ] ;
let contentHtml = "" ;
// 序列化content节点的所有子节点
for ( let i = 0 ; i < contentNode . childNodes . length ; i ++ ) {
const child = contentNode . childNodes [ i ] ;
// 忽略空文本节点
if ( child . nodeType === 1 || ( child . nodeType === 3 && child . textContent . trim ( ) ) ) {
contentHtml += new XMLSerializer ( ) . serializeToString ( child ) ;
}
}
this . loadFileDMC = contentHtml . trim ( ) ;
console . log ( "解析出来DMC内容" , contentHtml )
console . log ( "解析出来DMC内容" , contentHtml . trim ( ) )
// this.contentResult = contentHtml.trim();
} ,
// 提取新建目录时候的DMC文件中content标签内的内容
extractContent2 ( xmlDoc ) {
const contentNodes = xmlDoc . getElementsByTagName ( "content" ) ;
if ( contentNodes . length === 0 ) {
this . contentResult = "未找到content标签" ;
return ;
}
const contentNode = contentNodes [ 0 ] ;
let contentHtml = "" ;
// 序列化content节点的所有子节点
for ( let i = 0 ; i < contentNode . childNodes . length ; i ++ ) {
const child = contentNode . childNodes [ i ] ;
// 忽略空文本节点
if ( child . nodeType === 1 || ( child . nodeType === 3 && child . textContent . trim ( ) ) ) {
contentHtml += new XMLSerializer ( ) . serializeToString ( child ) ;
}
}
this . viewXmlContent = contentHtml . trim ( ) ;
console . log ( "加载解析出来DMC内容" , contentHtml )
console . log ( "加载解析出来DMC内容" , contentHtml . trim ( ) )
this . restoreContentXh2 ( this . viewXmlContent )
// this.contentResult = contentHtml.trim();
} ,
// 解析rdf:Description为对象
parseRdfDescription ( xmlDoc ) {
const rdfObj = { } ;
const rdfNamespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" ;
const rdfNode = xmlDoc . getElementsByTagNameNS ( rdfNamespace , "Description" ) [ 0 ] ;
if ( ! rdfNode ) {
// this.rdfResult = { error: "未找到rdf:Description标签" };
return ;
}
// 解析dc命名空间下的所有子节点
const dcNamespace = "http://purl.org/dc/elements/1.1/" ;
const dcNodes = rdfNode . getElementsByTagNameNS ( dcNamespace , "*" ) ;
Array . from ( dcNodes ) . forEach ( node => {
const key = node . localName ; // 获取不带命名空间前缀的标签名
const value = node . textContent . trim ( ) || "" ; // 处理空标签
rdfObj [ key ] = value ;
} ) ;
console . log ( "解析出来DMC目录内容" , rdfObj )
// this.rdfResult = rdfObj;
for ( let key in this . form ) {
this . form [ key ] = rdfObj [ key ] ? rdfObj [ key ] : '' ;
}
this . form . name = rdfObj . title ;
this . form . version = '000' ;
} ,
//转换时间值
timeChange ( isoTime ) {
const date = new Date ( isoTime ) ;
// 3. 提取时间组件(注意:月份从 0 开始,需 +1; 数字不足 2 位时补 0)
const year = date . getFullYear ( ) ; // 年份: 2025
const month = String ( date . getMonth ( ) + 1 ) . padStart ( 2 , "0" ) ; // 月份: 09( getMonth() 返回 8, +1 后补 0)
const day = String ( date . getDate ( ) ) . padStart ( 2 , "0" ) ; // 日期: 01
const hours = String ( date . getHours ( ) ) . padStart ( 2 , "0" ) ; // 小时: 16( 24小时制)
const minutes = String ( date . getMinutes ( ) ) . padStart ( 2 , "0" ) ; // 分钟: 39
const seconds = String ( date . getSeconds ( ) ) . padStart ( 2 , "0" ) ; // 秒: 07
// 4. 拼接成正常时间格式
const normalTime = ` ${ year } - ${ month } - ${ day } ${ hours } : ${ minutes } : ${ seconds } ` ;
return normalTime ;
} ,
// 关闭预览弹窗
handleCloseMask ( ) {
this . maskViewShow = false ;
} ,
//关闭弹窗节点
handleClose ( type ) {
console . log ( '点' , type ) ;
this . dialogVisibleHistory = false ;
this . dialogVisibleNav = false ;
this . dialogVisibleRight = false ;
this . dialogVisibleTips = false ;
this . dialogVisibleTips2 = false ;
this . dialogVisibleBland = false ;
this . dialogVisibleBland = false ;
this . currentNode = null ;
this . clearNodeState ( ) ;
} ,
handleClose2 ( ) {
this . dialogVisibleHistory = false ;
this . dialogVisibleNav = false ;
this . dialogVisibleRight = false ;
this . dialogVisibleTips = false ;
this . dialogVisibleTips2 = false ;
this . dialogVisibleBland = false ;
this . dialogVisibleBland = false ;
} ,
//测试 保存当前目录信息
saveNowDmcClick ( ) {
const targetNode = this . findNodeById ( this . treeData , this . currentNode . id ) ;
targetNode . minorVersion = '01' ;
const aaa = this . editor . txt . html ( ) ;
console . log ( "当前的所有html内容4" , aaa )
this . catalogueAnalysis ( this . treeData ) ;
this . generateXml ( false , this . currentNode . id ) ;
// this.$sendToDotNet('RefreshTree');
this . contentXmlStr = this . editor . txt . html ( ) ;
} ,
//保存当前DMC信息
saveNowDmc2 ( type ) {
console . log ( "保存时候点击" , this . lastClick )
if ( type == 'save' ) {
console . log ( "保存时候点击 this.currentNode" , this . currentNode , this . currentNode . minorVersion )
// if(this.currentNode.minorVersion == '00'){
const targetNode = this . findNodeById ( this . treeData , this . lastClick ) ;
targetNode . minorVersion = '01' ;
// }
console . log ( "保存时候点击 treedata" , this . treeData )
this . catalogueAnalysis ( this . treeData ) ;
this . generateXml ( false , this . lastClick ) ;
this . contentXmlStr = this . editor . txt . html ( ) ;
// const targetNode = this.findNodeById(this.treeData, this.lastClick);
// if (targetNode) {
// targetNode.minorVersion = '01';
// }
// this.catalogueAnalysis(this.treeData);
} else if ( type == 'noSave' ) {
this . getDmName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + this . lastClick + this . domNameStr [ 3 ] + this . domNameStr [ 4 ] ;
console . log ( "加载富文本的文件名" , this . getDmName )
this . loadFWBFile ( this . getDmName ) ;
console . log ( "不保存" )
}
this . dialogVisibleTips2 = false ;
console . log ( "saveNowDmc2" , type )
} ,
//保存当前DMC信息
saveNowDmc ( type ) {
if ( type == 'save' ) {
this . navIsAdd = 'other'
this . generateXml ( false ) ;
this . dialogVisibleTips = false ;
this . dialogVisibleNav = true ;
} else if ( type == 'noSave' ) {
this . getDmName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + this . lastClick + this . domNameStr [ 3 ] + this . domNameStr [ 4 ] ;
this . loadFWBFile ( this . getDmName ) ;
this . dialogVisibleTips = false ;
this . dialogVisibleNav = true ;
}
this . clearFormData ( ) ;
this . showView = false ;
this . $sendToDotNet ( 'CancelUserHistoy' )
} ,
//测试 绑定资源弹窗显示
showBand ( ) {
this . dialogVisibleRight = false ;
this . dialogVisibleBland = true ;
} ,
//测试 历史版本展示
showHistory ( ) {
this . dialogVisibleRight = false ;
this . dialogVisibleHistory = true ;
this . getDmName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + this . currentNode . id + this . domNameStr [ 3 ] + this . domNameStr [ 4 ] ;
console . log ( "历史版本查询时候的名字" , this . getDmName )
console . log ( "历史版本查询时候的domNameStr" , this . domNameStr )
console . log ( "历史版本查询时候的currentNode" , this . currentNode )
this . $sendToDotNet ( "GetHistoryVesions" , this . getDmName )
} ,
//版本定稿
finalVersion ( ) {
console . log ( "定版时候的参数" , this . currentNode )
const newStr = 'A-A_' + this . currentNode . lagreVersion + '_00' ;
// let versionName = this.domNameStr[0]+this.domNameStr[1]+this.domNameStr[2]+this.currentNode.id+this.domNameStr[3]+this.domNameStr[4]+'.xml';
const versionName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + this . currentNode . id + newStr + this . domNameStr [ 4 ] + '.xml' ;
// this.currentNode.minorVersion = '00';
const targetNode = this . findNodeById ( this . treeData , this . currentNode . id ) ;
targetNode . minorVersion = '00' ;
this . catalogueAnalysis ( this . treeData ) ;
console . log ( versionName )
this . $sendToDotNet ( "CreatVersion" , versionName )
} ,
//显示新建弹窗
showAddDialog ( type ) {
console . log ( "点击新建" , type )
this . $sendToDotNet ( "CancelPriview" )
this . navIsAdd = type ;
if ( type == "create" ) {
this . form . name = '' ;
this . isLoadOldDmc = '2' ,
this . clearFormData ( ) ;
} else {
this . form . name = this . currentNode . name ;
}
if ( this . dmcIsChange ( ) ) {
this . dialogVisibleNav = true ;
this . showView = false ;
} else {
this . dialogVisibleTips = true ;
}
// this.$sendToDotNet('CancelUserHistoy')
this . dialogVisibleRight = false ;
} ,
//截取路径信息
removeQuotationMarks ( data ) {
const result = data . replace ( /^"|"$/g , '' ) ;
return result ;
} ,
//目录节点点击
handleNodeClick ( data ) {
this . currentNode = data ;
this . navIsAdd = '' ;
this . gengxin ( ) ;
console . log ( "这一次点击的节点信息" , data ) ;
console . log ( "上一次点击的时候的ID" , this . lastClick )
console . log ( "这一次点击的时候的ID" , this . nowClick )
if ( this . lastClick == this . nowClick . id ) {
this . nowClick = data ;
this . lastClick = data . id ;
// this.generateXml(false);
// this.catalogueAnalysis(this.treeData);
} else {
console . log ( "中中中中中" , this . lastClick , this . dmcIsChange ( ) )
if ( this . lastClick && ! this . dmcIsChange ( ) ) {
this . dialogVisibleTips2 = true ;
console . log ( "dialogVisibleTips2出现" )
console . log ( "恢复成上一次点击" , this . lastClick )
// this.$refs.tree.setCheckedKeys([this.lastClick]);
// 确保DOM更新后再重置状态
this . $nextTick ( ( ) => {
this . $refs . tree . setCheckedKeys ( [ this . lastClick ] ) ;
this . $refs . tree . setCurrentKey ( this . lastClick ) ;
} ) ;
} else {
const target = this . domNameStr [ 3 ] ;
// 假设需要替换的格式是 "前缀_xxx_yy", 其中xxx是3位, yy是2位
// 先找到最后两个下划线的位置
const lastUnderlineIndex = target . lastIndexOf ( '_' ) ;
const secondLastUnderlineIndex = target . lastIndexOf ( '_' , lastUnderlineIndex - 1 ) ;
if ( lastUnderlineIndex > - 1 && secondLastUnderlineIndex > - 1 ) {
// 截取前缀部分(到第二个下划线)
const prefix = target . substring ( 0 , secondLastUnderlineIndex + 1 ) ;
// 截取中间部分( 3位) 和末尾部分( 2位) , 并用新值替换
// const newValue = `${prefix}${data.lagreVersion}_${data.minorVersion}`;
const newValue = ` ${ prefix } ${ data . lagreVersion } _00 ` ;
// 更新数组
this . domNameStr . splice ( 3 , 1 , newValue ) ;
this . replaced = true ;
}
console . log ( "点击时候的节点data" , data . id )
this . getDmName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + data . id + this . domNameStr [ 3 ] + this . domNameStr [ 4 ] ;
console . log ( "加载富文本的文件名" , this . getDmName )
this . loadFWBFile ( this . getDmName ) ;
this . lastClick = data . id ;
}
// if(this.lastClick){
// if(!this.dmcIsChange()){
// this.navIsAdd = 'edit';
// this.generateXml(false,this.lastClick);
// }
// }
// this.getDmName = this.domNameStr[0]+this.domNameStr[1]+this.domNameStr[2]+data.id+this.domNameStr[3]+this.domNameStr[4];
// console.log("加载富文本的文件名",this.getDmName)
// this.loadFWBFile(this.getDmName);
}
console . log ( "当前节点点击" , data ) ;
// this.$sendToDotNet('GetFilePath','PMC',data.id,'');
} ,
//确认新建目录
confirmAdd ( type ) {
if ( type ) {
this . loadFileDMC = '' ;
} else {
this . $sendToDotNet ( 'CopyToWorkDire' ) ;
}
this . $refs . form . validate ( ( valid ) => {
if ( ! valid ) return
// if(!this.dmcIsChange()){
// }else{
// }
const newNode = {
id : this . queryMaxId ( ) ,
maxId : this . mId ,
name : this . form . name ,
attributes : [ ] ,
formMes : this . form ,
lagreVersion : this . form . version , //大版本
minorVersion : '00' , //临时版本
children : [ ]
}
console . log ( "新建章节目录时候的参数" , newNode )
this . nowMaxId = newNode . id ;
if ( this . currentNode ) {
if ( ! this . currentNode . children ) {
this . $set ( this . currentNode , 'children' , [ ] )
}
this . currentNode . children . push ( newNode )
} else {
this . treeData . push ( newNode )
}
this . dialogVisibleNav = false
this . $nextTick ( ( ) => {
this . $refs . tree . setCurrentKey ( newNode . id )
this . currentNode = newNode ;
this . catalogueAnalysis ( this . treeData ) ;
// this.$sendToDotNet('SaveFile','PMC',newNode.id,JSON.stringify(this.currentNode));
//创建目录时候同时创建一个空DM文件
this . generateXml ( true )
} )
} )
} ,
//编辑目录时候点击确认进行保存
confirmEdit ( ) {
this . currentNode . name = this . form . name ;
console . log ( "点击编辑确定" , this . currentNode , this . treeData )
this . currentNode . minorVersion = '01' ;
this . catalogueAnalysis ( this . treeData ) ;
this . isNavEdit = true ;
this . dialogVisibleNav = false ;
this . generateXml ( false , this . treeData . id )
// let targetNode = this.findNodeById(this.treeData,this.currentNode.id);
// if (targetNode) {
// // 替换attributes
// // targetNode.name = ...this.currentNode.name];
// // this.hasReplaced = true;
// console.log('替换成功,新的节点数据:', targetNode);
// } else {
// console.warn('未找到节点');
// }
// console.log('获取当前节点',this.currentNode)
} ,
// 删除时候的二次确认弹窗
deleteDialog ( ) {
console . log ( "currentNode.children" , this . currentNode )
this . dialogVisibleNavDel = true ;
} ,
// 删除绑定资源按钮
deleteAttr ( name , index ) {
this . nowAttr = {
name : name ,
index : index ,
}
this . dialogVisibleAttrDel = true ;
} ,
// 删除绑定资源二次确定
deleteAttrSure ( ) {
this . currentNode . attributes . splice ( this . nowAttr . index , 1 ) ;
this . catalogueAnalysis ( this . treeData ) ;
this . dialogVisibleAttrDel = false ;
} ,
//删除节点时候判断是否有子节点。
deleteNode ( ) {
if ( this . currentNode . children && this . currentNode . children . length > 0 ) {
this . $message ( {
type : 'warning' ,
message : '该节点包含子节点,不能删除!'
} )
} else {
let isDel = this . deleteNodeFromTree ( this . treeData , this . currentNode . id )
console . log ( "删除是否成功" , isDel )
// this.currentNode = null;
const fileId = this . currentNode . id ;
this . currentNode = '' ;
this . catalogueAnalysis ( this . treeData ) ;
this . dialogVisibleNavDel = false ;
// this.$sendToDotNet('RefreshTree');
console . log ( '删除RMDMfile fileId' , fileId )
this . $sendToDotNet ( 'RMDMfile' , 'DMC' , fileId )
// this.$message({
// type: 'success',
// message: '删除成功!'
// })
}
} ,
// 更新指定节点的版本号
updateNodeVersion ( id , vs ) {
const targetNode = this . findNodeById ( this . treeData2 , id ) ;
if ( targetNode ) {
targetNode . lagreVersion = vs ;
}
} ,
//删除节点
deleteNodeFromTree ( nodes , id ) {
for ( let i = 0 ; i < nodes . length ; i ++ ) {
if ( nodes [ i ] . id === id ) {
nodes . splice ( i , 1 )
return true
}
if ( nodes [ i ] . children && nodes [ i ] . children . length > 0 ) {
if ( this . deleteNodeFromTree ( nodes [ i ] . children , id ) ) {
return true
}
}
}
return false
} ,
//重置输入框
resetForm ( ) {
this . $refs . form . resetFields ( )
} ,
// 搜索相关方法
handleSearch ( ) {
if ( ! this . searchText . trim ( ) ) {
this . $refs . tree . filter ( this . searchText ) ;
// 搜索内容为空时,重置所有节点的可见性
this . resetTreeVisibility ( this . treeData )
} else {
this . $refs . tree . filter ( this . searchText )
}
} ,
//清除搜索
handleSearchClear ( ) {
this . searchText = '' ;
// 清空搜索时重置所有节点的可见性
this . $refs . tree . filter ( '' ) ;
this . resetTreeVisibility ( this . treeData )
} ,
//重置目录节点信息
resetTreeVisibility ( nodes ) {
nodes . forEach ( node => {
// 重置节点的可见性
node . visible = true
if ( node . children && node . children . length > 0 ) {
this . resetTreeVisibility ( node . children )
}
} )
// 强制刷新树组件
this . $refs . tree . updateKeyChildren ( )
} ,
//目录节点信息
filterNode ( value , data ) {
if ( ! value ) return true ; // 空值时显示所有节点
// 这里假设你要搜索的是节点的name属性
return data . name . toLowerCase ( ) . includes ( value . toLowerCase ( ) ) ;
} ,
//筛选后高亮class
isHighlight ( data ) {
return this . searchText && data . name . toLowerCase ( ) . includes ( this . searchText . toLowerCase ( ) )
} ,
//右键
// 处理右键点击事件
handleRightClick ( event , data , node , component ) {
console . log ( "node, component" , node , component )
event . preventDefault ( ) ; // 阻止默认右键菜单
this . currentNode = data ;
// this.getDmName = this.domNameStr[0]+this.domNameStr[1]+this.domNameStr[2]+this.lastClick+this.domNameStr[3]+this.domNameStr[4];
// console.log("删除的DM名字",this.getDmName)
// return;
this . dialogVisibleRight = true ;
// 初始化已选属性
// this.selectedAttributes = data.attributes ? [...data.attributes] : [];
// // 显示弹窗
// this.$sendToDotNet('GetFilePath','PMC',data.id,'');
} ,
// 保存属性
saveAttributes ( ) {
console . log ( "this.currentNode.id" , this . currentNode . id )
this . $sendToDotNet ( 'GetFilePath' , 'PMC' , this . currentNode . id , '' ) ;
// if (this.currentNode) {
// // 保存选中的属性到当前节点
// this.currentNode.attributes = [...this.selectedAttributes];
// // 刷新树结构
// this.$refs.tree.setCurrentKey(this.currentNode.id);
// }
// this.dialogVisibleRight = false;
} ,
//查询最大ID值
queryMaxId ( ) {
// maxId = '00001'
console . log ( "初始化ID" , this . treeData )
// if(this.treeData[0]){
let maxId = this . mId ? this . mId : '00001' ;
const length = maxId . length ;
// 将字符串转换为数字并加1
const number = parseInt ( maxId , 10 ) + 1 ;
// 格式化数字为指定长度的字符串,不足的前面补零
maxId = number . toString ( ) . padStart ( length , '0' ) ;
// }
this . mId = maxId ;
return maxId ;
// let maxId = 0;
// let treeData = this.treeData;
// // 递归遍历函数
// const traverse = (nodes) => {
// if (!nodes || nodes.length === 0) return;
// nodes.forEach(node => {
// // 比较当前节点ID与最大值
// if (node.id > maxId) {
// maxId = node.id;
// }
// // 递归处理子节点
// traverse(node.children);
// });
// };
// // 开始遍历
// traverse(treeData);
// console.log("当前数据最大ID",maxId)
// const length = maxId.length;
// // 将字符串转换为数字并加1
// const number = parseInt(maxId, 10) + 1;
// // 格式化数字为指定长度的字符串,不足的前面补零
// maxId = number.toString().padStart(length, '0');
// if(maxId == 1){
// maxId = '00001'
// }
// return maxId;
} ,
//解析XML目录( 暂时不用)
extractDmCode ( xmlString ) {
// 1. 解析 XML 字符串
const parser = new DOMParser ( ) ;
const xmlDoc = parser . parseFromString ( xmlString , "text/xml" ) ;
// 2. 获取所有 dmCode 节点
const dmCodeNodes = xmlDoc . getElementsByTagName ( "dmCode" ) ;
const issueInfoNodes = xmlDoc . getElementsByTagName ( "issueInfo" ) ;
const languageNodes = xmlDoc . getElementsByTagName ( "language" ) ;
// 3. 遍历节点,提取属性
let dmCodeList = Array . from ( dmCodeNodes ) . map ( node => {
const attributes = { } ;
// 遍历节点的所有属性
for ( let i = 0 ; i < node . attributes . length ; i ++ ) {
const attr = node . attributes [ i ] ;
attributes [ attr . name ] = attr . value ;
}
return attributes ;
} ) ;
let issueInfoList = Array . from ( issueInfoNodes ) . map ( node => {
const attributes = { } ;
// 遍历节点的所有属性
for ( let i = 0 ; i < node . attributes . length ; i ++ ) {
const attr = node . attributes [ i ] ;
attributes [ attr . name ] = attr . value ;
}
return attributes ;
} ) ;
let languageList = Array . from ( languageNodes ) . map ( node => {
const attributes = { } ;
// 遍历节点的所有属性
for ( let i = 0 ; i < node . attributes . length ; i ++ ) {
const attr = node . attributes [ i ] ;
attributes [ attr . name ] = attr . value ;
}
return attributes ;
} ) ;
// 处理函数:将对象按指定字段集拼接成字符串
let dmCodeTitle = [ 'modelIdentCode' , 'systemDiffCode' , 'systemCode' , 'subSystemCode' , 'subSubSystemCode' , 'disassyCode' , 'disassyCodeVariant' , 'infoCode' , 'infoCodeVariant' , 'itemLocationCode' ]
let issueInfoTitle = [ 'issueNumber' , 'inWork' ] ;
let languageTitle = [ 'languageIsoCode' , 'countryIsoCode' ]
// 处理三组数据
let dmCodeResult = this . joinFields ( dmCodeList , dmCodeTitle , '-' ) ;
let issueInfoResult = this . joinFields ( issueInfoList , issueInfoTitle , '_' ) ;
let languageResult = this . joinFields ( languageList , languageTitle , '_' ) ;
console . log ( "参数 dmCodeResult" , dmCodeResult )
console . log ( "参数 issueInfoResult" , issueInfoResult )
console . log ( "参数 languageResult" , languageResult )
// let dmCodeResult2 = [];
let newList = [ ] ;
for ( let i = 0 ; i < dmCodeResult .length ; i + + ) {
// let strA = dmCodeResult[0]+'_'+dmCodeResult[0]
let str = dmCodeResult [ i ] + "-" + issueInfoResult [ i ] + "-" + languageResult [ i ]
newList . push ( str ) ;
}
console . log ( "结果" , newList )
} ,
//解析目录节点数据
generateTreeData ( xmlContent ) {
console . log ( "加载XML解析内容 初始化内容" , xmlContent )
// 1. 解析XML
const parser = new DOMParser ( ) ;
const xmlDoc = parser . parseFromString ( xmlContent , "text/xml" ) ;
console . log ( "加载XML解析内容 初始化XML" , xmlDoc )
// 2. 获取根节点( content下的所有pmEntry)
const contentNode = xmlDoc . querySelector ( "content" ) ;
console . log ( "加载XML解析内容 content" , contentNode )
const rootPmEntries = contentNode ? Array . from ( contentNode . children ) . filter ( node => node . tagName === "pmEntry" ) : [ ] ;
// 3. 递归处理节点,构建树形结构
this . treeData = this . parsePmEntries ( rootPmEntries ) ;
this . handleCheckVersion ( ) ;
// console.log("")
console . log ( "重新解析结果" , this . treeData )
// if(this.treeData.length>0){
// this.clearNodeState();
// }
// this.enableContextMenu();//绑定右键
// 获取最大ID
const simpleParaNode = xmlDoc . querySelector ( "simplePara" ) ;
console . log ( "加载XML解析内容 id" , simpleParaNode )
const maxId = simpleParaNode . getAttribute ( "maxId" ) || "00001" ;
console . log ( "当前目录最大ID" , maxId )
this . mId = maxId ;
} ,
/ * *
* 递归解析pmEntry节点列表 , 生成树形数据
* @ param { NodeList } pmEntries - pmEntry节点列表
* @ param { Object } parent - 父节点 ( 用于处理嵌套关系 )
* @ returns { Array } 树形结构数组
* /
parsePmEntries ( pmEntries , parent = null ) {
const treeNodes = [ ] ;
console . log ( "parent" , parent )
pmEntries . forEach ( entry => {
// const lagreVersion = parent.getAttribute("lagreVersion") || "";
// const minorVersion = parent.getAttribute("minorVersion") || "";
// console.log("数循环结果 大版本",lagreVersion)
// console.log("数循环结果 小版本",minorVersion)
// a. 提取当前节点的id、name、attributes
const titleNode = entry . querySelector ( "pmEntryTitle" ) || entry . querySelector ( "techName" ) ;
if ( ! titleNode ) return ; // 跳过无标题的节点
const id = titleNode . getAttribute ( "id" ) ;
const name = titleNode . textContent . trim ( ) ;
const attributesStr = titleNode . getAttribute ( "attributes" ) || "" ;
const lagreVersion = titleNode . getAttribute ( "lagreVersion" ) || "000" ;
const minorVersion = titleNode . getAttribute ( "minorVersion" ) || "00" ;
// const maxID = titleNode.getAttribute("maxId") || "00001";
const attributes = attributesStr ? attributesStr . split ( "," ) . map ( item => item . trim ( ) ) : [ ] ;
// b. 创建节点基本结构
const node = {
id ,
name ,
// maxId:maxID,
attributes ,
formMes : { } , // 固定空对象
children : [ ] ,
lagreVersion : lagreVersion , //大版本
minorVersion : minorVersion , //临时版本
} ;
// c. 处理子节点( 当前pmEntry下的子pmEntry)
const childEntries = Array . from ( entry . children ) . filter ( child => child . tagName === "pmEntry" ) ;
if ( childEntries . length > 0 ) {
node . children = this . parsePmEntries ( childEntries , node ) ;
}
treeNodes . push ( node ) ;
} ) ;
return treeNodes ;
} ,
//测试 解析xml 暂未使用
parseXml ( xmlInput ) {
this . errorMessage = '' ;
this . parsedData = [ ] ;
try {
// 创建DOMParser实例
const parser = new DOMParser ( ) ;
const xmlDoc = parser . parseFromString ( xmlInput , "text/xml" ) ;
console . log ( "xmlDoc" , xmlDoc )
// 检查XML解析错误
const parserError = xmlDoc . getElementsByTagName ( "parsererror" ) [ 0 ] ;
if ( parserError ) {
throw new Error ( "XML格式错误: " + parserError . textContent ) ;
}
// 获取所有顶级pmEntry节点
const pmEntries = xmlDoc . querySelectorAll ( 'content > pmEntry' ) ;
let parsedData = [ ] ;
// 解析每个pmEntry
pmEntries . forEach ( pmEntry => {
const entryData = this . parsePmEntry ( pmEntry ) ;
if ( entryData ) {
parsedData . push ( entryData ) ;
}
} ) ;
parsedData . map ( ( res ) => {
if ( res . infoCode ) {
return res . is = res . infoCode , res . name = res . title ;
}
} )
this . treeData = parsedData ;
console . log ( "parsedData" , parsedData )
} catch ( error ) {
this . errorMessage = "解析失败: " + error . message ;
console . error ( "XML解析错误:" , error ) ;
}
} ,
/ * *
* 获取指定节点的值
* @ param { Element } parentNode - 父节点
* @ param { string } selector - 节点选择器
* @ returns { string } 节点值
* /
getNodeValue ( parentNode , selector ) {
const node = parentNode . querySelector ( selector ) ;
return node ? node . textContent . trim ( ) : '' ;
} ,
//格式化数据提取节点内容
parsePmEntry ( pmEntryElement ) {
// 获取pmEntryTitle
const titleElement = pmEntryElement . querySelector ( 'pmEntryTitle' ) ;
if ( ! titleElement ) return null ;
const title = titleElement . textContent . trim ( ) ;
const result = {
title ,
children : [ ] ,
subItems : [ ]
} ;
// 获取当前pmEntry下的所有子节点
const childNodes = Array . from ( pmEntryElement . childNodes ) ;
// 查找子pmEntry和dmRef节点
childNodes . forEach ( node => {
if ( node . nodeType !== 1 ) return ; // 只处理元素节点
if ( node . tagName === 'pmEntry' ) {
// 递归解析子pmEntry
const childData = this . parsePmEntry ( node ) ;
if ( childData ) {
result . children . push ( childData ) ;
}
} else if ( node . tagName === 'dmRef' ) {
// 解析dmRef中的infoCode
const dmCode = node . querySelector ( 'dmRefIdent > dmCode' ) ;
if ( dmCode && dmCode . hasAttribute ( 'infoCode' ) ) {
result . subItems . push ( {
infoCode : dmCode . getAttribute ( 'infoCode' )
} ) ;
}
}
} ) ;
// 如果没有子节点但有subItems, 设置当前节点的infoCode为第一个subItem的infoCode
if ( result . children . length === 0 && result . subItems . length > 0 ) {
result . infoCode = result . subItems [ 0 ] . infoCode ;
}
return result ;
} ,
// 处理数据信息
joinFields ( dataList , fields ) {
return dataList . map ( item => {
return fields . map ( field => item [ field ] ) . join ( '_' ) ;
} ) ;
} ,
//处理目录节点信息
catalogueAnalysis ( treeData ) {
console . log ( "处理每个节点信息 treeData" , treeData )
// 递归处理每个节点, 跟踪路径用于生成infoName
const processNode = ( node , path = [ ] , level = 0 ) => {
let nodeStr = '' ;
console . log ( "处理每个节点信息 node" , node )
// 每个节点都用pmEntry标签包裹
nodeStr += '<pmEntry>\n' ;
// 计算当前节点的路径, 用于生成infoName
const currentPath = [ ... path , node . name ] ;
// 如果有子节点, 添加pmEntryTitle标签
if ( node . children && node . children . length > 0 ) {
nodeStr += ` \ t<pmEntryTitle attributes=' ${ node . attributes } ' lagreVersion=" ${ node . lagreVersion } " minorVersion=" ${ node . minorVersion } " id=" ${ node . id } "> ${ node . name } </pmEntryTitle> \ n ` ;
// 递归处理子节点
node . children . forEach ( ( child , index ) => {
console . log ( "index" , index )
// 递归处理子节点, 传入当前路径( 移除了未使用的infoCode和issueDate参数)
nodeStr += processNode ( child , currentPath , level + 1 ) ;
} ) ;
} else {
// 没有子节点的节点用dmRef标签包裹
nodeStr += '\t<dmRef>\n' ;
// 添加dmRefIdent部分, 包含动态生成的dmCode
nodeStr += ` \ t \ t<dmRefIdent> \ n ` ;
nodeStr += ` \ t \ t \ t<dmCode itemLocationCode="A" infoCodeVariant="A" infoCode=" ${ getInfoCode ( level ) } " disassyCodeVariant="A" disassyCode="00" assyCode="00" subSubSystemCode=" ${ getSubSubSystemCode ( level ) } " subSystemCode=" ${ getSubSystemCode ( level ) } " systemCode="P4" systemDiffCode="A" modelIdentCode="YSC001"/> \ n ` ;
nodeStr += ` \ t \ t \ t<issueInfo issueNumber="001" inWork="01"/> \ n ` ;
nodeStr += ` \ t \ t \ t<language languageIsoCode="zh" countryIsoCode="CN"/> \ n ` ;
nodeStr += ` \ t \ t</dmRefIdent> \ n ` ;
// 添加dmRefAddressItems标签
nodeStr += ` \ t \ t<dmRefAddressItems> \ n ` ;
// 添加dmTitle标签, 包含techName和infoName
nodeStr += ` \ t \ t \ t<dmTitle> \ n ` ;
nodeStr += ` \ t \ t \ t \ t<techName attributes=' ${ node . attributes } ' lagreVersion=" ${ node . lagreVersion } " minorVersion=" ${ node . minorVersion } " id=" ${ node . id } "> ${ node . name } </techName> \ n ` ;
nodeStr += ` \ t \ t \ t \ t<infoName> ${ currentPath . join ( '-' ) } </infoName> \ n ` ;
nodeStr += ` \ t \ t \ t</dmTitle> \ n ` ;
// 添加issueDate标签
nodeStr += ` \ t \ t \ t<issueDate year="2024" month="06" day=" ${ getIssueDay ( level ) } "/> \ n ` ;
// 闭合dmRefAddressItems标签
nodeStr += ` \ t \ t</dmRefAddressItems> \ n ` ;
// 闭合dmRef标签
nodeStr += ` \ t</dmRef> \ n ` ;
}
// 闭合当前节点的pmEntry标签
nodeStr += '</pmEntry>\n' ;
return nodeStr ;
} ;
// 根据层级和索引生成infoCode
const getInfoCode = ( level , index = 0 ) => {
if ( level === 1 && index === 0 ) return "042" ;
if ( level === 1 && index === 1 ) return "041" ;
return "040" ;
} ;
// 根据层级生成subSystemCode
const getSubSystemCode = ( level ) => {
if ( level === 0 ) return "0" ;
if ( level === 1 ) return "1" ;
if ( level === 2 ) return "3" ;
return "0" ;
} ;
// 根据层级生成subSubSystemCode
const getSubSubSystemCode = ( level , index = 0 ) => {
if ( level === 1 ) return "1" ;
if ( level === 2 ) return index + 1 ;
return "0" ;
} ;
// 根据层级生成issueDay
const getIssueDay = ( level ) => {
return level === 1 ? "13" : "12" ;
} ;
// 处理所有根节点
let result = '' ;
treeData . forEach ( node => {
result += processNode ( node ) ;
} ) ;
console . log ( 'catalogueString 目录字符串' , result ) ;
this . catalogueString = result ;
this . saveNav ( ) ;
// console.log(this.treeData)
} ,
//生成目录节点XML信息 并保存目录pmc
saveNav ( ) {
let xmlStr = ` <?xml version="1.0" encoding="UTF-8" standalone="no"?>
< ! DOCTYPE pm [
] >
< pm xsi :noNamespaceSchemaLocation = "http://www.s1000d.org/S1000D_4-1/xml_schema_flat/pm.xsd" xmlns :xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns :rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns :dc = "http://www.purl.org/dc/elements/1.1/" xmlns :xlink = "http://www.w3.org/1999/xlink" >
< identAndStatusSection >
< pmAddress >
< pmIdent >
< pmCode modelIdentCode = "YSC001" pmIssuer = "732380192B" pmNumber = "00001" pmVolume = "00" / >
< language countryIsoCode = "CN" languageIsoCode = "zh" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< / pmIdent >
< pmAddressItems >
< issueDate year = "2024" month = "06" day = "24" / >
< pmTitle > 无人机系统地面运输方舱使用维护说明书 < / pmTitle >
< / pmAddressItems >
< / pmAddress >
< pmStatus issueType = "new" >
< security securityClassification = "01" / >
< responsiblePartnerCompany enterpriseCode = " " / >
< originator / >
< applic >
< displayText >
< simplePara maxId = '`+this.mId+`' > A0304 - 1 A无人机系统地面运输方舱 < / simplePara >
< / displayText >
< / applic >
< brexDmRef >
< dmRef xlink :type = "simple" xlink :actuate = "onRequest" xlink :show = "replace" xlink :href = "URN:S1000D:DMC-S1000D-E-04-10-0301-00A-022A-D" >
< dmRefIdent >
< dmCode modelIdentCode = "YSC001" systemDiffCode = "A" systemCode = "P4" subSystemCode = "0" subSubSystemCode = "0" assyCode = "00" disassyCode = "00" disassyCodeVariant = "A" infoCode = "022" infoCodeVariant = "A" itemLocationCode = "A" / >
< / dmRefIdent >
< / dmRef >
< / brexDmRef >
< qualityAssurance >
< unverified / >
< / qualityAssurance >
< / pmStatus >
< / identAndStatusSection >
< content > `
+ this . catalogueString +
` </content>
< / pm > `
console . log ( "传递字符串" , this . catalogueString )
console . log ( "存时候" , xmlStr )
this . $sendToDotNet ( 'SaveFile' , 'PMC' , '' , xmlStr ) ;
} ,
//测试 加载目录
jzml ( ) {
let a = ` <!DOCTYPE pm [
] >
< pm xsi :noNamespaceSchemaLocation = "http://www.s1000d.org/S1000D_4-1/xml_schema_flat/pm.xsd" xmlns :xsi = "http://www.w3.org/2001/XMLSchema-instance" xmlns :rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns :dc = "http://www.purl.org/dc/elements/1.1/" xmlns :xlink = "http://www.w3.org/1999/xlink" >
< identAndStatusSection >
< pmAddress >
< pmIdent >
< pmCode modelIdentCode = "YSC001" pmIssuer = "732380192B" pmNumber = "00001" pmVolume = "00" / >
< language countryIsoCode = "CN" languageIsoCode = "zh" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< / pmIdent >
< pmAddressItems >
< issueDate year = "2024" month = "06" day = "24" / >
< pmTitle > 无人机系统地面运输方舱使用维护说明书 < / pmTitle >
< / pmAddressItems >
< / pmAddress >
< pmStatus issueType = "new" >
< security securityClassification = "01" / >
< responsiblePartnerCompany enterpriseCode = " " / >
< originator / >
< applic >
< displayText >
< simplePara > A0304 - 1 A无人机系统地面运输方舱 < / simplePara >
< / displayText >
< / applic >
< brexDmRef >
< dmRef xlink :type = "simple" xlink :actuate = "onRequest" xlink :show = "replace" xlink :href = "URN:S1000D:DMC-S1000D-E-04-10-0301-00A-022A-D" >
< dmRefIdent >
< dmCode modelIdentCode = "YSC001" systemDiffCode = "A" systemCode = "P4" subSystemCode = "0" subSubSystemCode = "0" assyCode = "00" disassyCode = "00" disassyCodeVariant = "A" infoCode = "022" infoCodeVariant = "A" itemLocationCode = "A" / >
< / dmRefIdent >
< / dmRef >
< / brexDmRef >
< qualityAssurance >
< unverified / >
< / qualityAssurance >
< / pmStatus >
< / identAndStatusSection >
< content > < pmEntry >
< pmEntryTitle > 装备概况 < / pmEntryTitle >
< pmEntry >
< pmEntryTitle > 方舱概述 < / pmEntryTitle >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00003" > 无人机系统 < / techName >
< infoName > 装备概况 - 方舱概述 - 功能介绍 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00004" > 无人机系统 < / techName >
< infoName > 装备概况 - 方舱概述 - 规格介绍 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = '["金","木","水"]' id = "00005" > 无人机系统 < / techName >
< infoName > 装备概况 - 舱体 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00006" > 无人机系统 < / techName >
< infoName > 装备概况 - 机身转运小车 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00007" > 无人机系统 < / techName >
< infoName > 装备概况 - 无人机部件存储装置 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00008" > 无人机系统 < / techName >
< infoName > 装备概况 - 机身转运小车 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< pmEntryTitle > 附件及工具 < / pmEntryTitle >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00010" > 无人机系统 < / techName >
< infoName > 装备概况 - 附件及工具 - 灭火器 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00011" > 无人机系统 < / techName >
< infoName > 装备概况 - 附件及工具 - 应急灯 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00012" > 无人机系统 < / techName >
< infoName > 装备概况 - 附件及工具 - 土木工具 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "040" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "3" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00013" > 无人机系统 < / techName >
< infoName > 装备概况 - 附件及工具 - 机械工具 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "12" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< / pmEntry >
< / pmEntry >
< pmEntry >
< pmEntryTitle > 使用说明 < / pmEntryTitle >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00014" > 无人机系统 < / techName >
< infoName > 使用说明 - 无人机出舱 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00015" > 无人机系统 < / techName >
< infoName > 使用说明 - 无人机入舱 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< pmEntry >
< dmRef >
< dmRefIdent >
< dmCode itemLocationCode = "A" infoCodeVariant = "A" infoCode = "042" disassyCodeVariant = "A" disassyCode = "00" assyCode = "00" subSubSystemCode = "1" subSystemCode = "1" systemCode = "P4" systemDiffCode = "A" modelIdentCode = "YSC001" / >
< issueInfo issueNumber = "000" inWork = "01" / >
< language languageIsoCode = "zh" countryIsoCode = "CN" / >
< / dmRefIdent >
< dmRefAddressItems >
< dmTitle >
< techName attributes = "[]" id = "00016" > 无人机系统 < / techName >
< infoName > 使用说明 - 灭火器使用 < / infoName >
< / dmTitle >
< issueDate year = "2024" month = "06" day = "13" / >
< / dmRefAddressItems >
< / dmRef >
< / pmEntry >
< / pmEntry >
< / content >
< / pm > `
this . parseToTreeData ( a ) ;
} ,
//清除新建目录弹窗内容信息。
clearFormData ( ) {
this . form = {
name : '' ,
version : '000' ,
date : '' ,
language : '' ,
level : '' ,
contributor : '' ,
creator : '' ,
applicabilityInformation : '' ,
qualityVerification : '' ,
permission : ''
}
} ,
//测试 格式化目录信息
parseToTreeData ( xmlString ) {
// 创建DOMParser实例
const parser = new DOMParser ( ) ;
// 解析XML字符串
const xmlDoc = parser . parseFromString ( xmlString , 'text/xml' ) ;
// 获取根节点下的所有pmEntry节点( 顶级节点)
const rootPmEntries = xmlDoc . querySelectorAll ( 'content > pmEntry' ) ;
// 递归解析节点的函数
const parseNode = ( xmlNode ) => {
// 检查是否有pmEntryTitle子节点
const titleNode = xmlNode . querySelector ( 'pmEntryTitle' ) ;
if ( titleNode ) {
// 有标题节点,说明是父节点
const node = {
id : '' , // 后续会从子节点中查找合适的id
name : titleNode . textContent . trim ( ) ,
children : [ ] ,
attributes : [ ]
} ;
// 修复选择器错误:使用更兼容的方式获取直接子节点
const childNodes = xmlNode . childNodes ;
const childPmEntries = [ ] ;
// 遍历所有子节点, 筛选出直接子pmEntry元素
for ( let i = 0 ; i < childNodes . length ; i ++ ) {
const child = childNodes [ i ] ;
// 检查是否是元素节点且标签名为pmEntry
if ( child . nodeType === 1 && child . tagName === 'pmEntry' ) {
childPmEntries . push ( child ) ;
}
}
// 递归解析每个子节点
childPmEntries . forEach ( childEntry => {
const childNode = parseNode ( childEntry ) ;
if ( childNode ) {
node . children . push ( childNode ) ;
}
} ) ;
// 为父节点生成合适的id
if ( ! node . id && node . children . length > 0 ) {
// 取第一个子节点id的前缀并生成父节点id
const firstChildId = node . children [ 0 ] . id ;
// 简单处理: 取前面的数字部分并减1( 根据实际情况调整)
node . id = ( parseInt ( firstChildId , 10 ) - 1 ) . toString ( ) . padStart ( firstChildId . length , '0' ) ;
}
return node ;
} else {
// 没有标题节点, 说明是叶子节点, 从dmRef中获取信息
const dmRef = xmlNode . querySelector ( 'dmRef' ) ;
if ( ! dmRef ) return null ;
// 获取techName节点中的id和内容
const techNameNode = dmRef . querySelector ( 'techName' ) ;
const id = techNameNode . getAttribute ( 'id' ) ;
const attributes = techNameNode . getAttribute ( 'attributes' ) ;
// 从infoName获取名称路径
const infoNameNode = dmRef . querySelector ( 'infoName' ) ;
const infoName = infoNameNode . textContent . trim ( ) ;
// 取最后一部分作为名称
const nameParts = infoName . split ( '-' ) ;
const name = nameParts [ nameParts . length - 1 ] ;
return {
id ,
name ,
children : [ ] ,
attributes : attributes
} ;
}
} ;
// 解析所有顶级节点
const treeData = [ ] ;
rootPmEntries . forEach ( entry => {
const node = parseNode ( entry ) ;
if ( node ) {
treeData . push ( node ) ;
}
} ) ;
console . log ( "打印" , treeData )
console . log ( "打印String" , JSON . stringify ( treeData ) )
this . treeData = treeData ;
} ,
//和后台交互 加载需要读取的dmc
loadFWBFile ( dmName ) {
// this.$sendToDotNet('LoadDM','DMC--A-P4-20-00-00A-00001A-A_000_01_zh_cn');
console . log ( "需要读取的富文本:" , dmName )
this . $sendToDotNet ( 'LoadDM' , 'DMC' , dmName ) ;
// this.$sendToDotNet('GetFilePath','PMC',data.id,'');
} ,
//和后台交互 查看历史版本
lookHistoryFile ( path ) {
let newPath = path + '\\' + this . getLastPartOfPath ( path ) + '.xml' ;
this . historyVsPath = path ;
console . log ( "发送路径" , newPath )
this . $sendToDotNet ( 'DMPreview' , 'HistoryDMPreview' , newPath )
// this.$sendToDotNet('GetHistoryDMContent',newPath);
// localStorage.setItem('filePath',newPath);
// const url = this.$router.resolve({ name: 'WangG2' }).href
// // 打开新窗口,可指定窗口大小和位置
// window.open(
// url,
// '_blank',
// 'width=800,height=600,top=100,left=100'
// )
} ,
//清除 NBSP str
clearNbsp ( originalStr ) {
const cleanedStr = originalStr . replace ( / /g , '' ) ;
console . log ( "结果cleanedStr" , cleanedStr )
return cleanedStr ;
} ,
//测试 测试拼接地址;
ceshi ( ) {
this . lisenPath = '"http://localhost:61980/"' ;
let e = {
detail : '"\\1.jpg"'
}
const parsedA = this . lisenPath . replace ( /"/g , '' ) ;
const parsedB = e . detail . replace ( /"/g , '' ) ;
// 2. 处理转义字符(如斜杠)
const processedA = parsedA . replace ( /\\/g , '' ) ;
const processedB = parsedB . replace ( /\\/g , '' ) ;
// 3. 确保基础URL以斜杠结尾
let baseUrl = processedA ;
if ( baseUrl && ! baseUrl . endsWith ( '/' ) ) {
baseUrl += '/' ;
}
this . insertImage ( baseUrl + processedB )
} ,
//判断拖拽进富文本的文件类型;
isImageSuffix ( a ) {
let type = '' ;
// 检查参数是否为字符串
if ( typeof a !== 'string' ) {
return false ;
}
// 转换为小写后判断(忽略大小写)
const lowerCaseA = a . toLowerCase ( ) ;
if ( this . allImgType . has ( lowerCaseA ) ) {
type = 'img' ;
} else if ( this . allMusicType . has ( lowerCaseA ) ) {
type = 'music' ;
} else if ( this . allVideoType . has ( lowerCaseA ) ) {
type = 'video' ;
} else if ( this . otherType . has ( lowerCaseA ) ) {
type = '3d'
} else {
type = 'other'
}
return type ;
} ,
//解析字符串信息
parseSpecialString ( str ) {
return str . replace ( /['"\\]/g , '' )
// 处理步骤:移除引号 → 替换转义反斜杠 → 解析Unicode
// return str
// .replace(/^"|"$/g, '')
// .replace(/\\\\/g, '\\')
// .replace(/\\\\/g, '\\')
// .replace(/""/g, '')
// .replace(/\\u([0-9a-fA-F]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)));
} ,
//根据ID查询节点 已经需要替换的内容信息
replaceAttributes ( ) {
// 找到treeData中id为xx节点
const targetNode = this . findNodeById ( this . treeData , this . currentNode . id ) ;
if ( targetNode ) {
// 替换attributes
targetNode . attributes = [ ... this . currentNode . attributes ] ;
// this.hasReplaced = true;
console . log ( '替换成功, 新的attributes:' , targetNode . attributes ) ;
}
this . catalogueAnalysis ( this . treeData ) ;
} ,
/ * *
* 查找树形结构中指定id的节点
* @ param { Array } nodes - 节点数组
* @ param { string } id - 要查找的节点id
* @ returns { Object | null } 找到的节点或null
* /
findNodeById ( nodes , id ) {
// 遍历节点数组
for ( const node of nodes ) {
// 找到目标节点
if ( node . id === id ) {
return node ;
}
// 递归查找子节点
if ( node . children && node . children . length > 0 ) {
const found = this . findNodeById ( node . children , id ) ;
if ( found ) {
return found ;
}
}
}
return null ;
} ,
//成功信息 暂未使用
successTips ( msg ) {
this . $message ( {
message : msg ,
type : 'success'
} ) ;
} ,
// 处理节点右键点击
// 处理节点右键点击
handleNodeContextMenu ( event , data , node , component ) {
event . preventDefault ( ) ;
event . stopPropagation ( ) ;
console . log ( "node" , node )
console . log ( "component" , component )
this . navIsAdd = '' ;
this . contextMenuNode = data ;
this . currentNode = data ;
console . log ( "右键以后赋值:" , this . currentNode , data )
this . getDmName = this . domNameStr [ 0 ] + this . domNameStr [ 1 ] + this . domNameStr [ 2 ] + data . id + this . domNameStr [ 3 ] + this . domNameStr [ 4 ] ;
console . log ( "删除的DM名字" , this . getDmName )
// return;
// 获取鼠标位置
let clientX = event . clientX ;
let clientY = event . clientY ;
// 预估菜单高度(可根据实际菜单内容调整)
const menuHeight = 200 ; // 包含4个选项+分隔线+关闭按钮的大概高度
const windowHeight = window . innerHeight ;
// 计算菜单底部位置
const menuBottom = clientY + menuHeight ;
// 如果菜单底部超出窗口高度,向上调整位置
if ( menuBottom > windowHeight ) {
// 调整后的位置 = 鼠标Y - 菜单高度(确保菜单顶部不超出窗口顶部)
clientY = Math . max ( 0 , clientY - menuHeight ) ;
}
// 设置调整后的菜单位置
this . contextMenuLeft = clientX ;
this . contextMenuTop = clientY ;
this . contextMenuVisible = true ;
// 点击其他区域关闭菜单 - 修复版
const handleClickOutside = ( e ) => {
// 先判断菜单元素是否存在
const menuElement = document . querySelector ( '.custom-context-menu' ) ;
if ( ! menuElement ) {
// 元素不存在时直接移除监听
document . removeEventListener ( 'click' , handleClickOutside ) ;
return ;
}
// 元素存在再判断点击位置
if ( ! menuElement . contains ( e . target ) ) {
this . contextMenuVisible = false ;
document . removeEventListener ( 'click' , handleClickOutside ) ;
}
} ;
// 确保移除之前可能存在的监听,避免重复绑定
setTimeout ( ( ) => {
document . removeEventListener ( 'click' , handleClickOutside ) ;
document . addEventListener ( 'click' , handleClickOutside ) ;
} , 0 ) ;
}
,
// 处理菜单选项点击
handleMenuClick ( option ) {
console . log ( '选择了选项:' , option , ',节点数据:' , this . contextMenuNode ) ;
// 根据选项执行对应操作
switch ( option ) {
case 'a' :
this . showAddDialog ( 'edit' ) ;
// 处理选项a逻辑
break ;
case 'b' :
this . showBand ( ) ;
// 处理选项b逻辑
break ;
case 'c' :
this . finalVersion ( ) ;
// 处理选项b逻辑
break ;
case 'd' :
this . showHistory ( ) ;
// 处理选项c逻辑
break ;
case 'e' :
// 处理选项d逻辑
this . deleteDialog ( ) ;
break ;
}
// 关闭菜单
this . contextMenuVisible = false ;
} ,
// 复用路径截取函数
getLastPartOfPath ( path ) {
if ( ! path || typeof path !== 'string' ) return '' ;
const lastBackslashIndex = path . lastIndexOf ( '\\' ) ;
return lastBackslashIndex === - 1 ? path : path . slice ( lastBackslashIndex + 1 ) ;
} ,
//转译 多个反斜杠
fixJsonEscapes ( str ) {
// 步骤1: 先将所有单个\转义为\\(基础转义修复)
let fixed = str . replace ( /(?<!\\)\\/g , '\\\\' ) ;
// // 步骤2: 将所有实际换行符( \n) 替换为字符串\\n
// fixed = fixed.replace(/\n/g, '\\n');
// // 步骤3: 处理可能存在的\r( 回车符)
// fixed = fixed.replace(/\r/g, '\\r');
return fixed ;
} ,
//测试 新开一个浏览器窗口
openWangG2InNewWindow ( sendStr ) {
let str = "[{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_000_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_000_00_zh_cn\",\"CreationTime\":\"2025-09-01T16:39:07.0578892+08:00\"},{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_001_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_001_00_zh_cn\",\"CreationTime\":\"2025-09-01T16:41:46.4181541+08:00\"},{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_002_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_002_00_zh_cn\",\"CreationTime\":\"2025-09-01T16:42:06.7153697+08:00\"},{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_003_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_003_00_zh_cn\",\"CreationTime\":\"2025-09-01T16:42:25.8314261+08:00\"},{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_004_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_004_00_zh_cn\",\"CreationTime\":\"2025-09-01T16:51:02.3778949+08:00\"},{\"Path\":\"C:\\Users\\sw\\Desktop\\net8.0-windows7.0\\DM_Material\\Version\\DMC-testNew2-A-P4-20-00-00A-00001A-A\\DMC-testNew2-A-P4-20-00-00A-00001A-A_005_00_zh_cn\",\"Name\":\"DMC-testNew2-A-P4-20-00-00A-00001A-A_005_00_zh_cn\",\"CreationTime\":\"2025-09-02T15:59:19.5476416+08:00\"}]"
// let strb = JSON.parse(str);
console . log ( "解析的结果" , str )
// // 获取wangG2页面的路由路径
const wangG2Url = this . $router . resolve ( { name : 'WangG2' } ) . href
// // 打开新窗口,可指定窗口大小和位置
// window.open(
// url,
// '_blank',
// 'width=800,height=600,top=100,left=100'
// )
// 打开新窗口, 假设wangG2.vue的路由路径是/wangG2
// const wangG2Url = this.$router.resolve({ path: '/wangG2' }).href;
// 打开新窗口并设置尺寸
this . wangG2Window = window . open (
wangG2Url ,
'WangG2Window' ,
'width=800,height=600,left=200,top=100'
) ;
// 检查窗口是否被浏览器拦截
if ( ! this . wangG2Window ) {
this . $message . error ( '窗口被浏览器拦截,请允许弹出窗口' ) ;
return ;
}
// 定时检查窗口是否加载完成并发送数据
this . checkWindowTimer = setInterval ( ( ) => {
// 窗口已关闭
if ( this . wangG2Window . closed ) {
clearInterval ( this . checkWindowTimer ) ;
this . $message . info ( 'wangG2窗口已关闭' ) ;
return ;
}
try {
// 尝试发送消息,确保窗口已加载
this . wangG2Window . postMessage (
{
type : 'INIT_DATA' ,
// payload: this.dataToSend,
payload : sendStr ,
sender : 'MainPage'
} ,
window . location . origin // 限制只发送到同源地址
) ;
// 发送成功后清除定时器
clearInterval ( this . checkWindowTimer ) ;
this . $message . success ( '数据已发送到wangG2窗口' ) ;
} catch ( error ) {
// 窗口未加载完成时会抛出错误,继续等待
console . log ( '等待wangG2窗口加载...' ) ;
}
} , 100 ) ;
} ,
// 将处理逻辑提取为单独的方法,便于绑定和解绑
handleFilePathSend ( e ) {
const newStr = this . parseSpecialString ( e . detail ) ;
console . log ( '路径接收:' , this . currentNode , e , e . detail , newStr ) ;
// 访问 currentNode 前先判断是否存在,避免 null 错误
if ( this . currentNode && this . currentNode . attributes ) {
this . currentNode . attributes . push ( newStr ) ;
this . replaceAttributes ( ) ;
console . log ( "当前节点" , this . currentNode , this . treeData ) ;
} else {
console . warn ( 'currentNode 不存在或无 attributes 属性' ) ;
}
} ,
} ,
watch : {
// 监听新建目录的弹窗状态
dialogVisibleNav ( newVal , oldVal ) {
console . log ( "弹窗" , newVal , oldVal )
if ( newVal == true ) {
this . loadFileDMC = '' ;
}
}
} ,
created ( ) {
// let that = this;
// 方式1: 直接访问全局变量
this . $watch (
( ) => this . $dotNetMessage ,
( newMsg ) => {
console . log ( '收到消息:' , newMsg )
}
)
//和后台交互 获取对应的DMC的历史版本列表
window . addEventListener ( 'GetHistoryVesions' , ( e ) => {
console . log ( '接收历史版本信息:' , e . detail )
if ( e . detail ) {
const aa = this . fixJsonEscapes ( e . detail ) ;
console . log ( "1第一次接收历史版本信息this.historyData" , e . detail , aa )
this . historyData = JSON . parse ( aa ) ;
console . log ( "1第二次接收历史版本信息this.historyData" , this . historyData )
}
} )
//和后台交互 暂未使用
window . addEventListener ( 'GetHistoryDMContent' , ( e ) => {
console . log ( 'GetHistoryDMContent接收历史版本信息XML:' , e . detail )
} )
//和后台交互 新建章节目录时候点击加载DMC文件
window . addEventListener ( 'GetExistenceDMContent' , ( e ) => {
// console.log('接收历史版本DMC的XML内容:',e, e.detail)
if ( e . detail ) {
this . isLoadOldDmc = '2' ;
this . showView = true ;
this . loadFileXML = e . detail ;
if ( this . loadFileXML . startsWith ( '"' ) ) {
this . loadFileXML = this . loadFileXML . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( this . loadFileXML . endsWith ( '"' ) ) {
this . loadFileXML = this . loadFileXML . substring ( 0 , this . loadFileXML . length - 1 ) ;
}
this . parseXmlDmc ( ) ;
}
} )
//和后台交互 接收目录XML
window . addEventListener ( 'FrontLoadProjectNew' , ( e ) => {
// 加载目录
console . log ( 'FrontLoadProjectNew 参数接收:' )
this . isLoadXml = true ;
this . currentNode = '' ;
//获取目录字段拼接,暂不用
// this.extractDmCode(e.detail)
// 去除首尾的双引号
let processed = e . detail . trim ( ) ;
// 检查并去除开头的双引号
if ( processed . startsWith ( '"' ) ) {
processed = processed . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( processed . endsWith ( '"' ) ) {
processed = processed . substring ( 0 , processed . length - 1 ) ;
}
// this.outputXml = processed;
this . generateTreeData ( processed ) ;
// this.parseXml(processed);
// this.parseToTreeData(processed)
} )
//和后台交互 单独获取DM的文文件(暂未使用)
window . addEventListener ( 'GetDMDta' , ( e ) => {
// 加载目录
console . log ( 'GetDMDta 参数接收:' , e , e . detail )
} )
//和后台交互 接收富文本XML
window . addEventListener ( 'FrontLoadDM' , this . FrontLoadDM _g1 )
//和后台交互 获取文件地址
window . addEventListener ( 'SendResourcePath' , ( e ) => {
console . log ( '拖拽文件地址:' , e , e . detail )
// 1. 去除双引号
const parsedA = this . lisenPath . replace ( /"/g , '' ) ;
const parsedB = e . detail . replace ( /"/g , '' ) ;
// 2. 处理转义字符(如斜杠)
const processedA = parsedA . replace ( /\\/g , '' ) ;
const processedB = parsedB . replace ( /\\/g , '' ) ;
// 3. 确保基础URL以斜杠结尾
let baseUrl = processedA ;
if ( baseUrl && ! baseUrl . endsWith ( '/' ) ) {
baseUrl += '/' ;
}
const cleanedFile = parsedB . replace ( /\\/g , '' ) ;
// 2. 提取后缀名
const lastDotIndex = cleanedFile . lastIndexOf ( '.' ) ;
const suffix = cleanedFile . substring ( lastDotIndex + 1 ) . toLowerCase ( ) ;
// allImgType allMusicType allVideoType
console . log ( "后缀" , suffix )
switch ( this . isImageSuffix ( suffix ) ) {
case 'img' :
this . insertImage ( baseUrl + processedB )
// this.insertImage( baseUrl + '/zw.jpg')
break ;
case 'music' :
this . insertAudio ( baseUrl + processedB )
break ;
case 'video' :
this . insertVideo ( baseUrl + processedB )
break ;
case '3d' :
this . insert3d ( baseUrl + '/zw.jpg' )
break ;
default :
this . $message ( {
message : '当前文件不支持' ,
type : 'warning'
} ) ;
break ;
}
} )
console . log ( '监听器开始注册:' , Date . now ( ) ) // 打印注册时间戳
//和后台交互 获取文件地址
window . addEventListener ( 'SendLisentPath' , this . SendLisentPathFun )
//和后台交互 获取项目名
window . addEventListener ( 'SendProjectName' , ( e ) => {
this . domNameStr [ 1 ] = this . removeQuotationMarks ( e . detail ) ;
console . log ( '获取项目文件夹名子:' , this . domNameStr , e , e . detail )
} )
//和后台交互 点击请求需要获取哪个DMC的历史版本列表
window . addEventListener ( 'GetHistoryVesions' , ( e ) => {
console . log ( '查询历史版本内容' , e . detail )
} )
//和后台交互 定稿之后获取最新的dm名称
window . addEventListener ( 'SendNewVersionDMFileName' , ( e ) => {
console . log ( "定稿以后的信息" , e . detail )
let str = this . removeQuotationMarks ( e . detail ) ;
console . log ( "定稿以后的 str" , str )
const firstUnderline = str . indexOf ( '_' ) ;
console . log ( "定稿以后的 firstUnderline" , firstUnderline )
const secondUnderline = str . indexOf ( '_' , firstUnderline + 1 ) ;
console . log ( "节点属性" , this . currentNode )
console . log ( "定稿以后的secondUnderline" , secondUnderline )
if ( this . currentNode ) {
this . currentNode . lagreVersion = str . substring (
firstUnderline + 1 ,
secondUnderline
) ;
this . updateNodeVersion ( this . currentNode . id , this . currentNode . lagreVersion )
console . log ( "定稿以后的currentNode" , this . currentNode )
console . log ( "定稿以后的树" , this . treeData )
this . catalogueAnalysis ( this . treeData ) ;
}
} )
//和后台交互 获取加载时候的DMC文件预览服务器端口号
window . addEventListener ( 'handPrePath' , ( e ) => {
console . log ( 'handPrePath111111111' , e . detail )
if ( e ) {
this . viewLis = e . detail ;
}
} )
//和后台交互 获取加载时候的DMC文件具体内容
window . addEventListener ( 'handreContent' , ( e ) => {
console . log ( '打印handreContent111111111111' , e . detail )
if ( e ) {
this . maskViewShow = true ;
this . viewXml = e . detail ;
if ( this . viewLis . startsWith ( '"' ) ) {
this . viewXml = this . viewXml . substring ( 1 ) ;
}
// 检查并去除结尾的双引号
if ( this . viewXml . endsWith ( '"' ) ) {
this . viewXml = this . viewXml . substring ( 0 , this . viewXml . length - 1 ) ;
}
this . parseXmlDmc _loadFile ( ) ;
}
} )
// window.addEventListener('handleMessageFromDotNet', this.fun1)
} ,
}
< / script >
< style >
. editor - container {
width : 100 % ;
margin : 0 auto ;
box - sizing : border - box ;
display : flex ;
}
. leftDiv {
width : 350 px ; /* 左边宽度 30% */
/* background: lightblue; */
padding - top : 25 px ;
}
. rightDiv {
width : calc ( 100 % - 350 px ) ; /* 右边宽度 70% */
/* background: lightcoral; */
height : 600 px ;
overflow : hidden auto ;
padding : 20 px ;
padding - top : 35 px ;
}
. toolbar {
margin - bottom : 10 px ;
}
. toolbar button {
margin - right : 10 px ;
padding : 5 px 10 px ;
background : # 409 eff ;
color : white ;
border : none ;
border - radius : 4 px ;
cursor : pointer ;
}
. toolbar button : hover {
background : # 66 b1ff ;
}
. editor2Opacity {
opacity : .5 ;
}
# editor , # editor2 {
/* border: 1px solid #ddd; */
min - height : 300 px ;
padding : 10 px ;
padding - top : 0 ;
text - align : left ;
}
# nav {
text - align : left ;
}
. content - preview {
margin - top : 20 px ;
border : 1 px solid # eee ;
padding : 15 px ;
background : # fafafa ;
text - align : left ;
}
# main th ,
# main td {
border : 1 px solid # ddd ;
padding : 8 px ;
text - align : left ;
}
# main th {
background - color : # f2f2f2 ;
}
# main {
height : 70 % ;
overflow : hidden ;
overflow - y : auto ;
}
/* 视频容器样式 */
. video - wrapper {
position : relative ;
margin : 15 px 0 ;
/* border: 1px solid #ddd; */
border - radius : 4 px ;
overflow : hidden ;
}
. video - controls {
position : absolute ;
top : 5 px ;
right : 5 px ;
z - index : 10 ;
}
. video - delete {
display : inline - block ;
padding : 2 px 8 px ;
background : rgba ( 255 , 0 , 0 , 0.7 ) ;
color : white ;
border - radius : 4 px ;
cursor : pointer ;
font - size : 12 px ;
user - select : none ;
}
. video - delete : hover {
background : rgba ( 255 , 0 , 0 , 0.9 ) ;
}
/* 确保视频响应式 */
video {
max - width : 100 % ;
display : block ;
background : # 000 ;
}
/* 禁用菜单项样式 */
. disabled - menu - item {
opacity : 0.5 ! important ;
cursor : not - allowed ! important ;
pointer - events : none ! important ;
}
/* 如果需要工具提示也禁用 */
. w - e - toolbar . w - e - menu : nth - child ( 1 ) ,
. w - e - toolbar . w - e - menu : nth - child ( 2 ) ,
. w - e - toolbar . w - e - menu : nth - child ( 18 ) ,
. w - e - toolbar . w - e - menu : nth - child ( 19 ) ,
. w - e - toolbar . w - e - menu : last - child {
/* display: none !important; */
}
. s1000d - editor - container {
display : flex ;
flex - direction : column ;
/*height: 100vh;*/
/* padding: 20px; */
box - sizing : border - box ;
}
. toolbar {
margin - bottom : 15 px ;
}
. tool - btn {
padding : 8 px 15 px ;
margin - right : 10 px ;
background - color : # 409 eff ;
color : white ;
border : none ;
border - radius : 4 px ;
cursor : pointer ;
}
. tool - btn : hover {
background - color : # 66 b1ff ;
}
. editor - area {
display : flex ;
flex : 1 ;
gap : 20 px ;
}
. editor {
flex : 1 ;
border : 1 px solid # dcdfe6 ;
border - radius : 4 px ;
overflow : hidden ;
}
. xml - preview {
flex : 1 ;
border : 1 px solid # dcdfe6 ;
border - radius : 4 px ;
padding : 10 px ;
overflow : auto ;
background - color : # f5f7fa ;
}
. xml - preview pre {
white - space : pre - wrap ;
font - family : Consolas , Monaco , monospace ;
margin : 0 ;
}
. modal {
position : fixed ;
z - index : 1000 ;
left : 0 ;
top : 0 ;
width : 100 % ;
height : 100 % ;
background - color : rgba ( 0 , 0 , 0 , 0.5 ) ;
display : flex ;
justify - content : center ;
align - items : center ;
}
. modal - content {
background - color : white ;
padding : 20 px ;
border - radius : 5 px ;
width : 60 % ;
max - height : 80 % ;
overflow : auto ;
}
. close {
float : right ;
font - size : 24 px ;
cursor : pointer ;
}
. valid {
color : # 67 c23a ;
}
. invalid {
color : # f56c6c ;
}
/deep/ . editor . w - e - text {
text - align : left ;
}
# nav {
overflow : hidden ;
height : 300 px ;
overflow - y : auto ;
}
. context - menu {
position : fixed ;
background : white ;
border : 1 px solid # ddd ;
box - shadow : 0 2 px 10 px rgba ( 0 , 0 , 0 , 0.2 ) ;
z - index : 1000 ;
padding : 5 px 0 ;
min - width : 100 px ;
}
. menu - item {
padding : 8 px 15 px ;
cursor : pointer ;
}
. menu - item : hover {
background - color : # f0f0f0 ;
}
. menu - item . active {
background - color : # e6f7ff ;
color : # 1890 ff ;
font - weight : bold ;
}
button {
margin : 10 px 10 px 0 0 ;
padding : 8 px 15 px ;
background : # 1890 ff ;
color : white ;
border : none ;
border - radius : 4 px ;
cursor : pointer ;
}
button : hover {
background : # 40 a9ff ;
}
< / style >
< style scoped >
/* 修改后的样式 */
. image - preview - dialog {
display : flex ;
flex - direction : column ;
background : rgba ( 0 , 0 , 0 , 0.9 ) ;
}
. image - container {
width : 100 % ;
overflow : auto ;
display : flex ;
align - items : center ;
justify - content : center ;
/* 默认高度( 会被JS覆盖) */
height : 80 vh ;
/* 添加边界保护 */
min - height : 500 px ;
max - height : calc ( 100 vh - 150 px ) ;
}
. control - bar {
height : 80 px ; /* 固定高度 */
flex - shrink : 0 ;
background : rgba ( 0 , 0 , 0 , 0.7 ) ;
display : flex ;
justify - content : center ;
align - items : center ;
gap : 15 px ;
}
/* 大屏适配 */
@ media ( min - height : 800 px ) {
. image - container {
height : 85 vh ;
}
}
. control - bar {
padding : 15 px ;
background : rgba ( 0 , 0 , 0 , 0.8 ) ;
border - radius : 10 px ;
box - shadow : 0 2 px 12 px 0 rgba ( 0 , 0 , 0 , 0.3 ) ;
display : flex ;
gap : 10 px ;
justify - content : center ;
}
/* 操作按钮样式 */
. action - btn {
width : 100 px ;
height : 50 px ;
font - size : 16 px ;
border - radius : 8 px ;
display : flex ;
flex - direction : column ;
align - items : center ;
justify - content : center ;
}
. action - btn i {
font - size : 20 px ;
margin - bottom : 5 px ;
}
. action - btn span {
font - weight : bold ;
}
/* 按钮颜色定制 */
. el - button -- primary {
background : # 409 EFF ;
border - color : # 409 EFF ;
}
. el - button -- primary : hover {
background : # 66 b1ff ;
border - color : # 66 b1ff ;
}
/* 旋转按钮特殊样式 */
. rotate - btn {
background : # 67 C23A ;
border - color : # 67 C23A ;
}
. rotate - btn : hover {
background : # 85 ce61 ;
border - color : # 85 ce61 ;
}
. floating - controls {
position : fixed ;
bottom : 30 px ;
left : 50 % ;
transform : translateX ( - 50 % ) ;
display : flex ;
gap : 20 px ;
z - index : 999 ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
/* 悬浮按钮 */
. floating - btn {
width : 60 px ;
height : 60 px ;
border - radius : 50 % ;
border : none ;
background : white ;
color : # 4 a6cf7 ;
display : flex ;
align - items : center ;
justify - content : center ;
2025-07-25 13:28:47 +08:00
cursor : pointer ;
2025-09-15 09:58:52 +08:00
position : relative ;
box - shadow : 0 4 px 20 px rgba ( 0 , 0 , 0 , 0.15 ) ;
transition : all 0.3 s cubic - bezier ( 0.68 , - 0.55 , 0.265 , 1.55 ) ;
}
. floating - btn . icon - container {
width : 40 px ;
height : 40 px ;
border - radius : 50 % ;
display : flex ;
align - items : center ;
justify - content : center ;
transition : all 0.3 s ;
}
. floating - btn . tooltip {
position : absolute ;
top : - 40 px ;
background : # 4 a6cf7 ;
color : white ;
padding : 5 px 10 px ;
border - radius : 6 px ;
2025-07-25 13:28:47 +08:00
font - size : 12 px ;
2025-09-15 09:58:52 +08:00
opacity : 0 ;
pointer - events : none ;
transition : all 0.3 s ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
/* 按钮颜色 */
. zoom - in { background : # 4 a6cf7 ; color : white ; }
. zoom - out { background : # f68084 ; color : white ; }
. rotate - btn { background : # 5 ee7df ; color : white ; }
. reset - btn { background : # f093fb ; color : white ; }
. close - btn { background : # ff7676 ; color : white ; }
/* 悬停动画 */
. floating - btn : hover {
transform : translateY ( - 5 px ) scale ( 1.05 ) ;
box - shadow : 0 8 px 25 px rgba ( 0 , 0 , 0 , 0.2 ) ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
. floating - btn : hover . tooltip {
opacity : 1 ;
transform : translateY ( - 5 px ) ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
. floating - btn : hover . icon - container {
transform : rotate ( 15 deg ) scale ( 1.1 ) ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
/* 点击效果 */
. floating - btn : active {
transform : scale ( 0.95 ) ;
2025-07-25 13:28:47 +08:00
}
2025-09-15 09:58:52 +08:00
. el - dialog _ _wrapper {
z - index : 10010 ! important ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. highlight {
color : # ff4d4f ;
font - weight : bold ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. operation - buttons {
text - align : left ;
}
/ *
. tree - manager {
padding : 20 px ;
}
. search - input {
width : 300 px ;
2025-07-28 17:01:13 +08:00
margin - right : 10 px ;
2025-09-15 09:58:52 +08:00
}
. tree - container {
border : 1 px solid # ebeef5 ;
2025-07-28 17:01:13 +08:00
border - radius : 4 px ;
2025-09-15 09:58:52 +08:00
padding : 10 px ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. el - tree {
min - height : 200 px ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. highlight {
color : # ff4d4f ;
font - weight : bold ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. custom - tree - node {
2025-07-28 17:01:13 +08:00
flex : 1 ;
2025-09-15 09:58:52 +08:00
display : flex ;
align - items : center ;
justify - content : space - between ;
font - size : 14 px ;
padding - right : 8 px ;
} * /
. tree - container {
overflow - x : auto ;
max - width : 280 px ;
margin : 30 px auto ;
margin - top : 10 px ;
padding : 20 px ;
border : 1 px solid # e0e0e0 ;
border - radius : 8 px ;
position : relative ;
}
. el - tree - node _ _children {
overflow : auto ;
}
. el - tree - node _ _content {
max - width : 280 px ;
height : 30 px ;
overflow : auto ;
}
. el - tree - node _ _content span div {
/* overflow: auto; */
/* width:150px; */
text - align : left ;
}
/ * . b i n d M a i n {
text - align : left ;
2025-07-28 17:01:13 +08:00
overflow : hidden ;
2025-09-15 09:58:52 +08:00
overflow - y : auto ;
}
. bindMain > div {
margin - top : 10 px ;
} * /
. zyBox {
text - align : left ;
border : 1 px dashed deepskyblue ;
padding : 10 px ;
padding - top : 0 ;
border - radius : 4 px ;
margin - bottom : 20 px ;
}
. mask {
position : absolute ;
top : 0 ;
left : 0 ;
width : 100 % ;
height : 100 % ;
background - color : # 9 cf ;
opacity : 0.1 ;
}
. maskView {
position : fixed ;
top : 0 ;
left : 0 ;
z - index : 10010 ;
background - color : rgba ( 0 , 0 , 0 , .5 ) ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
< / style >
2025-07-28 17:01:13 +08:00
2025-09-15 09:58:52 +08:00
< style scoped >
/* 设置树形组件节点的定位和左内边距 */
. tree - container / deep / . el - tree - node {
position : relative ;
padding - left : 13 px ;
}
/* 设置树形组件节点的 before 伪类的样式*/
. tree - container / deep / . el - tree - node : before {
width : 1 px ;
height : 100 % ;
content : '' ;
position : absolute ;
top : - 38 px ;
bottom : 0 ;
left : 0 ;
right : auto ;
border - width : 1 px ;
border - left : 1 px solid # b8b9bb ;
}
/* // 设置树形组件节点的 after 伪类的样式 */
. tree - container / deep / . el - tree - node : after {
width : 13 px ;
height : 13 px ;
content : '' ;
position : absolute ;
left : 0 ;
right : auto ;
top : 12 px ;
bottom : auto ;
border - width : 1 px ;
border - top : 1 px solid # b8b9bb ;
}
/* // 设置树形组件首节点的左边框不显示 */
. tree - container / deep / . el - tree > . el - tree - node : before {
border - left : none ;
}
/* // 设置树形组件首节点的顶部边框不显示 */
. tree - container / deep / . el - tree > . el - tree - node : after {
border - top : none ;
}
/* // 设置树形组件末节点的 before 伪类的高度 */
. tree - container / deep / . el - tree . el - tree - node : last - child : before {
height : 50 px ;
}
/* // 设置树形组件节点字体大小、以及取消左内边距 */
. tree - container / deep / . el - tree . el - tree - node _ _content {
/* overflow: auto; */
color : # 000 ;
font - size : 14 px ;
padding - left : 0 ! important ;
height : 20 px ;
}
/* // 设置树形组件孩子节点左内边距 */
. tree - container / deep / . el - tree . el - tree - node _ _children {
padding - left : 11.5 px ;
}
/* // 设置树形组件复选框左右外边距 */
. tree - container / deep / . el - tree . el - tree - node _ _content > label . el - checkbox {
margin : 0 5 px 0 5 px ! important ;
}
/* // 设置树形组件展开图标定位、图层、内边距 */
. tree - container / deep / . el - tree . el - tree - node _ _expand - icon {
position : relative ;
z - index : 99 ;
}
/* // 设置树形组件叶子节点的默认图标不显示 */
. tree - container / deep / . el - tree . el - tree - node _ _expand - icon . is - leaf {
display : none ;
}
/* // 设置树形组件叶子节点的横线 */
. tree - container / deep / . el - tree . leaf - node - line {
width : 23 px ;
height : 13 px ;
content : '' ;
position : absolute ;
left : 13 px ;
right : auto ;
top : 12 px ;
bottom : auto ;
border - width : 1 px ;
border - top : 1 px solid # b8b9bb ;
}
/* // 设置树形组件有叶子节点的左外边距 */
. tree - container / deep / . el - tree . el - tree - node _ _content : has ( . is - leaf ) {
color : # 096 ;
margin - left : 24 px ! important ;
height : 36 px ;
/* overflow:auto; */
}
. el - tree -- highlight - current . el - tree - node . is - current > . el - tree - node _ _content {
background - color : # ccffdd ;
}
/deep/ . el - tree -- highlight - current . el - tree - node . is - current > . el - tree - node _ _content {
background - color : # 99 ccff6b ;
}
. w - e - tooltip - up . w - e - tooltip - item - wrapper : nth - child ( 1 ) {
display : none ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
/* 针对 el-tree 容器的滚动条优化 */
. elTree {
/* 设置最大高度以触发滚动 */
max - height : calc ( 100 vh - 200 px ) ;
overflow - y : auto ;
padding - right : 5 px ; /* 预留滚动条空间 */
padding - bottom : 5 px ; /* 预留横向滚动条空间 */
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
/* 滚动条轨道 - 区分横向和纵向 */
. elTree : : - webkit - scrollbar {
width : 6 px ; /* 纵向滚动条宽度 */
height : 4 px ; /* 横向滚动条高度(变细) */
}
/* 滚动条轨道背景 */
. elTree : : - webkit - scrollbar - track {
background : rgba ( 241 , 241 , 241 , 0.5 ) ; /* 轨道颜色更透明 */
border - radius : 3 px ;
}
/* 滚动条滑块 - 区分横向和纵向 */
. elTree : : - webkit - scrollbar - thumb {
background : rgba ( 193 , 193 , 193 , 0.6 ) ; /* 滑块颜色更透明 */
border - radius : 3 px ;
transition : background 0.3 s ease ;
}
/* 滚动条滑块悬停状态 */
. elTree : : - webkit - scrollbar - thumb : hover {
background : rgba ( 168 , 168 , 168 , 0.7 ) ; /* 悬停时透明度降低 */
}
/* 滚动条滑块激活状态 */
. elTree : : - webkit - scrollbar - thumb : active {
background : rgba ( 136 , 136 , 136 , 0.8 ) ; /* 激活时更不透明 */
}
/* 隐藏角落的交汇处 */
. elTree : : - webkit - scrollbar - corner {
background : transparent ;
}
/* Firefox 滚动条样式适配 */
. elTree {
scrollbar - width : thin ;
scrollbar - color : rgba ( 193 , 193 , 193 , 0.6 ) rgba ( 241 , 241 , 241 , 0.5 ) ;
}
< / style >
< style scoped >
. custom - context - menu {
2025-07-28 17:01:13 +08:00
position : fixed ;
2025-09-15 09:58:52 +08:00
width : 120 px ;
background : # fff ;
border - radius : 4 px ;
box - shadow : 0 2 px 10 px rgba ( 0 , 0 , 0 , 0.15 ) ;
2025-07-28 17:01:13 +08:00
z - index : 1000 ;
2025-09-15 09:58:52 +08:00
padding : 5 px 0 ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. menu - item {
padding : 6 px 15 px ;
cursor : pointer ;
font - size : 14 px ;
}
/deep/ . el - dialog {
border - radius : 10 px ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
. loadContent1 {
/* height:50px; */
background - color : # fff ;
width : 90 % ;
/* height: 90%; */
/ * p o s i t i o n : a b s o l u t e ;
top : 5 % ;
left : 5 % ;
padding : 20 px ;
overflow : auto ;
box - sizing : border - box ; * /
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
/deep/ . loadContent table {
border - collapse : collapse ; /* 合并边框 */
width : 100 % ;
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
/deep/ . loadContent table , /deep/ . loadContent td {
border : 1 px solid # ddd ; /* 表格、表头、单元格都添加边框 */
2025-07-28 17:01:13 +08:00
}
2025-09-15 09:58:52 +08:00
/deep/ . loadContent th {
background - color : # f1f1f1 ;
border : 1 px solid # ddd ; /* 表格、表头、单元格都添加边框 */
}
/deep/ . loadContent th , /deep/ . loadContent td {
padding : 8 px 12 px ; /* 添点内边距,让内容不贴边 */
2025-07-28 17:01:13 +08:00
text - align : left ;
}
2025-09-15 09:58:52 +08:00
. changeState {
color : # d25d1f ;
margin - left : - 24 px ;
font - size : 8 px ! important ;
}
/* 树形组件样式 */
. tree - container . el - tree {
white - space : nowrap ;
min - width : 100 % ;
position : static ; /* 避免定位冲突 */
}
/* 解决节点展开后被遮挡的问题 */
. tree - container . el - tree - node {
overflow : visible ! important ; /* 允许子节点溢出显示 */
position : relative ; /* 确保层级正确 */
}
/* 修复连接线和内容容器 */
. tree - container . el - tree - node _ _children {
overflow : visible ! important ;
position : relative ;
}
/* 确保节点内容不被裁剪 */
. tree - container . el - tree - node _ _content {
overflow : visible ! important ;
}
/* 在 wang.vue 的样式部分添加 */
. elTree {
/* 设置固定高度,超出部分显示滚动条 */
max - height : calc ( 100 vh - 200 px ) ; /* 根据页面布局调整具体数值 */
overflow - y : auto ; /* 纵向溢出时显示滚动条 */
overflow - x : auto ; /* 横向溢出时显示滚动条(防止节点名称过长) */
padding - right : 8 px ; /* 预留滚动条空间,避免内容被遮挡 */
}
/* 优化滚动条样式(可选) */
. elTree : : - webkit - scrollbar {
width : 6 px ;
height : 6 px ;
}
. elTree : : - webkit - scrollbar - thumb {
background - color : # ccc ;
border - radius : 3 px ;
}
. elTree : : - webkit - scrollbar - track {
background - color : # f5f5f5 ;
}
/* 针对树形组件容器添加横向滚动支持 */
. tree - container {
/* 限制容器最大宽度(可根据实际布局调整) */
max - width : 100 % ;
overflow - x : auto ; /* 横向溢出时显示滚动条 */
padding - bottom : 8 px ; /* 预留底部空间,避免滚动条遮挡内容 */
}
/* 确保树形组件本身不限制宽度,让内容能撑开容器 */
. elTree {
min - width : 100 % ; /* 至少占满容器宽度 */
display : inline - block ; /* 让树组件宽度由内容决定 */
white - space : nowrap ; /* 防止节点内容自动换行 */
}
/* 优化节点文本显示,避免过长文本被截断 */
. custom - tree - node span ,
. el - tree span {
max - width : none ; /* 取消最大宽度限制 */
overflow : visible ; /* 允许内容溢出显示 */
text - overflow : clip ; /* 取消省略号,完整显示文本 */
}
< / style >
< style scoped >
/* 限制弹窗内容区域高度并添加滚动条 */
/deep/ . custom - dialog . el - dialog _ _body {
max - height : 55 vh ; /* 固定最大高度,可根据需求调整 */
overflow - y : auto ; /* 内容超出时显示纵向滚动条 */
padding : 15 px ; /* 调整内边距,避免内容紧贴边框 */
}
/deep/ . viewDialog . el - dialog _ _body {
max - height : 65 vh ; /* 固定最大高度,可根据需求调整 */
height : 65 vh ; /* 固定最大高度,可根据需求调整 */
}
/* 可选:美化滚动条样式 */
/deep/ . custom - dialog . el - dialog _ _body : : - webkit - scrollbar {
width : 6 px ; /* 滚动条宽度 */
}
/deep/ . custom - dialog . el - dialog _ _body : : - webkit - scrollbar - thumb {
background : # ccc ; /* 滚动条滑块颜色 */
border - radius : 3 px ; /* 滑块圆角 */
}
/deep/ . custom - dialog . el - dialog _ _body : : - webkit - scrollbar - track {
background : # f5f5f5 ; /* 滚动条轨道颜色 */
}
< / style >
< style scoped >
/deep/ . fine - stripe - border1 {
margin : 50 px auto ;
padding : 20 px ;
border : 12 px solid ;
border - image : linear - gradient ( 45 deg ,
# ffcc00 0 % , # ffcc00 10 % ,
# 000000 10 % , # 000000 20 % ,
# ffcc00 20 % , # ffcc00 30 % ,
# 000000 30 % , # 000000 40 % ,
# ffcc00 40 % , # ffcc00 50 % ,
# 000000 50 % , # 000000 60 % ,
# ffcc00 60 % , # ffcc00 70 % ,
# 000000 70 % , # 000000 80 % ,
# ffcc00 80 % , # ffcc00 90 % ,
# 000000 90 % , # 000000 100 %
) 1 ;
/* 内容居中 */
/ * d i s p l a y : f l e x ;
align - items : center ;
justify - content : center ;
font - family : Arial , sans - serif ;
font - size : 18 px ; * /
}
/deep/ . fine - stripe - border2 {
margin : 50 px auto ;
padding : 20 px ;
border : 12 px solid ;
border - image : linear - gradient ( 45 deg ,
# ff0000 0 % , # ff0000 10 % ,
# 000000 10 % , # 000000 20 % ,
# ff0000 20 % , # ff0000 30 % ,
# 000000 30 % , # 000000 40 % ,
# ff0000 40 % , # ff0000 50 % ,
# 000000 50 % , # 000000 60 % ,
# ff0000 60 % , # ff0000 70 % ,
# 000000 70 % , # 000000 80 % ,
# ff0000 80 % , # ff0000 90 % ,
# 000000 90 % , # 000000 100 %
) 1 ;
/* 内容居中 */
/ * d i s p l a y : f l e x ;
align - items : center ;
justify - content : center ;
font - family : Arial , sans - serif ;
font - size : 18 px ; * /
}
. iconImg {
height : 20 px ;
cursor : pointer ;
margin - right : 20 px ;
margin - top : 10 px ;
}
2025-07-25 13:28:47 +08:00
< / style >