123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- <template>
- <div class="semantics-edit-page">
- <div class="semantics-tool page-block-wrap">
- <div class="tool-btn" @click="handleBtnClick({type:'search'})">
- <img :src="toolIcon['search']" />
- 搜索
- </div>
- <div class="tool-btns">
- <el-popover
- placement="right"
- v-model="isSelectLabelShow"
- v-if="compareFiles.length"
- trigger="manual">
- <select-label-detail
- :isSelectLabelShow="isSelectLabelShow"
- :lastSelectLabelArr="selectedLabelArr"
- :selectedFileArr="selectedFileArr"
- :newAddLabelArr="newAddLabelArr"
- @close="handleSelectLabel"
- />
- <div slot="reference" class="tool-btn" style="padding:0 30px !important;border-right: 1px solid #DCDFE6;"
- @click="handleBtnClick({type:'selectLabel'},isSelectLabelShow?'close':'open')">
- <img :src="toolIcon['eye']" style="width:14px,height:9px"/>
- 选择标签
- </div>
- </el-popover>
-
- <div class="tool-btn" v-for="btn in toolBtnArr" :key="btn.type" @click="handleBtnClick(btn)">
- <img :src="toolIcon[btn.icon]" :style="btn.icon==='eye'?{'width':'14px','height':'9px'}:{}"/>
- {{btn.text}}
- </div>
- </div>
- </div>
- <div class="semantics-content" v-if="compareFiles.length">
- <div class="file-page-label-wrap">
- <draggable
- class="drag-cont"
- v-model="compareFiles"
- animation="300"
- @start="dragStartHandler"
- @update="dragEnter"
- @end="movePageLabel"
- >
- <div class="page-label" :class="{'active':currentPageIndex===index}"
- v-for="(label,index) in compareFiles" :key="label.DocId"
- @click="changePageLabel(index)"
- >
- <span class="text-ellipsis">{{label.Title}}</span>
- <span class="close" @click.stop="deleteCompareFile(label,index)"><i class="el-icon-close"></i></span>
- </div>
- </draggable>
-
- </div>
- <div class="files">
- <div class="file-item overflow-hide-scrollbar"
- @scroll="hideTextAreaTool('scroll',document)"
- :class="{'couple':showingFiles.length===2||showingFiles.length===1}"
- v-for="(document,index) in showingFiles" :key="document.DocId">
- <div class="file-item-info">
- <p class="file-title">{{document.Title}}</p>
- <p class="file-sub-info"><!-- <span style="margin-right:30px;">{{document.Theme}}</span> --><span>所属目录:{{document.ClassifyName}}</span></p>
- <!-- <span class="close-btn" @click.stop="deleteCompareFile(document,index)"><i class="el-icon-circle-close"></i></span> -->
- </div>
- <div class="file-item-content" :id="`file-content-${index}`"
- v-click-outside="hideTextAreaTool"
- @mouseup.stop="e=>{handleMouseUp(e,index)}">
- <div class="file-item-block" :class="{'this-block':block.ishasThisLabel,'select-block':block.isSelectLabel}"
- v-for="block in document.SectionList" :key="block.SectionId"
- >
- <!-- @mousemove="e=>checkTextArea(e,document)" -->
- <p class="block-innerText" :id="block.SectionId">{{block.innerText}}</p>
- <div class="file-item-icon">
- <el-popover
- placement="right"
- trigger="hover">
- <section-label-detail
- :detailArr="[
- {title:'当前标签',isThis:1,arr:block.isThisLabelArr||[]},
- {title:'历史标签(我的)',isThis:0,arr:block.isHistoryLabelArr||[]},
- {title:'Ta的标签',isThis:0,arr:block.isOtherLabelArr||[]},
- ]"
- @deleteLab="(label)=>{deleteSelectLabel(document,block,label)}"
- @addLab="(label)=>{quickAddSelectLabel(document,block,label)}"
- />
- <span slot="reference" @click.stop><img :src="require(`@/assets/img/document_m/menu.svg`)"></span>
- </el-popover>
- <span class="label" @click.stop="handleAddSelectionLabel(document,block)"><img :src="require(`@/assets/img/document_m/label.svg`)"></span>
- </div>
-
- </div>
- <!-- 高亮方案的兼容版本
- <highlight-canvas
- ref="HighlightCanvas"
- :parentDomId="`file-content-${index}`"
- :parentIndex="index"/> -->
- </div>
- </div>
- </div>
- </div>
- <div class="semantics-content" v-if="compareFiles.length===0">
- <tableNoData text="暂无信息" class="empty"/>
- </div>
- <!-- 选择对比文档弹窗 -->
- <select-file-dialog
- :isSelectFileShow="isSelectFileShow"
- :selectedFileArr="selectedFileArr"
- @selectFile="AddCompareFiles"
- @close="handleBtnClick({type:'selectFile'},'close')"
- />
- <!-- 打标签弹窗 -->
- <add-section-label-dialog
- :isAddSectionLabelShow="isAddSectionLabelShow"
- :sectionInfo="sectionInfo"
- @addSection="addSectionLabel"
- @close="handleBtnClick({type:'addSectionLabel'},'close')"
- />
- <!-- 搜索框弹窗 -->
- <search-box
- ref="searchBox"
- :isSearchBoxShow="isSearchBoxShow"
- @close="handleBtnClick({type:'search'},'close')"
- />
- <!-- 保存/另存为+上传图片弹窗 -->
- <save-semantic-dialog
- ref="saveDialog"
- :isSaveFileShow="isSaveFileShow"
- :semanticInfo="semanticInfo"
- :saveType="saveType"
- :resultData="resultData"
- :dialogLoading="dialogLoading"
- @saveSemantic="saveSemantic"
- @uploadImg="uploadImg"
- @close="checkSemanticId"
- />
- <!-- 选定文字操作栏 -->
- <select-text-area-tool
- v-show="isShowTextArea"
- ref="SelectTextAreaTool"
- :isShowTextArea="isShowTextArea"
- :positionInfo="positionInfo"
- :textAreaInfo="textAreaInfo"
- :currentTextArea="currentTextArea"
- @addTextAreaLabel="addTextAreaLabel"
- @quickAddTextAreaLabel="quickAddTextAreaLabel"
- @deleteTextAreaLabel="deleteTextAreaLabel"
- />
- </div>
- </template>
- <script>
- /* js */
- import {toolIcon,toolBtnArr,dialogMap,textAreaToolWidth} from '../utils/config';
- import {formatSemanticFile,formatCompareListItem,
- checkSelectionAndRange,getCurrentRange,
- getTextRange,updateLabelList,
- addNewTextRange,checkIsSelectLabelInFile,
- checkAllLabelsAreEmpty} from '../utils/index';
- /*components */
- import draggable from 'vuedraggable';
- import selectFileDialog from './components/selectFileDialog.vue';
- import AddSectionLabelDialog from './components/addSectionLabelDialog.vue';
- import SectionLabelDetail from './components/sectionLabelDetail.vue';
- import SelectLabelDetail from './components/selectLabelDetail.vue';
- import SaveSemanticDialog from './components/saveSemanticDialog.vue';
- import SearchBox from './components/searchBox.vue';
- import HighlightCanvas from './components/highlightCanvas.vue';
- import SelectTextAreaTool from './components/selectTextAreaTool.vue';
- /* api */
- import {semanticInterface} from '@/api/modules/semanticsApi.js';
- export default {
- components: {
- draggable,selectFileDialog, AddSectionLabelDialog,
- SectionLabelDetail, SelectLabelDetail, SaveSemanticDialog,
- SearchBox,HighlightCanvas, SelectTextAreaTool
- },
- directives: {
- 'click-outside':{
- bind(el, binding) {
- const clickHandle = (e)=>{
- //点击file-item-content之外的地方,隐藏选定文字操作栏
- const legalClassNameArr = ['file-item-content','block-innerText','select-text-area-tool']
- const SelectTextAreaTool = document.querySelector('.select-text-area-tool')
- if(el.contains(e.target)||legalClassNameArr.includes(e.target.className)||SelectTextAreaTool.contains(e.target)){
- return false
- }
- if(binding.value && typeof binding.value === 'function'){
- binding.value(_,_,e)
- }
- }
- el.__click__outside = clickHandle
- document.addEventListener('click',clickHandle)
- },
- unbind(el,binding,vnode){
- document.removeEventListener('click',el.__click__outside)
- }
- },
- },
- data() {
- return {
- /* button 页面操作按钮相关*/
- toolIcon:toolIcon,//操作栏
- selectedLabelArr:[],//选择标签-已选择的标签
- /* document-files 文档相关*/
- selectedFileArr:[],//已选择的文档ids
- compareFiles:[],//对比的文档
- showingFiles:[],//展示在可视区的文档 是compareFiles中的其中三个
- /* block and block-label 段落及段落标签相关*/
- newAddLabelArr:[],//当前页(段落)新打的标签
- sectionInfo:{},//当前选择的段落
- /* page-label 标签页 */
- currentPageIndex:0,//当前选择的标签页,与showingFiles[0]对应
- dragStartIndex:0,//拖拽标签页的标识
- /* semantic 文档对比信息 */
- semanticId:0,//文档对比id,为0时是新增
- saveType:0,//0 另存为 1保存
- resultData:{},//文档对比保存的结果,用于生成预览图片
- semanticInfo:{},//语义分析信息
- /* textArea text-label 选定文字及选定文字标签 */
- blockInfo:{SectionId:'',DocId:''},//选定文字时,选区所属的段落信息,为document.SectionList的其中一项
- positionInfo:{top:0,left:0},//选定文字时,操作栏应展示的位置
- textAreaInfo:[],//选定文字时,该选定文字区域信息
- currentTextArea:{},//当前选择的textArea textAreaInfo中的某一项
- isShowTextArea:false,//控制选定文字操作栏展示
- /* dialog */
- isSearchBoxShow:false,//搜索框弹窗
- isSelectLabelShow:false,//全部标签弹窗
- isSelectFileShow:false,//选择对比文档弹窗
- isSaveFileShow:false,//保存弹窗
- isAddSectionLabelShow:false,//打标签弹窗
- dialogLoading:false,//保存弹窗用的
- };
- },
- computed:{
- toolBtnArr(){//操作栏
- //新增
- if(this.semanticId===0){
- return this.compareFiles.length?toolBtnArr.slice(0,-1):[toolBtnArr[0]]
- }else{
- //编辑
- return toolBtnArr
- }
- },
- },
- methods: {
- //获取语义分析详情
- getSemanticData(){
- const {fileId} = this.$route.query
- if(fileId&&Number(fileId.split('_')[1])){
- this.semanticId = Number(fileId.split('_')[1])
- semanticInterface.getSemanticDetail({
- CompareId:this.semanticId
- }).then(res=>{
- if(res.Ret!==200) return
- this.initSemantic(res.Data)
- })
- }else{
- this.semanticId = 0
- this.semanticInfo = {
- SaCompareId:this.semanticId,
- Title:'',
- ClassifyId:''
- }
- }
- },
- //初始化语义分析
- initSemantic(data){
- const {SaCompareId,Title,ClassifyId,KeywordsList} = data
- this.semanticInfo = {SaCompareId,Title,ClassifyId}
- const {DocList} = data
- //初始化 selectedFileArr
- this.selectedFileArr = DocList.map(doc=>{
- return doc.DocId
- })
- //初始化 compareFiles
- this.compareFiles = DocList?DocList.map(doc=>{
- doc = formatSemanticFile(doc,this.selectedLabelArr)
- return doc
- }):[]
- //初始化 showingFiles
- this.initShowingFiles()
- //初始化搜索词
- if(KeywordsList.length){
- this.$refs.searchBox.searchArr = KeywordsList
- }
- },
- //点击工具栏按钮
- handleBtnClick(btn,operate='open'){
- const {type} = btn
- this.saveType = type==='saveOther'?0:1
- this[dialogMap[type]] = operate==='open'?true:false
- if(operate==='close'){
- this.dialogLoading = false
- }
- },
- /* 移动标签相关 */
- dragStartHandler({oldIndex}){
- //console.log('start',oldIndex)
- this.currentPageIndex = oldIndex
- this.dragStartIndex = oldIndex
- },
- //拖动后 compareFiles的顺序也会改变
- dragEnter({newIndex}){},
- movePageLabel({newIndex}){
- //console.log('end',newIndex)
- if(this.dragStartIndex===newIndex) return
- //切换标签
- this.changePageLabel(newIndex)
- },
- /*--------- */
- //切换文档标签页
- changePageLabel(index){
- //切换当前标签索引
- this.currentPageIndex = index
- //标签视口宽度
- const dragContWidth = $('.drag-cont').width()
- //单个标签宽度()
- const pageLabelWidth = $('.page-label').outerWidth()
- //标签总宽度(包括不可见部分)
- const pageLabelTotalWidth = pageLabelWidth*this.compareFiles.length
- //当前偏移位置
- const dragMarginLeft = Number($('.drag-cont').css('marginLeft').slice(0,-2))
- //当前选择标签在drag-cont的位置(加上偏移修正)
- const currentPosition = pageLabelWidth*index+dragMarginLeft
- //如果当前选择标签的前后三个不在视口,则移动确保这7个标签在视口处
- const safeWidth = pageLabelWidth*3
- //currentPosition>dragContWidth-safeWidth marginLeft为负
- const minusMargin = (currentPosition>(dragContWidth-safeWidth))
- //currentPosition<pageLabelWidth*2 marginLeft为正
- const plusMargin = (currentPosition<safeWidth)
- //但|marginLeft|+dragContWidth<=pageLabelTotalWidth
- const isMove = (dragContWidth<pageLabelTotalWidth)&&(minusMargin||plusMargin)
- //打印只是为了调试
- /* console.table([{
- 'pageIndex':index,
- 'dragContWidth':dragContWidth,
- 'pageLabelWidth':pageLabelWidth,
- 'pageLabelTotalWidth':pageLabelTotalWidth,
- 'dragMarginLeft':dragMarginLeft,
- 'currentPosition':currentPosition,
- 'minusMargin':minusMargin,
- 'plusMargin':plusMargin,
- }]) */
- if(isMove){
- let isLimit = pageLabelWidth*3+dragContWidth+Math.abs(dragMarginLeft)>=pageLabelTotalWidth
- let marginLeft = minusMargin&&isLimit?pageLabelTotalWidth-dragContWidth:pageLabelWidth*3
- const indexLimit = this.compareFiles.length<=10||index<3
- marginLeft = (plusMargin&&isLimit)||indexLimit?0:pageLabelWidth*3
- marginLeft = minusMargin?marginLeft*-1:marginLeft
- //console.log('isLimit',isLimit)
- //console.log('move',marginLeft)
- $('.drag-cont').css('marginLeft',isLimit?marginLeft:(marginLeft+dragMarginLeft))
- }
- //更新视口文档
- this.initShowingFiles()
- },
- //初始化展示视口文档
- initShowingFiles(){
- //切换前先关掉搜索框
- this.handleBtnClick({type:'search'},'close')
- //showingFiles为currentPageIndex,currentPageIndex+1,currentPageIndex+2的三个文档
- const currentPageIndex = this.currentPageIndex
- if(this.compareFiles.length===0){
- this.showingFiles = []
- return
- }
- //判断currentPageIndex+1,currentPageIndex+2是否越界
- if(currentPageIndex===this.compareFiles.length-1){
- this.showingFiles = [this.compareFiles[currentPageIndex]]
- }else if(currentPageIndex===this.compareFiles.length-2){
- this.showingFiles = [this.compareFiles[currentPageIndex],this.compareFiles[currentPageIndex+1]]
- }else{
- this.showingFiles = [this.compareFiles[currentPageIndex],this.compareFiles[currentPageIndex+1],this.compareFiles[currentPageIndex+2]]
- }
-
- this.$nextTick(()=>{
- //初始化showingFiles中选定文字标签
- const textAreaRange = []
- const ortherTextAreaRange = []
- this.showingFiles.forEach(file=>{
- if(file.textAreaList){
- file.textAreaList = file.textAreaList.map(text=>{
- const {rangeInfo,range} = getTextRange(text)
- text.areaRangeInfo = rangeInfo
- if(text.ishasThisLabel){
- textAreaRange.push(range)
- }
- if(text.isSelectLabel){
- ortherTextAreaRange.push(range)
- }
- return text
- })
- }
- })
- this.$nextTick(()=>{
- if(!CSS.highlights){
- this.$message.warning('该浏览器不支持高亮效果,请切换至chrome浏览器105版本以上')
- return
- }
- CSS.highlights&&CSS.highlights.set('show-result',new Highlight(...textAreaRange))
- CSS.highlights&&CSS.highlights.set('show-result-other',new Highlight(...ortherTextAreaRange))
- })
- /* //重新渲染highlightCanvas
- const canvasList = this.$refs.HighlightCanvas
- canvasList.forEach(canvas=>{
- canvas.initCanvasStyle()
- }) */
- //重新渲染搜索文字
- this.$refs.searchBox.searchWord(_,'research')
- })
- },
- //点击段落打标签icon
- handleAddSelectionLabel(file,block){
- const {DocId} = file
- const {SectionId,isThisLabelArr} = block
- //获取段落信息
- this.sectionInfo = {
- DocId,SectionId,isThisLabelArr
- }
- this.isAddSectionLabelShow = true
- },
- //点击上方选择标签icon
- handleSelectLabel({type,selectedLabelArr}){
- if(type!=='close'){
- this.selectedLabelArr = selectedLabelArr
- this.compareFiles = this.compareFiles.map(doc=>{
- //检测文档标签是否有被筛选的,有则将段落/片段的isSelectLabel设置为true
- doc = checkIsSelectLabelInFile(doc,this.selectedLabelArr)
- return doc
- })
- //更新视口文档
- this.initShowingFiles()
- }
- this.isSelectLabelShow = false
- },
- //段落打标签,可以一次打多个
- addSectionLabel(labelArr){
- //console.log('addArr',labelArr)
- //转换拿到的标签格式
- const labelList = labelArr.map(item=>{
- let temp = {
- LabelId :item.SaLabelId||item.LabelId,
- LabelName:item.LabelName,
- IsHistory:0,IsOther:0,
- IsThis:1,
- }
- return temp
- })
- this.updateSectionLabel(labelList,this.sectionInfo)
- this.checkLabel(labelList)
- this.isAddSectionLabelShow = false
- },
- //删除当前段落标签
- deleteSelectLabel(document,block,label){
- //获取当前段落的LabelList isThisLabelArr
- const {LabelList,isThisLabelArr} = block
- //labelList为isThisLabelArr删掉label这一项的数组
- const labelList = isThisLabelArr.filter(l=>l.LabelId!==label.LabelId)
- //LabelList对应的项要将IsThis改为0,存在IsThis IsHistory IsOther三者都为0的label不影响展示和数据,可以不管
- const newLabelList = LabelList.map(l=>{
- if(l.LabelId===label.LabelId&&l.IsThis===1){
- l.IsThis=0
- }
- return l
- })
- //updateSectionLabel type = 'delete'
- this.updateSectionLabel(labelList,{
- DocId:document.DocId,
- SectionId:block.SectionId
- },'delete',newLabelList)
- },
- //段落快速打标签,一次打一个
- quickAddSelectLabel(document,block,label){
- //获取当前段落的isThisLabelArr
- const {isThisLabelArr} = block
- //判断label在isThisLabelArr有没有,没有就 addSectionLabel
- if(isThisLabelArr.find(l=>l.LabelId===label.LabelId)){
- return
- }
- this.sectionInfo = {
- DocId:document.DocId,
- SectionId:block.SectionId,
- isThisLabelArr
- }
- this.addSectionLabel([...isThisLabelArr,label])
- },
- //更新段落标签
- updateSectionLabel(labelList,{DocId,SectionId},type='add',LabelList=[]){
- //找到更新的是哪篇文章
- let fileIndex = 0
- const file = this.compareFiles.find((file,index)=>{
- fileIndex=index
- return file.DocId===DocId
- })
- //找到更新的是哪个段落
- let sectionIndex=0
- const section = file.SectionList.find((section,index)=>{
- sectionIndex=index
- return section.SectionId===SectionId
- })
- if(!section) return
- //更新段落的标签信息,实际上更换的只有isThisLabelArr 和LabelList中对应的部分
- //其他两个数组不会做更改
- section.isThisLabelArr = labelList||[]
- section.ishasThisLabel = labelList.length?true:false
- if(type==='add'){
- //需要去重和更新LabelList的对应项
- const {LabelList,isThisLabelArr} = section
- section.LabelList = updateLabelList(LabelList,isThisLabelArr)
- }else{
- section.LabelList = LabelList
- }
- //更新段落和文章
- file.SectionList.splice(sectionIndex,1,section)
- this.compareFiles.splice(fileIndex,1,file)
- },
- //检查是否有新加的标签,如果有 更新newAddLabelArr
- checkLabel(arr){
- arr.forEach(label=>{
- if(this.newAddLabelArr.findIndex(l=>l.LabelId===label.LabelId)===-1){
- this.newAddLabelArr.push(label)
- }
- })
- },
- //添加对比文档
- AddCompareFiles(fileKeys){
- //获取新选的文档标签 HeadLabel 按理说 应该与selectedLabelArr合并去重
- //但是打开selectedLabel的时候会重新请求一次选择对比文档详情 所以这里可以什么都不用做
- semanticInterface.getCompareDocumentDetail({
- DocIds:fileKeys.join(',')
- }).then(res=>{
- if(res.Ret!==200) return
- const {DocList} = res.Data
- const newCompareFiles = DocList.map(doc=>{
- return formatSemanticFile(doc,this.selectedLabelArr)
- })
- this.compareFiles = [...this.compareFiles,...newCompareFiles]
- this.selectedFileArr = [...this.selectedFileArr,...fileKeys]
- this.initShowingFiles()
- //最后关闭这个弹窗
- this.handleBtnClick({type:'selectFile'},'close')
- })
- },
- //删除对比文档
- deleteCompareFile({DocId},index){
- //更新currentPageIndex
- const length = this.compareFiles.length
- if(length===1){
- this.$message.warning('请至少保留一个文档')
- return
- }
- if(this.currentPageIndex===length-1){
- this.currentPageIndex--
- }
- //compareFiles删除一项
- const fileIndex = this.compareFiles.findIndex(f=>f.DocId===DocId)
- this.compareFiles.splice(fileIndex,1)
- this.initShowingFiles()
- //selectedFileArr删除fileid
- const selectedIndex = this.selectedFileArr.findIndex(f=>f===DocId)
- this.selectedFileArr.splice(selectedIndex,1)
- //隐藏选定文字操作栏
- this.hideTextAreaTool()
- },
- //保存/另存为语义分析
- saveSemantic(semanticInfo){
- const{SaCompareId,Title,ClassifyId} = semanticInfo
- //参数格式转换
- const CompareList = this.compareFiles.map(file=>{
- return formatCompareListItem(file)
- })
- /* console.log('result',CompareList)
- return */
- this.dialogLoading = true
- semanticInterface.saveSemantic({
- SaCompareId:this.saveType===0?0:Number(SaCompareId),
- Title,ClassifyId:Number(ClassifyId),
- CompareList
- }).then(async (res)=>{
- this.dialogLoading = false
- if(res.Ret!==200) return
- const hintWord = this.saveType===0?'另存为':SaCompareId?'保存':'新增'
- this.$message.success(`${hintWord}成功`)
- this.semanticId = res.Data.SaCompareId
- this.semanticInfo.SaCompareId = res.Data.SaCompareId
- this.semanticInfo.Title = Title
- this.semanticInfo.ClassifyId = ClassifyId
- this.resultData = res.Data
- //检查是否有搜索词,有则保存搜索词
- const searchArr = this.$refs.searchBox.searchArr
- await semanticInterface.saveKeyWords({
- SaCompareId:this.semanticId,
- Keywords:searchArr
- })
- this.$refs.saveDialog.goNext()
- })
- },
- //保存/另存为弹窗关闭时触发
- //检查当前页面的语义分析id是否一致,不一致则replace对应的详情页
- checkSemanticId(type){
- //console.log('type',type)
- //console.log('show',this.isSaveFileShow)
- const {SaCompareId,ClassifyId} = this.semanticInfo
- const fileId = this.$route.query.fileId
- //type为toList时,需要跳转回列表页
- //关闭弹窗时,会触发两次close事件,第一次是按钮触发,第二次是父级组件改变了isSaveFileShow触发
- //第一次的type为toList,第二次的type为undefined,因为需要跳转,所以将这段逻辑提前并return
- if(type==='toList'){
- sessionStorage.setItem('fileClassify',ClassifyId+'')
- sessionStorage.setItem('fileId',SaCompareId+'')
- this.$router.replace('/semanticsPage')
- return
- }
- //edit的情况
- if(SaCompareId&&fileId&&Number(this.$route.query.fileId.split('_')[1])!==SaCompareId){
- this.$router.replace({path:'/editSemantics',query:{fileId:'children_'+SaCompareId}})
- }
- //add的情况
- if(this.$route.path==='/addSemantics'&&SaCompareId){
- this.$router.replace({path:'/editSemantics',query:{fileId:'children_'+SaCompareId}})
- }
- this.handleBtnClick({type:'saveFile'},'close')
- },
- //上传结果图片
- async uploadImg(imgData){
- //将base64上传获得线上地址
- const form = new FormData();
- form.append('Image', imgData);
- const res = await semanticInterface.uploadImg(form)
- if(res.Ret!==200) return
- //上传结果图片
- semanticInterface.updateSemanticImg({
- SaCompareId:this.semanticId,
- ResultImg:res.Data.ResourceUrl
- }).then(res=>{
- if(res.Ret!==200) return
- this.$message.success('上传结果图片成功')
- this.checkSemanticId('toList')
- })
- },
- //在file-item-content区域鼠标抬起触发
- handleMouseUp(e,index){
- if(e.type!=="mouseup") return
- //关闭选定文字操作栏
- this.hideTextAreaTool()
- const selection = document.getSelection()
- const file = this.showingFiles[index]
- //获取该段落的选定文字标签
- if(!checkSelectionAndRange(selection)){
- //不是选区,单纯的鼠标点击后抬起
- if(e.target.nodeName==='P'&&e.target.className.includes('block-innerText')){
- const blockId = Number(e.target.id)||0
- blockId&&this.checkPosTextLabel(e,file,blockId)
- }
- return
- }
- //是选区
- this.getSelectionRange(selection,file)
- },
- //检测位置是否有选定文字标签,若有则展示操作栏
- checkPosTextLabel({clientX,clientY},file,SectionId){
- //获取该段落的选定文字标签
- const textAreaList = file.textAreaList.filter(t=>t.SectionId===SectionId)
- const block = file.SectionList.find(s=>s.SectionId===SectionId&&s.IsPart===0)
- const textAreaInfo = []
- //判断文字标签是否在点击位置内
- textAreaList.forEach(text=>{
- if(text.areaRangeInfo){
- const {BoundingXRange,BoundingYRange} = text.areaRangeInfo
- const isBoundingX = clientX>=BoundingXRange[0]&&clientX<=BoundingXRange[1]
- const isBoundingY = clientY>=BoundingYRange[0]&&clientY<=BoundingYRange[1]
- isBoundingX&&isBoundingY&&(textAreaInfo.push(text))
- }
- })
- /* console.log('arr',textAreaInfo) */
- if(textAreaInfo.length){
- //根据最大范围确定操作栏应展示的位置
- const maxWidth = Math.max.apply(null,textAreaInfo.map(i=>i.areaRangeInfo.rangeWidth))
- const maxTextRange = textAreaInfo.find(item=>item.areaRangeInfo.rangeWidth===maxWidth)
- this.positionInfo = {
- left:maxTextRange.areaRangeInfo.BoundingXRange[0]+maxWidth/2 - textAreaToolWidth/2,
- top:maxTextRange.areaRangeInfo.BoundingYRange[1]
- }
- this.blockInfo = {DocId:file.DocId,...block}
- this.currentTextArea = maxTextRange
- this.textAreaInfo = textAreaInfo
- this.isShowTextArea = true
- }else{
- this.hideTextAreaTool()
- }
- },
- //获取选区并展示操作栏
- getSelectionRange(selection,file){
- const range = selection.getRangeAt(0)
- //因为鼠标点击选区时选区会消失,重新渲染一次
- selection.removeAllRanges()
- selection.addRange(range)
- const {currentRange,currentNode} = getCurrentRange(selection,range)
- //根据id找到选定文字所属段落
- const SectionId = Number(currentNode.parentNode.id)
- const block = file.SectionList.find(s=>s.SectionId===SectionId)
- this.blockInfo = {...block,DocId:file.DocId}
- //根据currentRange确定选定文字操作栏应该出现的位置
- const bounding = currentRange.getClientRects()
- this.positionInfo = {
- left:bounding[bounding.length-1].left+bounding[bounding.length-1].width/2 - textAreaToolWidth/2,
- top:bounding[bounding.length-1].top+bounding[bounding.length-1].height
- }
- //根据currentRange确定是选区是否已有标签 并展示操作栏
- this.checkOffsetPosTextLabel(currentRange,file,SectionId,currentRange.toString())
- //无论是否有标签,都需要展示操作栏
- this.isShowTextArea = true
- },
- //检测段落指定位置是否有选定文字标签
- checkOffsetPosTextLabel({startOffset,endOffset},file,SectionId,rangeString){
- //获取该段落的选定文字标签
- const textAreaList = file.textAreaList.filter(t=>t.SectionId===SectionId)
- const textAreaInfo = []
- textAreaList.forEach(text=>{
- if(text.areaRangeInfo){
- const {StartOffset,EndOffset} = text.areaRangeInfo
- const isIncludeStart = startOffset<=StartOffset
- const isIncludeEnd = endOffset<=EndOffset
- isIncludeStart&&isIncludeEnd&&(textAreaInfo.push(text))
- }
- })
- this.textAreaInfo = textAreaInfo
- if(this.textAreaInfo.length){
- //根据最大范围确定currentTextArea
- const maxOffset = Math.max.apply(null,textAreaInfo.map(i=>i.areaRangeInfo.rangeOffset))
- const maxTextRange = textAreaInfo.find(item=>item.areaRangeInfo.rangeOffset===maxOffset)
- this.currentTextArea = maxTextRange
- }else{
- //如果当前指定位置内,没有选定文字标签,则新生成一个作为currentTextArea
- this.currentTextArea = addNewTextRange(Number(SectionId),startOffset,endOffset,rangeString)
- /* const fileIndex = this.compareFiles.findIndex(f=>f.DocId===file.DocId)
- file.textAreaList.push(_.cloneDeep(this.currentTextArea))
- this.compareFiles.splice(fileIndex,1,file) */
- }
- },
- //隐藏选定文字操作栏,并清除选区
- hideTextAreaTool(type,doc,e){
- //页面滚动触发,需要判断滚动的文章是否是当前选定文字操作框对应的文章
- //如果不是,啥都不做;如果是,隐藏操作框
- if(type==='scroll'){
- if(!this.isShowTextArea) return
- if(doc.DocId===this.blockInfo.DocId){
- document.getSelection().removeAllRanges()
- this.isShowTextArea = false
- }
- }else{
- //点击页面外的区域触发,隐藏操作栏
- //document.getSelection().removeAllRanges()
- this.isShowTextArea = false
- }
- },
- //选定文字打标签,一次可以打多个/零个 零个的时候单独处理
- addTextAreaLabel(labelArr){
- //更改currentTextArea
- this.currentTextArea.isThisLabelArr = labelArr
- this.currentTextArea.ishasThisLabel = labelArr.length?true:false
- const {LabelList,isThisLabelArr} = this.currentTextArea
- this.currentTextArea.LabelList = updateLabelList(LabelList,isThisLabelArr)
- //更改file.textAreaList[]
- const {startOffset,endOffset} = this.currentTextArea
- const textAreaListItem = _.cloneDeep(this.currentTextArea)
- const {DocId,SectionId} = this.blockInfo
- let fileIndex = 0
- const file = this.compareFiles.find((file,index)=>{
- fileIndex=index
- return file.DocId===DocId
- })
- const textAreaListIndex = file.textAreaList.findIndex(i=>{
- return i.startOffset===startOffset&&i.endOffset===endOffset&&i.SectionId===SectionId
- })
- textAreaListIndex!==-1&&labelArr.length!==0&&file.textAreaList.splice(textAreaListIndex,1,textAreaListItem)
- textAreaListIndex===-1&&labelArr.length!==0&&file.textAreaList.push(textAreaListItem)
- //labelArr为空时,检查是否应该删除这一项
- if(textAreaListIndex!==-1&&labelArr.length===0){
- checkAllLabelsAreEmpty(textAreaListItem)&&
- file.textAreaList.splice(textAreaListIndex,1)
- }
-
- //更改textAreaInfo
- const textAreaInfoIndex = this.textAreaInfo.findIndex(i=>{
- return i.startOffset===startOffset&&i.endOffset===endOffset&&i.SectionId===SectionId
- })
- textAreaInfoIndex!==-1&&labelArr.length!==0&&this.textAreaInfo.splice(textAreaInfoIndex,1,textAreaListItem)
- textAreaInfoIndex===-1&&labelArr.length!==0&&this.textAreaInfo.push(textAreaListItem)
- //labelArr为空时,检查是否应该删除这一项
- if(textAreaInfoIndex!==-1&&labelArr.length===0){
- checkAllLabelsAreEmpty(textAreaListItem)&&
- this.textAreaInfo.splice(textAreaInfoIndex,1)
- }
-
- //initShowingFiles
- this.compareFiles.splice(fileIndex,1,file)
- this.initShowingFiles()
- this.checkLabel(labelArr)
- },
- //选定文字快速打标签,一次只能打一个
- quickAddTextAreaLabel(label){
- //获取当前选定文字的isThisLabelArr 步骤与段落快速打标签基本相同
- const {isThisLabelArr} = this.currentTextArea
- if(isThisLabelArr.find(l=>l.LabelId===label.LabelId)){
- return
- }
- this.addTextAreaLabel([...isThisLabelArr,label])
- },
- //删除选定文字标签
- deleteTextAreaLabel(label){
- //检查label.areaRangeInfo,rangeSectionId与currentTextArea是否匹配
- const {rangeSectionId,areaRangeInfo} = label
- const {startOffset,endOffset} = this.currentTextArea
- if(!(startOffset===areaRangeInfo.startOffset&&
- endOffset===areaRangeInfo.endOffset&&
- rangeSectionId===this.currentTextArea.SectionId)
- ){
- const textAreaInfoIndex = this.textAreaInfo.findIndex(i=>{
- return i.startOffset===areaRangeInfo.StartOffset&&i.endOffset===areaRangeInfo.EndOffset&&i.SectionId===rangeSectionId
- })
- textAreaInfoIndex!==-1&&(this.currentTextArea = this.textAreaInfo[textAreaInfoIndex])
- }
- const {isThisLabelArr} = this.currentTextArea
- const labelList = isThisLabelArr.filter(l=>l.LabelId!==label.LabelId)
- this.addTextAreaLabel(labelList)
- },
- //鼠标是否经过有选区的位置
- /* checkTextArea(e,doc){
- console.log('move',e)
- } */
- },
- mounted(){
- this.getSemanticData()
- },
- destroyed(){
- CSS.highlights&&CSS.highlights.clear();
- }
- };
- </script>
- <style lang="scss">
- .semantics-edit-page{
- .el-popover__reference{
- width: 100%;
- display: block;
- height: 100%;
- padding: 0 !important;
- }
- }
- </style>
- <style scoped lang="scss">
- @import "../css/basePage.scss";
- @import "../css/semanticsEditPage.scss";
- </style>
|