Files
IETM-web/src/components/wang.vue
2025-10-17 08:28:46 +08:00

5298 lines
184 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div style="height:100%;width:100%;">
<el-container style="height:100%;width:100%;">
<el-aside
:width="leftWidth + 'px'"
style="position: relative; overflow: hidden;"
>
<div class="drag-handle" @mousedown="startDrag"></div>
<div class="leftDiv" v-if='isLoadXml' style="width:100%;" >
<div id='navMain'>
<!-- 操作栏 -->
<div class="operation-buttons">
<!-- 节点搜索框 -->
<div style="margin:5px auto;width:100%;">
<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>
<!-- 操作栏按钮 -->
<div style="display:flex;margin-bottom: 5px;">
<div style="width:25%;height:30px;" class="iconImgDiv" @click="showAddDialog('create')" title='新建' v-if='isLoadXml'><img class='iconImg' title='新建' src="../assets/img/addIcon.png" alt=""></div>
<div style="width:25%;height:30px;" class="iconImgDiv" @click="showAddDialog('edit')" title='编辑' v-if='currentNode'><img class='iconImg' title='编辑' src="../assets/img/editIcon.png" alt=""></div>
<div style="width:25%;height:30px;" class="iconImgDiv" @click="saveNowDmcClick" title='保存' v-if='currentNode' ><img class='iconImg' title='保存' src="../assets/img/saveIcon.png" alt=""></div>
<div style="width:25%;height:30px;" class="iconImgDiv" @click="deleteDialog" title='删除' v-if='currentNode'><img class='iconImg' title='删除' src="../assets/img/delIcon.png" alt=""></div>
</div>
</div>
<!-- 'maxHeight':leftHeight+'px', -->
<div class="tree-container" :style="{'minHeight':'100px'}">
<div class="navTitle" >
<p @click='clearNodeState' :title="getBookName">{{getBookName}}</p>
<img @click='editBookName' class='iconImgMulu' title='编辑书名' src="../assets/img/bianji.png" alt="">
</div>
<el-scrollbar style="">
<!-- 滚动内容区域 -->
<div class="scroll-content">
<!-- 目录结构树 -->
<el-tree
class="elTree elTreeMain gd"
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-drag-end="handleDragEnd"
@node-contextmenu="handleNodeContextMenu"
:expand-on-click-node="false"
:highlight-current="true"
draggable
>
<!-- 节点自定义渲染插槽 -->
<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>
</div>
</template>
</span>
</el-tree>
</div>
</el-scrollbar>
</div>
</div>
<!-- <div id='nav'>
<nav-temp />
</div> -->
</div>
</el-aside>
<el-main style="">
<div class="rightDiv">
<div class="bName" :title="getBookName">{{getBookName}}</div>
<!-- 编辑框 -->
<!-- :style="{height:editorHeight+'px'}" -->
<!-- <el-button
type="primary"
icon="el-icon-s-data"
@click="countDomNodes"
style="margin: 5px;"
>
统计DOM节点数量
</el-button> -->
<!-- :class="{ editor2Opacity: dialogVisibleNav||dialogVisibleNavDel|| dialogVisible||dialogVisibleImg||dialogVisibleRight||dialogVisibleTips||dialogVisibleBland||dialogVisibleHistory||dialogVisibleTips2||editBookNameDialog }" -->
<div id="editor" v-show='currentNode' :class="{ editor2Opacity: dialogVisibleNav||dialogVisibleNavDel|| dialogVisible||dialogVisibleImg||dialogVisibleRight||dialogVisibleTips||dialogVisibleBland||dialogVisibleHistory||dialogVisibleTips2||editBookNameDialog }" ref="editor" ></div>
<!-- 提示信息 -->
<!-- <div class="paAutoStyle" v-show="!currentNode && isLoadXml">请打开所要编辑的的章节目录</div>
<div class="paAutoStyle" v-show="!isLoadXml">请加载所要编辑的文档目录</div> -->
</div>
</el-main>
</el-container>
<div class="paAuto paAutoStyle" v-show="!isLoadMsg">请加载有需编辑的项目</div>
<!-- 统计结果弹窗 -->
<el-dialog
title="DOM节点统计结果"
:visible.sync="countDialogVisible"
width="40%"
>
<div class="statistics-result">
<p>目标容器: {{ countTarget }}</p>
<p>总DOM节点数量: <span class="count-number">{{ domCount }}</span></p>
<p>元素节点数量: <span class="count-number">{{ elementCount }}</span></p>
<p>文本节点数量: <span class="count-number">{{ textCount }}</span></p>
<p>注释节点数量: <span class="count-number">{{ commentCount }}</span></p>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="countDialogVisible = false">关闭</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>
</div>
</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&&currentNode.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>
<!-- 新建编辑目录弹窗 -->
<el-dialog
:title="navIsAdd=='create'?'新建章节':'编辑章节'"
:visible.sync="dialogVisibleNav"
width="80%"
class="custom-dialog"
:before-close="handleClose"
>
<el-form label-position="left" label-width="120px" :model="form" :rules="rules" ref="form">
<!-- 按钮区域 -->
<div style="margin-bottom: 15px;">
<el-button type="info" icon="el-icon-folder-opened" v-if='navIsAdd == "create"' @click="loadFileBtn">加载文件</el-button>
<el-button type="info" icon="el-icon-data-analysis" v-if='showView' @click="viewLoadDMFile">预览文件</el-button>
</div>
<!-- 两列布局容器 -->
<el-row :gutter="20">
<!-- 第一列 -->
<el-col :span="24">
<div class="colStyle colStyle1">
<img title='章节名称' src="../assets/img/wenjian.png" >
<span>章节名称</span>
</div>
<el-input v-model="form.name" autocomplete="off"></el-input>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<div class="colStyle">
<img title='责任合作单位' src="../assets/img/danwei.png" >
<span>责任合作单位</span>
</div>
<el-input v-model="form.contributor" autocomplete="off"></el-input>
</el-col>
<!-- 第一列 -->
<el-col :span="12">
<div class="colStyle">
<img title='创作单位' src="../assets/img/hezuodanwei.png" >
<span>创作单位</span>
</div>
<el-input v-model="form.creator" autocomplete="off"></el-input>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<div class="colStyle">
<img title='适用性信息' src="../assets/img/xinxi.png" >
<span>适用性信息</span>
</div>
<el-input v-model="form.applicabilityInformation" autocomplete="off"></el-input>
</el-col>
<!-- 第一列 -->
<el-col :span="12">
<div class="colStyle">
<img title='质量验证' src="../assets/img/xinxi.png" >
<span>质量验证</span>
</div>
<el-input v-model="form.qualityVerification" autocomplete="off"></el-input>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<div class="colStyle">
<img title='权限' src="../assets/img/quanxian.png" >
<span>权限</span>
</div>
<!-- <el-input v-model="form.permission" autocomplete="off"></el-input> -->
<el-select v-model="form.permission" style="width:100%;" placeholder="请选择">
<el-option
v-for="item in optionsPermission"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-col>
<!-- 第一列 -->
<el-col :span="12">
<div class="colStyle">
<img title='版本信息' src="../assets/img/jurassic_version.png" >
<span>版本信息</span>
</div>
<el-input v-model="form.version" disabled autocomplete="off"></el-input>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<div class="colStyle">
<img title='发布时间' src="../assets/img/fabushijian.png" >
<span>发布时间</span>
</div>
<el-date-picker
style="width:100%;"
v-model="form.date"
type="date"
placeholder="选择日期">
</el-date-picker>
<!-- <el-input v-model="form.date" autocomplete="off"></el-input> -->
</el-col>
<!-- 第一列 -->
<el-col :span="12">
<div class="colStyle">
<img title='语言' src="../assets/img/duoyuyan.png" >
<span>语言</span>
</div>
<el-input v-model="form.language" autocomplete="off"></el-input>
</el-col>
<!-- 第二列 -->
<el-col :span="12">
<div class="colStyle">
<img title='密级' src="../assets/img/miji.png" >
<span>密级</span>
</div>
<el-select v-model="form.level" style="width:100%;" placeholder="请选择">
<el-option
v-for="item in optionsLevel"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- <el-input v-model="form.level" autocomplete="off"></el-input> -->
</el-col>
<!-- 单独占满一行的表单项 -->
<el-col :span="12" v-if='showView'>
<div class="colStyle">
<img title='使用加载数据' src="../assets/img/xinxi.png" >
<span>使用加载数据</span>
</div>
<div>
<el-select v-model="isLoadOldDmc" style="width:100%;" placeholder="请选择">
<el-option
v-for="item in options2"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
<!-- <el-radio v-model="isLoadOldDmc" label="1">使用</el-radio> -->
<!-- <el-radio v-model="isLoadOldDmc" label="2">不使用</el-radio> -->
</div>
</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='navIsAdd == "create"&&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="50%"
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="50%"
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="50%"
class="custom-dialog"
:before-close="handleClose2">
<span>是否保存当前编辑内容</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="50%"
class="custom-dialog"
:before-close="saveNowDmc2">
<span>是否保存当前编辑内容</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='nowRightHint' :title="nowRightHint">{{nowRightHint}}</div>
<div class="menu-item" @click="handleMenuClick('a')"><img title='编辑章节' src="../assets/img/bianji1.png" ><span>编辑章节</span></div>
<div class="menu-item" @click="handleMenuClick('b')"><img title='绑定资源' src="../assets/img/bangdingziyuanchi.png" ><span>绑定资源</span></div>
<div class="menu-item" @click="handleMenuClick('c')"><img title='版本定稿' src="../assets/img/dinggao.png" ><span>版本定稿</span></div>
<div class="menu-item" @click="handleMenuClick('d')"><img title='历史版本' src="../assets/img/gaojisousuo.png" ><span>历史版本</span></div>
<div class="menu-item" @click="handleMenuClick('e')"><img title='删除章节' src="../assets/img/shanchu-copy.png" ><span>删除章节</span></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"
>
<el-descriptions class="margin-top" v-if='viewXml' title="章节信息" :column="3" border>
<template slot="extra">
<el-button @click='dmcTable' type="primary" size="small">{{dmcHint?"收起":"展开"}}</el-button>
</template>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
章节名称
</template>
{{rdfDescriptions[0].children[0].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
创作单位
</template>
{{rdfDescriptions[0].children[1].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
权限
</template>
{{formatOther('permission',rdfDescriptions[0].children[2].text).label}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
合作单位
</template>
{{rdfDescriptions[0].children[5].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
版本号
</template>
{{rdfDescriptions[0].children[6].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
密级
</template>
{{formatOther('level',this.rdfDescriptions[0].children[7].text).label}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
发布日期
</template>
{{formatDate(rdfDescriptions[0].children[8].text)}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
适用性信息
</template>
{{rdfDescriptions[0].children[9].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
质量验证
</template>
{{rdfDescriptions[0].children[10].text}}
</el-descriptions-item>
<el-descriptions-item v-if='dmcHint'>
<template slot="label">
语言
</template>
{{rdfDescriptions[0].children[14].text}}
</el-descriptions-item>
</el-descriptions>
<div class="loadContent" v-html="neirong">
</div>
</el-dialog>
<el-dialog
title="修改书名"
:visible.sync="editBookNameDialog"
width="60%"
class="custom-dialog viewDialog2"
:before-close="handleCloseEditBookName"
>
<el-input v-model="getBookName" autocomplete="off"></el-input>
<span slot="footer" class="dialog-footer">
<el-button @click="editBookFun(false)">取消</el-button>
<el-button type="primary" @click="editBookFun(true)">修改</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import WangEditor from 'wangeditor';
import brImg from '../assets/img/br.png';
import '../assets/css/style.css'
export default {
name: 'WangEditor',
components: {
},
data() {
return {
countDialogVisible: false,
domCount: 0,
elementCount: 0,
textCount: 0,
commentCount: 0,
countTarget: '',
leftWidth: 380,
isDragging: false,
isLoadMsg:false,
minLevel:'',
maxLevel:'',
maxPermission:'',
minPermission:'',
nowRightHint:'',
dmcHint:false,
rdfDescriptions:[],
editBookNameDialog:false,
getBookName:'',
getBookNameDf:'',
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
shortcuts: [{
text: '今天',
onClick(picker) {
picker.$emit('pick', new Date());
}
}, {
text: '昨天',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24);
picker.$emit('pick', date);
}
}, {
text: '一周前',
onClick(picker) {
const date = new Date();
date.setTime(date.getTime() - 3600 * 1000 * 24 * 7);
picker.$emit('pick', date);
}
}]
},
optionList:[
{
label:'使用',
value:"1"
},
{
label:'不使用',
value:"2"
}
],
optionsPermission:[
{label:'一级',value:'1'},
{label:'二级',value:'2'},
{label:'三级',value:'3'},
{label:'四级',value:'4'},
{label:'五级',value:'5'},
{label:'六级',value:'6'},
{label:'七级',value:'7'},
{label:'八级',value:'8'},
{label:'九级',value:'9'},
{label:'十级',value:'10'},
],
optionsLevel: [
{value: '1',label: '公开'},
{value: '2',label: '秘密'},
{value: '3',label: '机密'},
{value: '4',label: '绝密'}
],
brImg:brImg,
imgUrlJg: require('../assets/img/jgIcon.png'),//警告Icon
imgUrlJs: require('../assets/img/jsIcon.png'),//警示Icon
editorHeight:'',//编辑器高度
historyVsPath:'',//查看历史文件路径
leftHeight:'0',//左边容器高度
isLoadXml:false,//是否加载DMC
neirong:'',//预览内容
isLoadOldDmc: "1", // 初始值需与 options 中的 value 类型一致
options2:[
{
value:"1",
label:"使用",
},
{
value:"2",
label:"不使用",
}
],
showView:false,//是否显加载原文档
tempDivData1:'',//模板文件容器
viewLis:'',//预览时候端口号
viewXml:'',//预览时候的XML内容
maskViewShow:false,//文件预览弹窗是否显示
// 屏幕整体尺寸(设备屏幕尺寸)
screenWidth: 0,
screenHeight: 0,
// 浏览器窗口尺寸
windowW: 0,
windowH: 0,
// 用于防抖的定时器
resizeTimer: null,
// 保存对新窗口的引用
wangG2Window: null,
// 用于检查窗口状态的定时器
checkWindowTimer: null,
showModifyBtn: false, // 控制是否显示【修改】的开关按钮点击后设为true
mId:'',//当前最大ID
loadFileDMC:'',//加载的DMC文件里面的content内容
loadFileXML:'',//加载的DMC文件内容
historyData:[],//历史版本列表信息
contextMenuVisible: false, // 右键菜单是否可见
contextMenuLeft: 0, // 右键菜单left位置
contextMenuTop: 0, // 右键菜单top位置
contextMenuNode: null, // 右键点击的节点数据
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:'1',
contributor:'',
creator:'四威高科',
applicabilityInformation:'',
qualityVerification:'',
permission:'1'
// 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,//暂无用
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',
// ],
newSelector:[],
oldSelector:[],
tempDivData:{//当前富文本str
innerHTML:'五'
},
colors:'',//暂无用
val1:'',//暂无用
val2:'',//暂无用
message: '',//暂无用
editor: null, //编辑器
editorContent: '',//富文本内容
}
},
computed: {
},
mounted() {
// 初始化尺寸
this.getWindowSize()
// 绑定 resize 事件
window.addEventListener('resize', this.handleResize)
// // 确保DOM已加载
// this.$nextTick(() => {
// this.initEditor()
// })
this.$nextTick(() => {
// 初始时如果容器不可见,等待 currentNode 变化后再初始化
if (this.currentNode) {
this.initEditor();
}
});
console.log('chrome对象是否存在:', !!window.chrome);
console.log('webview对象是否存在:', !!window.chrome?.webview);
window.removeEventListener('SelectFilePathSend', this.handleFilePathSend);
// 再绑定新的监听器
window.addEventListener('SelectFilePathSend', this.handleFilePathSend);
window.addEventListener('SelectFilePathSend', this.SendLisentPathFun);
},
beforeDestroy() {
// 销毁编辑器
if (this.editor) {
this.editor.destroy()
}
// 清理定时器
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)
},
methods: {
//清除节点选中
clearNodeState() {
this.currentNode = '';
// 通过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_g2(e) {
// 加载目录
console.log('FrontLoadProjectNew111 参数接收:')
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)
},
//接收富文本内容信息
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:'000',
date:'',
language:'',
level:'1',
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)
}
},
//测试发送给后端信息
sendMessageToHost() {
//调用后端 sendToDotNet
this.$sendToDotNet(this.val1,this.val2);
},
initEditor() {//初始化编辑器配置
this.editor = new WangEditor(this.$refs.editor)
const editorEl = this.$refs.editor;
if (!editorEl) {
console.warn('编辑器容器不存在');
return;
}
// 配置编辑器
this.editor.config.uploadImgShowBase64 = true // 使用 base64 保存图片
this.editor.config.onchange = (html) => {
this.editorContent = html;
}
let dm = this.editor.config.menus;
console.log("默认菜单",dm)
// 启用颜色选择功能
this.editor.config.colors = [
'#000000', '#ffffff', '#eeeef1',
'#ff0000', '#ff5e5e', '#ffbbbb',
'#0033ff', '#0055ff', '#3d7eff',
'red',"#096","#9cf"
]
// 完全自定义菜单
this.editor.config.menus = [
'image', // 图片
'video', // 视频
// 'head', // 标题
'bold', // 粗体
'fontSize',//字号
// 'fontName',//字体
'italic', // 斜体
'underline', // 下划线
'strikeThrough', // 删除线
// 'line',//行高
'lineHeight',//
'foreColor', // 文字颜色
'backColor', // 背景颜色
'link', // 链接
'list', // 列表
// 'todo',//
'justify', // 对齐方式
'quote', // 引用
// 'emoticon',//表情
'table', // 表格
'code', // 代码
'splitLine',//分割线
'undo', // 撤销
'redo', // 重做
]
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;">',1) // 第一个按钮弹出123使用图钉图标
this.addCustomButton('警告', '<img src="'+this.imgUrlJg+'" alt="按钮图标" style="width: 20px; height: 20px; object-fit: contain;">',2) // 第一个按钮弹出123使用图钉图标
}
// 创建编辑器
this.editor.create();
// 特别注意:需要在编辑器创建完成后绑定事件
this.$nextTick(() => {
console.log("初始化 setupDragHandler")
this.setupDragHandler()
})
// 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()
},
//编辑书名
editBookName() {
console.log("编辑书名")
const getBookNameDf = this.getBookName;
this.getBookNameDf = getBookNameDf;
this.editBookNameDialog = true;
},
editBookFun(type) {
if(type){
this.catalogueAnalysis(this.treeData);
this.editBookNameDialog = false;
}else{
this.getBookName = this.getBookNameDf;
this.editBookNameDialog = false;
}
},
// 通用的添加自定义按钮方法,接收两个参数:提示内容和图标
addCustomButton(alertContent, icon,type) {
let toolbarElem = null
// 方式1: 通过编辑器内部属性获取工具栏
if (this.editor.$toolbarElem && this.editor.$toolbarElem[0]) {
toolbarElem = this.editor.$toolbarElem[0]
console.log('通过$toolbarElem获取到工具栏')
}
// 方式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: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
margin: 0 2px;
background: #fff;
border-radius: 2px;
color: #333;
font-size: 18px;
`
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=""><br></p><div style='
// padding: 20px;
// margin: 20px;
// background-image:url("`+this.brImg+`");
// '><p class='teshu' style="border-radius: 4px;padding: 10px;border: 3px solid #000;"></p></div>
// <p data-we-empty-p=""><br></p>`)
// this.editor.cmd.do('insertHTML', `<p class='jg'>[[]]</p>`)
// this.editor.cmd.do('insertHTML', `<p data-we-empty-p=""><br></p><div style='margin: 10px auto;
// padding: 10px;
// border: 10px solid;
// background:#fff;
// border-image: linear-gradient(45deg,
// #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;' class='teshu2'></div><p data-we-empty-p=""><br></p>`)
this.editor.cmd.do('insertHTML', `<p data-we-empty-p=""><br></p><div style='margin: 10px auto;
padding: 10px;
background:#fff;' class='teshu2 borderStyle_yellow'></div><p data-we-empty-p=""><br></p>`)
break;
case 2:
case '2':
// this.editor.cmd.do('insertHTML', `<p class='js'><<>></p>`)
// this.editor.cmd.do('insertHTML', `<div class='jg' style='border:1px solid red;padding:10px;'></div>`)
// this.editor.cmd.do('insertHTML', `<p data-we-empty-p=""><br></p><div style="margin: 50px auto;
// padding: 20px;
// border: 12px solid;
// background:#fff;
// border-image: linear-gradient(-45deg,
// #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;" class='teshu'></div><p data-we-empty-p=""><br></p>`)
this.editor.cmd.do('insertHTML', `<p data-we-empty-p=""><br></p><div style="margin: 10px auto;
padding: 10px;
background:#fff;" class='teshu borderStyle_red'></div><p data-we-empty-p=""><br></p>`)
break;
}
}
// 添加悬停效果
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: 8px 15px;
background: #409eff;
color: white;
border-radius: 4px;
cursor: pointer;
display: inline-block;
margin: 0 5px 10px 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"><div></div></p>`)
break;
case 2:
this.editor.cmd.do('insertHTML', `<p class="fine-stripe-border2"><div></div></p>`)
break;
}
}
// 添加到编辑器容器的最前面
this.$refs.editor.insertBefore(fallbackBtn, this.$refs.editor.firstChild)
console.log(`已创建备用按钮(弹出${alertContent})`)
},
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()
})
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}类型文件,已阻止上传`)
// }
// }
// }
})
},
// 上传图片
insertImage(src) {
if (!this.editor) {
console.error('编辑器未初始化,无法插入图片');
return;
}else{
// src = 'http://localhost:54610/a1.jpg';
// const imgUrl = 'http://youneed.top:10017/uploads/1.jpg'
// const imgUrl = 'https://ww2.sinaimg.cn/mw690/007ut4Uhly1hx4v37mpxcj30u017cgrv.jpg';
if(src){
const imgUrl = src?src:'http://localhost:5432/DM_Material/a1.jpg';
console.log("地址",src,imgUrl)
this.editor.cmd.do('insertHTML', `<img src="${imgUrl}" width="50%" alt="图片">`)
}
}
},
// 上传3D资源模拟占位
insert3d(imgUrl) {
this.editor.cmd.do('insertHTML', `<img src="${imgUrl}" class='model3d' style="width: 100%;" alt="图片"><p data-we-empty-p=""><br></p>`)
// 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 '';
const regex = /<img([^>]*?)class="model3d"([^>]*?)\/?>/gi;
return htmlString.replace(regex, (match, prefix, suffix) => {
const attributes = (prefix || '') + (suffix || '');
return `<model3d class="model3d" ${attributes}></model3d>`;
});
},
//解析3d资源标识
modelToImg(htmlString) {
// 匹配<model3d>标签且class中包含model3d
const regex = /<model3d([^>]*?)class="([^"]*?)model3d([^"]*?)"([^>]*?)>/gi;
// 替换标签名,保留所有属性
return htmlString.replace(regex, '<img$1class="$2model3d$3"$4>');
},
dmcTable() {
if(this.dmcHint){
this.dmcHint = false;
}else{
this.dmcHint = true;
}
},
formatOther(type,data){
let textStr = null;
console.log("内容",type,data)
switch(type){
case "level":
textStr = this.optionsLevel.find(item => {
return item.value === data;
});
break;
case "permission":
textStr = this.optionsPermission.find(item => {
return item.value === data;
});
break;
}
console.log('内容',data,textStr)
return textStr;
},
formatDate(dateStr) {
if (!dateStr) return "";
try {
// 将字符串转换为Date对象
const date = new Date(dateStr);
// 获取年、月、日
const year = date.getFullYear();
// 月份从0开始需要+1并用padStart补零确保两位数
const month = String(date.getMonth() + 1).padStart(2, "0");
// 日期补零确保两位数
const day = String(date.getDate()).padStart(2, "0");
// 返回格式化后的字符串格式YYYY-MM-DD
return `${year}-${month}-${day}`;
} catch (error) {
console.error("日期格式化失败:", error);
return "无效日期";
}
},
parseRdfDescriptions() {
try {
const parser = new DOMParser();
const xmlDoc = parser.parseFromString(this.viewXml, 'text/xml');
// 定义RDF命名空间关键必须与XML中的命名空间一致
const nsResolver = (prefix) => {
const ns = {
'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#'
// 可以添加其他需要的命名空间
};
return ns[prefix] || null;
};
// 使用XPath查询所有rdf:Description元素
const xpathResult = xmlDoc.evaluate(
'//rdf:Description',
xmlDoc,
nsResolver,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null
);
this.rdfDescriptions = [];
let currentNode;
// 遍历所有找到的rdf:Description节点
while ((currentNode = xpathResult.iterateNext())) {
// 获取节点内的所有内容(包括子节点和文本)
const content = {
attributes: {},
children: [],
innerXML: currentNode.innerHTML // 完整的内部XML
};
// 获取所有属性
if (currentNode.attributes) {
for (let i = 0; i < currentNode.attributes.length; i++) {
const attr = currentNode.attributes[i];
content.attributes[attr.name] = attr.value;
}
}
// 获取所有子节点文本内容
if (currentNode.children && currentNode.children.length > 0) {
for (let i = 0; i < currentNode.children.length; i++) {
const child = currentNode.children[i];
content.children.push({
tag: child.tagName,
text: child.textContent,
attributes: Array.from(child.attributes).reduce((attrs, attr) => {
attrs[attr.name] = attr.value;
return attrs;
}, {})
});
}
} else {
// 如果没有子节点,直接获取文本内容
content.text = currentNode.textContent;
}
this.rdfDescriptions.push(content);
}
console.log('所有rdf:Description内容', this.rdfDescriptions);
} catch (error) {
console.error('解析XML出错', error);
}
},
// 插入视频
insertVideo(src) {
if (!this.editor) {
console.error('编辑器未初始化,无法插入插入视频');
return;
}else{
// 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', `<p data-we-empty-p=""><div><video src="${videoUrl}" style="width: 100%;" controls="controls" style="max-width: 100%"></video></div><p data-we-empty-p=""><br></p><p data-we-empty-p=""><br></p></p>`)
}
// 或者使用更简单的插入方式
// this.editor.txt.append(`<video src="${videoUrl}" controls="controls" style="max-width: 100%"></video>`)
},
// 插入音频
insertAudio(src) {
if (!this.editor) {
console.error('编辑器未初始化,无法插入音频');
return;
}else{
// 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 = `
<p data-we-empty-p=""><audio controls src="${audioUrl}" style="width: 100%;"></audio></p><p data-we-empty-p=""><br></p><p data-we-empty-p=""><br></p><p data-we-empty-p=""><br></p>
`;
// 插入到编辑器
this.editor.cmd.do('insertHTML', audioHtml);
}
// 或者使用更简单的方式
// 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里面的东西
if(newDST){
newDST = this.removeColgroup(newDST)
} else{
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://www.purl.org/dc/elements/1.1/">
<rdf:Description>
<dc:title>`+desStr.name+`</dc:title>
<dc:creator>`+desStr.creator+`</dc:creator>
<dc:permission>`+desStr.permission+`</dc:permission>
<dc:subject/>
<dc:publisher>`+desStr.creator+`</dc:publisher>
<dc:contributor>`+desStr.contributor+`</dc:contributor>
<dc:version>`+desStr.version+`</dc:version>
<dc:level>`+desStr.level+`</dc:level>
<dc:date>`+desStr.date+`</dc:date>
<dc:applicabilityInformation>`+desStr.applicabilityInformation+`</dc:applicabilityInformation>
<dc:qualityVerification>`+desStr.qualityVerification+`</dc:qualityVerification>
<dc:type>text</dc:type>
<dc:format>text/xml</dc:format>
<dc:identifier>`+this.getDmName+`</dc:identifier>
<dc:language>`+desStr.language+`</dc:language>
<dc:rights>01</dc:rights>
</rdf:Description>
<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);
console.log("存储最终1",this.tempDivData)
console.log("存储最终2",xmlString)
console.log("存储最终3",xmlData)
//存富文本信息
// 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;
}
this.contentXmlStr = this.editor.txt.html();
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) {
navContainer.innerHTML = '<p>没有找到标题元素,无法生成目录。</p>'
return
}
const tocList = document.createElement('ul')
tocList.style.listStyleType = 'none'
tocList.style.paddingLeft = '0'
headings.forEach(heading => {
console.log("heading",)
const level = parseInt(heading.tagName.substring(1))
const listItem = document.createElement('li')
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;
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)
tocList.appendChild(listItem)
})
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)
},
// 处理所有标题元素的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
},
// XML特殊字符转义
escapeXml(unsafe) {
return unsafe.replace(/[<>&'"]/g, (c) => {
switch (c) {
case '<': return '&lt;';
case '>': return '&gt;';
case '&': return '&amp;';
case '\'': return '&apos;';
case '"': return '&quot;';
default: return c;
}
});
},
// 从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);
// 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)
}
// 重置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(/&lt;/g, '<')
.replace(/&gt;/g, '>')
.replace(/&amp;/g, '&')
.replace(/&apos;/g, "'")
.replace(/&quot;/g, '"');
// 移除可能的多余空格和换行
content = content.trim();
return content;
} catch (e) {
console.error('S1000D导入错误:', e);
alert(`导入S1000D XML失败: ${e.message}`);
return '';
}
},
rgbToHex(r, g, b) {//色号转换
console.log("colors",this.colors)
return `#${[r, g, b].map(x => x.toString(16).padStart(2, '0')).join('')}`;
},
//保存内容到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>`;
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)
}
}
reader.readAsText(file)
},
completeModel3DTags(htmlString) {
// 处理自闭合的model3d标签替换为完整的闭合标签
return htmlString.replace(/<model3d([^>]*?)\/>/g, (match, attributes) => {
// 返回带有相同属性的完整闭合标签
return `<model3d${attributes}></model3d>`;
});
},
// 解析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>')
},
/**
* 修复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>`
})
},
// 检测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>`
})
},
// 检测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>`
})
},
//富文本内容打标签
dataXmlProcessing(type,saveId) {
let html_1 = '';
let html = '';
if(this.editor){
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="文件名"
html_1 = html.replace(reg, '$1$3$4');
console.log('解析地址:',html_1)
}
// 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);
},
countDomNodes() {
// 重置计数
this.domCount = 0
this.elementCount = 0
this.textCount = 0
this.commentCount = 0
// 这里可以改为你需要统计的容器选择器
// 例如: '#editor' 或 '.tree-container' 或 'body'
const targetSelector = '#editor'
const container = document.querySelector(targetSelector)
if (!container) {
this.$message.error('未找到目标容器')
return
}
this.countTarget = targetSelector
// 递归统计所有节点
this.traverseNodes(container)
// 显示结果弹窗
this.countDialogVisible = true
},
// 递归遍历节点并计数
traverseNodes(node) {
if (!node) return
// 总节点数+1
this.domCount++
// 分类计数
switch(node.nodeType) {
case 1: // 元素节点
this.elementCount++
break
case 3: // 文本节点
// 过滤空白文本节点
if (node.textContent.trim()) {
this.textCount++
}
break
case 8: // 注释节点
this.commentCount++
break
}
// 递归处理子节点
if (node.childNodes && node.childNodes.length) {
Array.from(node.childNodes).forEach(child => {
this.traverseNodes(child)
})
}
},
// 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目录如果不需要可以去掉
let html_2 = this.tempDivData1.innerHTML.replace(reg2, `$1${jc}$3$4`);
// html_2 = this.modelToImg(html_2);
// console.log("大豪科技等哈时间",this.viewLis)
// console.log('加载还原地址:',html_2)
let processedL = this.hintFun(html_2)
this.neirong = this.modelToImg(processedL);
// document.getElementsByClassName("loadContent")[0].innerHTML=html_2;
// document.getElementsByClassName("loadContent1")[0].innerHTML=html_2;
// console.log('加载还原地址:',html_3)
// 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();
}
},
hintFun(html_2) {
let html = html_2;
// 先定义所有需要用到的变量,确保初始化顺序
// 需要移除的class
// const classesToRemove = ['borderStyle_yellow', 'borderStyle_red'];
// // 处理class属性 - 先替换指定class
// html = html.replace(/class="([^"]*)"/g, (match, classValues) => {
// let newClassValues = classValues;
// // 在替换函数内部定义class映射确保在使用前初始化
// const classMappings = {
// 'teshu': 'testBo',
// 'teshu2': 'testBo2'
// };
// // 替换class
// Object.keys(classMappings).forEach(oldClass => {
// const newClass = classMappings[oldClass];
// const regex = new RegExp(`\\b${oldClass}\\b`, 'g');
// newClassValues = newClassValues.replace(regex, newClass);
// });
// // 移除不需要的class
// classesToRemove.forEach(classToRemove => {
// const regex = new RegExp(`\\b${classToRemove}\\b\\s*`, 'g');
// newClassValues = newClassValues.replace(regex, '').trim();
// });
// return `class="${newClassValues}"`;
// });
// 定义需要替换的class映射关系
const classMappings = {
'teshu': 'testBo',
'teshu2': 'testBo2'
};
// 使用正则表达式匹配class属性并替换相应的值
// 这个正则表达式会匹配class属性中的各个class名称
html = html.replace(/class="([^"]*)"/g, (match, classValues) => {
let newClassValues = classValues;
// 遍历替换映射替换每个需要替换的class
Object.keys(classMappings).forEach(oldClass => {
const newClass = classMappings[oldClass];
// 使用单词边界确保只替换完整的class名称
const regex = new RegExp(`\\b${oldClass}\\b`, 'g');
newClassValues = newClassValues.replace(regex, newClass);
});
return `class="${newClassValues}"`;
});
const regex = /(<div\s+[^>]*class="[^"]*(testBo2|testBo)[^"]*"[^>]*>)(.*?)(<\/div>)/gis;
html = html.replace(regex, (match, startTag, className, content, endTag) => {
// 验证捕获的className
console.log('捕获的class名称:', className);
// 定义不同class对应的边框样式
let borderStyle;
if (className === 'testBo2') {
borderStyle = '3px solid #ffcc00'; // testBo的边框样式(深黄色)
} else if (className === 'testBo') {
borderStyle = '3px solid red'; // testBo2的边框样式(红色)
}
// 包裹div的完整样式
const wrapperStyle = `background:#fff;padding: 10px;border: ${borderStyle};border-radius: 8px;`;
// 包裹内容
const wrappedContent = `<div style='${wrapperStyle}'>${content}</div>`;
// 返回处理后的标签
return `${startTag}${wrappedContent}${endTag}`;
});
return html;
// const regex = /\s*class\s*=\s*"teshu"\s*/gi;
// const regex2 = /\s*class\s*=\s*"teshu2"\s*/gi;
// // 将匹配到的class替换为class="testBo"
// const styleRegex = /(<div[^>]*?)style\s*=\s*"[^"]*?"\s*([^>]*?class\s*=\s*"teshu"[^>]*?>)/gi;
// html_2 = html_2.replace(styleRegex, '$1$2');
// const styleRegex2 = /(<div[^>]*?)style\s*=\s*"[^"]*?"\s*([^>]*?class\s*=\s*"teshu2"[^>]*?>)/gi;
// html_2 = html_2.replace(styleRegex2, '$1$2');
// let html_3 = html_2.replace(regex, ' class="testBo"');
// let html_4 = html_3.replace(regex2, ' class="testBo2"');
// // let html_4 = html_3;
// // 正则表达式匹配class="testBo"的div标签
// // 匹配模式:<div class="testBo"[属性...]>内容</div>
// const regex1 = /(<div\s+class="testBo"[^>]*>)(.*?)(<\/div>)/gi;
// const regex22 = /(<div\s+class="testBo2"[^>]*>)(.*?)(<\/div>)/gi;
// // 替换匹配到的内容
// // 在原内容外层包裹<div style='background:#fff'>...</div>
// let processed = html_4.replace(regex22, (match, startTag, content, endTag) => {
// return `${startTag}<div style='background:#fff;padding: 10px;
// border: 3px solid #000;
// border-radius: 8px;
// '>${content}</div>${endTag}`;
// });
// console.log("预览数据processed",processed)
// let processedL = processed.replace(regex1, (match, startTag, content, endTag) => {
// return `${startTag}<div style='background:#fff;padding: 10px;
// border: 3px solid #000;
// border-radius: 8px;
// '>${content}</div>${endTag}`;
// });
// console.log("预览数据processedL",processedL)
// return processedL
},
//处理 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() {
if(this.editor){//初始化时候
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;
}else{
return true
}
},
//测试 启用右键功能
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;
const startX = e.clientX;
const startWidth = this.leftWidth;
const handleMouseMove = (e) => {
if (!this.isDragging) return;
const diffX = e.clientX - startX;
// 限制最小宽度
const newWidth = Math.max(100, startWidth + diffX);
// 限制最大宽度
this.leftWidth = Math.min(500, newWidth);
this.getWindowSize();
};
const handleMouseUp = () => {
this.isDragging = false;
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
e.preventDefault();
},
//测试 拖动图片
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'
}
},
//获取屏幕尺寸
getWindowSize() {
// this.windowW = window.innerWidth
// this.windowH = window.innerHeigh
// t
// this.leftHeight = window.innerHeight - 200;
// this.editorHeight = window.innerHeight - 250;
if(this.currentNode){
const element = document.querySelector('.w-e-toolbar')
const container = document.querySelector('.w-e-text-container');
const rightDivHeight = document.querySelector(".rightDiv").scrollHeight;
container.style.height = (rightDivHeight -element.scrollHeight - 80 ) +'px' ;
console.log("内容高度2", (rightDivHeight -element.scrollHeight - 80 ) +'px')
}
this.windowH = window.innerHeight;
this.leftHeight = window.innerHeight - 200; // 检查此值是否合理
this.editorHeight = window.innerHeight - 250;
// 强制刷新滚动条
this.$nextTick(() => {
const scrollbar = this.$refs.scrollbar; // 需给 el-scrollbar 添加 ref="scrollbar"
if (scrollbar) scrollbar.update();
});
},
// 尺寸变化时的处理函数
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");
console.log("得到的1",xmlDoc)
// 检查解析错误
const errorNode = xmlDoc.querySelector("parsererror");
console.log("得到的2",errorNode)
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(contentHtml.trim())
// 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://www.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"); // 月份09getMonth() 返回 8+1 后补 0
const day = String(date.getDate()).padStart(2, "0"); // 日期01
const hours = String(date.getHours()).padStart(2, "0"); // 小时1624小时制
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;
},
// 关闭修改书名弹窗
handleCloseEditBookName() {
this.getBookName = this.getBookNameDf;
this.editBookNameDialog = false;
},
//关闭弹窗节点
handleClose(type) {
this.loadFileDMC = '';
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) {
if(this.editor){
const html4 = this.editor.txt.html();
console.log("保存内容4",html4)
}
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.loadFileDMC = '';
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';
// targetNode.lagreVersion = this.currentNode.lagreVersion
const num = parseInt(this.currentNode.lagreVersion, 10);
// 3. 加1运算
const newNum = num + 1;
// 4. 格式化为3位带前导零的字符串
this.form.version = String(newNum).padStart(3, "0");
console.log("定稿时候逇form",this.form)
this.catalogueAnalysis(this.treeData);
this.generateXml(false);
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.loadFileDMC = '';
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 = '';
console.log("这一次点击的节点信息",data);
console.log("上一次点击的时候的ID",this.lastClick)
console.log("这一次点击的时候的ID",this.nowClick)
if(this.lastClick == this.nowClick.id){
this.currentNode = data;
this.nowClick = data;
this.lastClick = data.id;
}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{
this.currentNode = data;
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);
setTimeout(() => {
this.getWindowSize();
}, 30);
// this.$sendToDotNet('GetFilePath','PMC',data.id,'');
},
zy(dataStr) {
try {
// 1. 清理字符串
const cleaned = dataStr.replace(/;$/g, '');
// 2. 转义双引号
const escaped = cleaned.replace(/"/g, '\\"');
// 3. 解码 Unicode
let unicodeDecoded = JSON.parse(`"${escaped}"`);
// 4. 处理反斜杠
let a = unicodeDecoded.replace(/\\\\/g, "\\")
return a;
} catch (e) {
// 捕获解析错误,避免页面崩溃
console.error("字符串解析失败:", e);
return "解析错误";
}
},
//确认新建目录
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.currentNode = '';
this.catalogueAnalysis(this.treeData);
// this.$sendToDotNet('SaveFile','PMC',newNode.id,JSON.stringify(this.currentNode));
//创建目录时候同时创建一个空DM文件
console.log("创建目录时候同时创建一个空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)
// this.currentNode = null;
const fileId = this.currentNode.id;
this.catalogueAnalysis(this.treeData);
this.dialogVisibleNavDel = false;
// this.$sendToDotNet('RefreshTree');
console.log('删除RMDMfile fileId',fileId)
this.$sendToDotNet('RMDMfile','DMC',fileId,this.currentNode.lagreVersion)
this.currentNode = '';
// 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())
},
// 保存属性
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") : [];
let getBookName = xmlDoc.getElementsByTagName('pmTitle');
this.getBookName = getBookName[0].textContent;
console.log("得到的书名",this.getBookName)
// 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;
const issueInfoNode = xmlDoc.querySelector("issueInfo");
this.minLevel = issueInfoNode.getAttribute("minLevel")
this.maxLevel = issueInfoNode.getAttribute("maxLevel")
this.maxPermission = issueInfoNode.getAttribute("maxPermission")
this.minPermission = issueInfoNode.getAttribute("minPermission")
console.log("版本号上各种参数",this.minLevel,this.maxLevel,this.minPermission,this.maxPermission)
},
/**
* 递归解析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 a1 = this.form.permission;//2
let a2 = this.form.level;//2
// let minP = this.minPermission;//1
let maxP = this.maxPermission;//5
// let minL = this.minLevel;//1
let maxL = this.maxLevel;//5
if(a1>maxP){
maxP = a1;
}
if(a2>maxL){
maxL = a2;
}
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 minLevel="1" maxLevel="`+maxL+`" maxPermission="`+maxP+`" minPermission="1" issueNumber="000" inWork="01"/>
</pmIdent>
<pmAddressItems>
<issueDate year="2024" month="06" day="24"/>
<pmTitle>`+this.getBookName+`</pmTitle>
</pmAddressItems>
</pmAddress>
<pmStatus issueType="new">
<security securityClassification="01"/>
<responsiblePartnerCompany enterpriseCode=" "/>
<originator/>
<applic>
<displayText>
<simplePara maxId='`+this.mId+`'>A0304-1A无人机系统地面运输方舱</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);
// if(this.dialogVisibleNav){
// this.dialogVisibleNav = false;
// this.getDmName = this.domNameStr[0]+this.domNameStr[1]+this.domNameStr[2]+this.currentNode.id+this.domNameStr[3]+this.domNameStr[4];
// console.log("加载富文本的文件名997",this.getDmName)
// setTimeout(() => {
// this.loadFWBFile(this.getDmName);
// console.log("加载富文本的文件名997")
// }, 500);
// }
},
//测试 加载目录
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-1A无人机系统地面运输方舱</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:'1',
contributor:'',
creator:'四威高科',
applicabilityInformation:'',
qualityVerification:'',
permission:'1'
}
},
//测试 格式化目录信息
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(/&nbsp;/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'
});
},
//目录节点拖拽结束后
handleDragEnd() {
//拖拽完成后保存目录节点。
this.catalogueAnalysis(this.treeData)
},
// 处理节点右键点击
// 处理节点右键点击
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;
this.nowRightHint = data.name;
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 = '';
}
},
currentNode(newVal) {
if (newVal) {
this.$nextTick(() => {
// 先销毁旧编辑器
if (this.editor) {
this.editor.destroy();
}
// 初始化新编辑器
this.initEditor();
});
} else {
// 节点为空时销毁编辑器
if (this.editor) {
this.editor.destroy();
this.editor = null;
}
}
}
},
created() {
// let that = this;
// 方式1直接访问全局变量
this.$watch(
() => this.$dotNetMessage,
(newMsg) => {
console.log('收到消息:', newMsg)
}
)
//和后台交互 获取对应的DMC的历史版本列表
window.addEventListener('GetHistoryVesions', (e) => {
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', this.FrontLoadDM_g2)
//和后台交互 接收目录XML
// window.addEventListener('FrontLoadProjectNew', (e) => {
// })
//和后台交互 单独获取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)
let newData = this.zy(e.detail);
// 1. 去除双引号
const parsedA = this.lisenPath.replace(/"/g, '');
const parsedB = newData.replace(/"/g, '');
// 2. 处理转义字符(如斜杠)
const processedA = parsedA.replace(/\\/g, '');
// const processedB = parsedB.replace(/\\/g, '');
const processedB = parsedB.replace(/\\\\/g, "\\");
console.log("processedB",processedB,parsedB)
// 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('监听器开始注册11', 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)
this.isLoadMsg = true;
})
//和后台交互 定稿之后获取最新的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) => {
if(e){
this.viewLis = e.detail;
}
})
//和后台交互 获取加载时候的DMC文件具体内容
window.addEventListener('handreContent', (e) => {
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);
}
console.log("得到的0",this.viewXml)
this.parseRdfDescriptions(this.viewXml)
this.parseXmlDmc_loadFile();
}
})
// window.addEventListener('handleMessageFromDotNet', this.fun1)
},
}
</script>
<style scoped>
.drag-handle {
position: absolute;
top: 0;
right: 0;
width: 5px;
height: 100%;
cursor: col-resize;
/* background-color: #aaa; */
background-color: rgba(0,0,0,.1);
z-index: 2;
}
.drag-handle:hover {
/* background-color: #666; */
}
.el-main{
padding:0 10px ;
}
</style>