Files
structureplugins/jero-web/src/views/documentTool/documentComparison/DocumentDataComparison.vue
T

855 lines
27 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>
<internal-detail-page :title="$t('docTool.comparison.initiateDocumentComparison')"
:content-padding="0"
:loading="loading"
need-custom-back-func
@back="handleBack">
<template v-slot:titleRightCustom>
<a-button icon="upload"
type="primary"
ghost
style="margin-left: 6px"
@click="handleExportXls">
导出比对结果
</a-button>
</template>
<div class="can-scroll-content">
<div class="detail-content">
<!--左边的文档-->
<div class="detail-content-left">
<div class="detail-content-left-title">
<a-tooltip placement="topLeft">
<template #title>
<span>{{ $route.query.infoNumberLeft }} {{ $route.query.infoNameLeft }}</span>
</template>
<span>{{ $route.query.infoNumberLeft }} {{ $route.query.infoNameLeft }}</span>
</a-tooltip>
</div>
<!--左边的目录-->
<div class="standard-catalogue part-common" :class="{'hide-catalogue': !leftCatalogueShow}">
<!-- <div class="catalogue-show" @click="changeLeftCatalogueShow">-->
<!-- <a-icon :type="leftCatalogueShow ? 'left' : 'right'" />-->
<!-- </div>-->
<div class="part-title" v-show="leftCatalogueShow">{{ $t('standardRegulationLibrary.standardCatalogue') }}</div>
<div class="has-title-part-content" v-show="leftCatalogueShow">
<a-tree
class="draggable-tree"
:selected-keys="leftTreeSelectedKeys"
:replace-fields="{key: 'menuId'}"
@select="onSelectLeft"
:tree-data="resultData.menuLeft">
<a-icon slot="switcherIcon" type="down" :style="{ fontSize: '12px', color: '#103770' }" />
<template slot="title" slot-scope="{title}">
<!-- 目录前三个和有子集的标题加粗 -->
<span :style="title.indexOf('.')===-1?'font-weight: 600;':''">{{ title }}</span>
</template>
</a-tree>
</div>
</div>
<!--左侧标准信息-->
<div class="detail-content-left-container">
<!--标准名称-->
<div class="standard-name">
<a-tooltip placement="topLeft">
<template #title>
<span>{{ dataLeft.itemsNum ? dataLeft.itemsNum + dataLeft.itemsName : '' }}</span>
<span v-if="similarityDegree">相似度
<span>{{similarityDegree}}</span>
<span>{{textContent}}</span>
</span>
</template>
<span>{{ dataLeft.itemsNum ? dataLeft.itemsNum + dataLeft.itemsName : '' }}</span>
<span v-if="similarityDegree">相似度
<span style="color: red">{{similarityDegree}}</span>
<span>{{textContent}}</span>
</span>
</a-tooltip>
</div>
<div class="detail-content-left-scroll">
<div class="detail-content-left-item" @click="detailLeft(index,item)"
v-for="(item,index) in resultData.textLeft" :key="index"
:class="{'detail-content-item-selected': leftHighlightMenuId === item.menuId,'detail-content-item-saved':item.reviewed + '' === '1'}">
<div style="position: relative">
<div class="detail-content-item-text" style="margin-bottom: 10px;color: #040B29">
{{ item.itemsNum + ' ' + item.itemsName }}
</div>
<div class="detail-content-item-text" v-html="item.itemsText"></div>
<div @click="addViewRemark(item)" class="addRemarkBtn" v-show="!item.remark && !item.closeBtn">
<a-icon type="plus-circle" class="iconClass" /></div>
<div @click="addViewRemark(item)" class="addRemarkBtn" v-show="item.remark && !item.closeBtn">
<a-icon type="eye" class="iconClass"/></div>
<div @click="closeView(item)" class="addRemarkBtn" v-show="item.closeBtn">
<a-icon type="close-circle" class="iconClass"/></div>
</div>
<div v-if="item.addModalState" style="margin-top: 40px">
<a-textarea
v-model.trim="item.remark"
:maxlength="500"
placeholder="书写笔记"
:auto-size="{ minRows: 3, maxRows: 5 }"
/>
<div style="text-align: right;margin: 10px 0">
<a-button type="primary" @click="modalSave(item)">
提交
</a-button>
</div>
</div>
</div>
</div>
</div>
</div>
<!--右侧文档-->
<div class="detail-content-right">
<div class="detail-content-right-title">
<a-tooltip placement="topLeft">
<template #title>
<span>{{ $route.query.infoNumberRight }} {{ $route.query.infoNameRight }}</span>
</template>
<span>{{ $route.query.infoNumberRight }} {{ $route.query.infoNameRight }}</span>
</a-tooltip>
</div>
<!--右侧目录-->
<div class="standard-catalogue part-common" :class="{'hide-catalogue': !rightCatalogueShow}">
<!-- <div class="catalogue-show" @click="changeRightCatalogueShow">-->
<!-- <a-icon :type="rightCatalogueShow ? 'left' : 'right'" />-->
<!-- </div>-->
<div class="part-title" v-show="rightCatalogueShow">{{ $t('standardRegulationLibrary.standardCatalogue') }}</div>
<div class="has-title-part-content" v-show="rightCatalogueShow">
<a-tree
class="draggable-tree"
:selected-keys="rightTreeSelectedKeys"
:replace-fields="{key: 'menuId'}"
@select="onSelectRight"
:tree-data="resultData.menuRight">
<a-icon slot="switcherIcon" type="down" :style="{ fontSize: '12px', color: '#103770' }" />
<template slot="title" slot-scope="{title}">
<!-- 目录前三个和有子集的标题加粗 -->
<span :style="title.indexOf('.')===-1?'font-weight: 600;':''">{{ title }}</span>
</template>
</a-tree>
</div>
</div>
<!--右侧标准信息-->
<div class="detail-content-right-container">
<!--标准名称-->
<div class="standard-name">
<a-tooltip placement="topLeft">
<template #title>
<span>{{ dataRight.itemsNum ? dataRight.itemsNum + dataRight.itemsName : '' }}</span>
<span v-if="similarityDegree">相似度
<span>{{similarityDegree}}</span>
<span>{{textContent}}</span>
</span>
</template>
<span>{{ dataRight.itemsNum ? dataRight.itemsNum + dataRight.itemsName : '' }}</span>
<span v-if="similarityDegree">相似度
<span style="color: red">{{similarityDegree}}</span>
<span>{{textContent}}</span>
</span>
</a-tooltip>
</div>
<div class="detail-content-right-scroll">
<div class="detail-content-right-item" @click="detailRight(index,item)"
v-for="(item,index) in resultData.textRight" :key="index"
:class="{'detail-content-item-selected': item.menuId === rightHighlightMenuId, 'detail-content-item-saved':item.reviewed + '' === '1'}">
<div style="position: relative">
<div class="detail-content-item-text" style="margin-bottom: 10px;color: #040B29">
{{ item.itemsNum + ' ' + item.itemsName }}
</div>
<div class="detail-content-item-text" v-html="item.itemsText">
</div>
<div @click="addViewRemark(item)" class="addRemarkBtn" v-show="!item.remark && !item.closeBtn">
<a-icon type="plus-circle" class="iconClass" /></div>
<div @click="addViewRemark(item)" class="addRemarkBtn" v-show="item.remark && !item.closeBtn">
<a-icon type="eye" class="iconClass"/></div>
<div @click="closeView(item)" class="addRemarkBtn" v-show="item.closeBtn">
<a-icon type="close-circle" class="iconClass"/></div>
</div>
<div v-if="item.addModalState" style="margin-top: 40px">
<a-textarea
v-model.trim="item.remark"
:maxlength="500"
placeholder="书写笔记"
:auto-size="{ minRows: 3, maxRows: 5 }"
/>
<div style="text-align: right;margin: 10px 0">
<a-button type="primary" @click="modalSave(item)">
提交
</a-button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</internal-detail-page>
</template>
<script>
// 添加全文评论弹框
import InternalDetailPage from '../../../components/InternalDetailPage.vue'
import { getComparisonDetail, clauseComparison } from '../../../api/documentToolApi.js'
import { downFile, postAction } from '../../../api/manage'
export default {
name: 'DocumentDataComparison',
components: { InternalDetailPage },
data () {
return {
formInline: {},
loadingText: false,
rules: {},
loading: false,
resultData: {},
isMatching: true, // 自动匹配是否开启
dataLeft: {},
dataRight: {},
pageFrom: null,
leftCatalogueShow: true, // 左侧的标准目录是否展示
rightCatalogueShow: true, // 右侧的标准目录是否展示
leftTreeSelectedKeys: [], // 左侧被选中树节点
rightTreeSelectedKeys: [], // 右侧被选中树节点
leftHighlightMenuId: null, // 左侧高亮数据的menuId
rightHighlightMenuId: null, // 右侧高亮数据的menuId
similarityDegree: '',
textContent: '',
itemLeftIndex: '',
itemRightIndex: ''
}
},
watch: {
itemRightIndex: {
deep: true,
handler (newVal, oldVal) {
if (oldVal !== '') {
this.resultData.textRight[oldVal].addModalState = false
this.resultData.textRight[oldVal].closeBtn = false
}
}
},
itemLeftIndex: {
deep: true,
handler (newVal, oldVal) {
if (oldVal !== '') {
this.resultData.textLeft[oldVal].addModalState = false
this.resultData.textLeft[oldVal].closeBtn = false
}
}
}
},
mounted () {
this.getData()
},
methods: {
// 获取文件对比详情
getData () {
const query = {
id: this.$route.query.id
}
this.loading = true
getComparisonDetail(query).then((res) => {
if (res.success) {
this.resultData = res.result || {}
} else {
this.resultData = {}
}
}).finally(() => {
this.loading = false
})
},
// 点击左侧文档内容
detailLeft (num, item) {
this.leftTreeSelectedKeys = [item.menuId]
this.similarityDegree = ''
this.textContent = ''
this.itemLeftIndex = num
if (item.id === this.dataLeft.id && !this.isMatching) {
this.dataLeft = {}
this.leftHighlightMenuId = null
return
}
this.leftHighlightMenuId = item.menuId
this.dataLeft = item
this.dataLeft.numIndex = num
// 自动匹配,右侧数据需要跳转
if (this.isMatching) {
const index = this.dataLeft.targetStand
if (index > -1) {
this.dataRight = this.resultData.textRight[index]
this.dataRight.numIndex = index
this.rightHighlightMenuId = this.dataRight.menuId
this.rightTreeSelectedKeys = [this.dataRight.menuId]
this.handleJumpRightData(index)
this.clauseComparison()
} else {
this.rightHighlightMenuId = ''
this.dataRight = {}
this.resultData = { ...this.resultData }
}
}
},
// 点击右侧文档内容
detailRight (num, item) {
this.rightTreeSelectedKeys = [item.menuId]
this.similarityDegree = ''
this.textContent = ''
this.itemRightIndex = num
if (item.id === this.dataRight.id && !this.isMatching) {
this.dataRight = {}
this.rightHighlightMenuId = null
return
}
this.dataRight = item
this.dataRight.numIndex = num
this.rightHighlightMenuId = item.menuId
if (this.isMatching) {
const index = this.dataRight.targetStand
if (index > -1) {
this.dataLeft = this.resultData.textLeft[index]
this.dataLeft.numIndex = index
this.leftHighlightMenuId = this.dataLeft.menuId
this.leftTreeSelectedKeys = [this.dataLeft.menuId]
this.handleJumpLeftData(index)
this.clauseComparison()
} else {
this.dataLeft = {}
this.leftHighlightMenuId = ''
this.resultData = { ...this.resultData }
}
}
},
// 自动匹配
clauseComparison () {
const query = {
leftId: this.dataLeft.id,
rightId: this.dataRight.id
}
this.loading = true
clauseComparison(query).then((res) => {
if (res.success) {
this.loading = false
this.resultData.textLeft[this.dataLeft.numIndex].itemsText = res.result.htmlDiffStr[0]
this.resultData.textRight[this.dataRight.numIndex].itemsText = res.result.htmlDiffStr[1]
this.similarityDegree = res.result.similarityDegree
if (parseFloat(res.result.similarityDegree) < parseFloat('75%')) {
this.textContent = '不相似'
} else if (parseFloat(res.result.similarityDegree) >= parseFloat('75%') && parseFloat(res.result.similarityDegree) !== parseFloat('100%')) {
this.textContent = '相似'
} else if (parseFloat(res.result.similarityDegree) === parseFloat('100%')) {
this.textContent = '相同'
}
} else {
this.loading = false
}
})
},
// 左侧树选择
onSelectLeft (selectedKeys, exports) {
const node = exports.node.$vnode.data.props.dataRef
const index = this.resultData.textLeft.findIndex(tt => tt.menuId === node.menuId)
this.dataLeft = this.resultData.textLeft[index]
this.dataLeft.numIndex = index
this.itemLeftIndex = index
this.leftHighlightMenuId = this.dataLeft.menuId
this.leftTreeSelectedKeys = [this.dataLeft.menuId]
this.handleJumpLeftData(index)
// 处理选中右侧树
if (this.isMatching) {
const indexRight = this.dataLeft.targetStand
if (indexRight > -1) {
this.dataRight = this.resultData.textRight[indexRight]
this.dataRight.numIndex = indexRight
this.rightHighlightMenuId = this.dataRight.menuId
this.rightTreeSelectedKeys = [this.dataRight.menuId]
this.handleJumpRightData(indexRight)
this.clauseComparison()
} else {
this.rightHighlightMenuId = ''
this.dataRight = {}
this.resultData = { ...this.resultData }
}
}
},
// 右侧树选中
onSelectRight (selectedKeys, exports) {
const node = exports.node.$vnode.data.props.dataRef
const index = this.resultData.textRight.findIndex(tt => tt.menuId === node.menuId)
this.dataRight = this.resultData.textRight[index]
this.dataRight.numIndex = index
this.itemRightIndex = index
this.rightHighlightMenuId = this.dataRight.menuId
this.rightTreeSelectedKeys = [this.dataRight.menuId]
this.handleJumpRightData(index)
// 处理选中左侧树
if (this.isMatching) {
const indexLeft = this.dataRight.targetStand
if (indexLeft > -1) {
this.dataLeft = this.resultData.textLeft[indexLeft]
this.dataLeft.numIndex = indexLeft
this.leftHighlightMenuId = this.dataLeft.menuId
this.leftTreeSelectedKeys = [this.dataLeft.menuId]
this.handleJumpLeftData(indexLeft)
this.clauseComparison()
} else {
this.dataLeft = {}
this.leftHighlightMenuId = ''
this.resultData = { ...this.resultData }
}
}
},
/**
* 左侧数据跳转
*/
handleJumpLeftData (index) {
if (index > -1) {
const scrollContent = document.getElementsByClassName('detail-content-left-scroll')
const clauseItemDom = document.getElementsByClassName('detail-content-left-item')
scrollContent[0].scrollTop = clauseItemDom[index].offsetTop - 175
}
},
/**
* 右侧数据跳转
*/
handleJumpRightData (index) {
if (index > -1) {
const detailContent = document.getElementsByClassName('detail-content-right-scroll')
const detailRight = document.getElementsByClassName('detail-content-right-item')
detailContent[0].scrollTop = detailRight[index].offsetTop - 175
}
},
handleBack () {
this.$router.push({
path: '/documentTool/documentComparison'
})
},
changeLeftCatalogueShow () {
this.leftCatalogueShow = !this.leftCatalogueShow
},
changeRightCatalogueShow () {
this.rightCatalogueShow = !this.rightCatalogueShow
},
// 添加笔记
addViewRemark (item) {
item.addModalState = true
item.closeBtn = true
},
closeView (item) {
// if (item.remark !== item.oldRemark) {
// this.$confirm({
// title: '提示',
// content: '<p>笔记内容有修改,是否保存?</p>',
// onOk: () => {
// this.modalSave(item)
// item.closeBtn = false
// item.addModalState = false
// },
// onCancel: () => {
// item.closeBtn = false
// item.addModalState = false
// }
// })
// } else {
item.closeBtn = false
item.addModalState = false
// }
},
handleExportXls () {
const fileName = this.$route.query.infoNumberLeft + ' - ' + this.$route.query.infoNumberRight + '比对结果'
const fileSuffix = '.xls'
const param = {}
param.id = this.$route.query.id
param.exportName = fileName + fileSuffix
// 加一个大的提示
const modalLoading = this.$info({
title: this.$t('tips'),
content: <span>{this.$t('exportTip')}
<a-spin size="small" /></span>,
keyboard: false
})
// 把知道了这个按钮去掉
this.$nextTick(() => {
document.getElementsByClassName('ant-modal-confirm-btns')[0].style = 'display:none'
})
downFile('/compare/sarFileCompareInfo/exportFullTextCompareXls', param).then((data) => {
if (!data) {
this.$message.warning(this.$t('fileDownloadFail'))
return
}
if (typeof window.navigator.msSaveBlob !== 'undefined') {
window.navigator.msSaveBlob(new Blob([data], { type: 'application/vnd.ms-excel' }), fileName + fileSuffix)
} else {
const url = window.URL.createObjectURL(new Blob([data], { type: 'application/vnd.ms-excel' }))
const link = document.createElement('a')
link.style.display = 'none'
link.href = url
link.setAttribute('download', fileName + fileSuffix)
document.body.appendChild(link)
link.click()
document.body.removeChild(link) // 下载完成移除元素
window.URL.revokeObjectURL(url) // 释放掉blob对象
}
}).finally(() => {
// 销毁这个提示
modalLoading.destroy()
})
},
modalSave (item) {
const query = {
remark: item.remark,
id: item.id
}
postAction('/compare/sarFileCompareItem/edit', query).then((res) => {
item.oldRemark = item.remark
if (res.success) {
this.$message.success(res.message)
} else {
this.$message.warning(res.message)
}
})
}
}
}
</script>
<style scoped lang="less">
.header-btn {
margin-left: 12px;
}
.header-btn:first-child {
margin-left: 0;
}
.can-scroll-content {
height: 100%;
overflow: auto;
}
.detail-content {
height: 100%;
background-color: #eff1f4;
}
.detail-content-left {
width: 50%;
float: left;
height: 100%;
border-right: 2px #EFF1F3 solid;
box-sizing: border-box;
border-bottom: 2px #EFF1F3 solid;
/*display: flex;*/
}
.detail-content-right {
width: 50%;
height: 100%;
float: left;
box-sizing: border-box;
border-bottom: 2px #EFF1F3 solid;
/*display: flex;*/
}
.detail-content-left-header {
width: 100%;
font-size: 16px;
font-family: Blue Sky Noto;
font-weight: 400;
color: #040B29;
margin-bottom: 24px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.box-title-text-remarks {
line-height: 1.4;
display: flex;
/*align-items: center;*/
margin-bottom: 10px;
}
.item-model {
width: calc(100% - 232px);
}
.title-text-remarks {
width: 68px;
color: #000F16;
display: inline-block;
font-weight: 500;
font-size: 14px;
margin-right: 16px;
margin-top: 6px;
text-align: right;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.box-button {
height: 38px;
/*margin-top: 2px;*/
}
.remarks {
margin-top: 20px;
width: 50%;
display: inline-block;
padding: 0 32px;
box-sizing: border-box;
}
.itemModel {
width: calc(100% - 232px);
}
.submit-button {
height: 52px;
text-align: right;
padding: 10px 24px;
}
.detail-content-left-container {
height: calc(100% - 65px);
width: calc(100% - 201px);
display: inline-block;
overflow-y: auto;
transition: all 1s;
border-radius: 4px;
scroll-behavior: smooth;
flex: 1;
}
.detail-content-right-container {
height: calc(100% - 65px);
width: calc(100% - 201px);
overflow-y: auto;
display: inline-block;
transition: all 1s;
scroll-behavior: smooth;
flex: 1;
.standard-name {
margin-right: 0;
}
}
.detail-content-left-scroll {
height: calc(100% - 25px - 40px);
width: calc(100% - 20px);
display: inline-block;
margin: 0 10px 0 10px;
overflow: auto;
background-color: white;
border-radius: 7px;
}
.detail-content-right-scroll {
height: calc(100% - 25px - 40px);
width: calc(100% - 10px);
display: inline-block;
margin-left: 10px;
overflow: auto;
border-radius: 7px;
background-color: white;
}
.detail-content-left-item {
padding: 16px 20px 28px 20px;
box-sizing: border-box;
border: 1px solid #EFF1F3;
cursor: pointer;
background-color: white;
position: relative;
}
.detail-content-right-item {
padding: 16px 20px 28px 20px;
box-sizing: border-box;
border: 1px solid #EFF1F3;
cursor: pointer;
background-color: white;
position: relative;
}
.detail-content-left-item:last-child {
margin-bottom: 0;
}
.detail-content-item-text {
font-size: 16px;
font-weight: 400;
color: #040B29;
word-break: break-word;
/deep/ table {
width: 100%;
}
/deep/ img {
max-width: 100%;
}
}
.detail-content-item-selected {
border: 2px red solid !important;
}
.detail-content-item-saved {
border: 2px #21c9cc solid;
}
::v-deep .delClass {
color: #ff7168;
}
::v-deep .insertClass {
color: green;
}
/deep/ .ant-tree li span.ant-tree-switcher {
float: right;
}
::-webkit-scrollbar {
width: 3px;
}
.part-common {
border-radius: 8px;
background: #FFFFFF;
}
.standard-catalogue {
height: calc(100% - 83px);
width: 200px;
overflow: auto;
display: inline-block;
margin: 10px 0 10px 0;
position: relative;
transition: width .2s linear;
/deep/ .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
background-color: transparent !important;
color: @primary-color;
}
.catalogue-show {
position: absolute;
width: 12px;
height: 24px;
left: 100%;
top: 50%;
transform: translateY(-50%);
background-color: @primary-color;
border-radius: 0 12px 12px 0;
cursor: pointer;
color: white;
.anticon {
left: -2px;
position: absolute;
top: 50%;
transform: translateY(-50%);
}
}
}
.hide-catalogue {
width: 0;
min-width: 0;
}
.part-title {
height: 40px;
background: rgba(213, 44, 38, 0.12);
border-radius: 8px 8px 0 0;
line-height: 40px;
padding: 0 24px;
font-size: 16px;
font-family: PingFang SC-Semibold, PingFang SC, sans-serif;
font-weight: 600;
color: #1D2129;
white-space: nowrap;
overflow: hidden;
}
.has-title-part-content {
height: calc(100% - 40px);
overflow: auto;
padding: 0 20px;
}
.standard-name {
margin: 10px 10px 5px 10px;
height: 40px;
background: #FFFFFF;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
}
.standard-name > span {
font-size: 16px;
font-family: PingFang SC-Semibold, PingFang SC, sans-serif;
font-weight: 500;
color: #1D2129;
flex: 1;
width: 0;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
.detail-content-left-title {
height: 50px;
width: calc(100% - 12px);
background: #fff;
margin-top: 8px;
border-radius: 4px;
line-height: 50px;
padding: 0 10px;
box-sizing: border-box;
font-size: 14px;
font-family: PingFang SC-Semibold, PingFang SC, sans-serif;
font-weight: 600;
color: #1D2129;
}
.detail-content-right-title{
height: 50px;
width: calc(100% - 2px);
background: #fff;
margin-top: 8px;
border-radius: 4px;
line-height: 50px;
padding: 0 10px;
box-sizing: border-box;
font-size: 14px;
font-family: PingFang SC-Semibold, PingFang SC, sans-serif;
font-weight: 600;
color: #1D2129;
}
.detail-content-button{
text-align: right;
padding-right: 16px;
}
.addRemarkBtn{
position: absolute;
bottom: -26px;
right: 0;
/*z-index: 10;*/
}
.iconClass{
font-size: 19px;
}
</style>