feat(RenderMinerU): 优化界面样式和功能

- 添加文件名显示
- 调整按钮布局和样式
- 优化预览和编辑切换逻辑
- 调整页面滚动逻辑- 修复部分样式问题
This commit is contained in:
陈昱达
2025-04-24 19:35:38 +08:00
parent 9a8902576a
commit c1a96c4e29
6 changed files with 189 additions and 59 deletions

View File

@@ -84,3 +84,25 @@
} }
} }
} }
.group-medium {
.el-radio-button {
background: #f8f8f8;
padding: 5px;
&:first-child {
border-radius: 8px 0 0 8px;
& .el-radio-button__inner {
border: none;
}
}
&:last-child {
border-radius: 0 8px 8px 0;
& .el-radio-button__inner {
border: none;
}
}
& .el-radio-button__inner {
padding: 8px 15px;
}
}
}

View File

@@ -37,8 +37,12 @@ body,
color: #000 !important; color: #000 !important;
background: #f1f3f5 !important; background: #f1f3f5 !important;
border-color: #f1f3f5 !important; border-color: #f1f3f5 !important;
& :disabled { &.is-disabled {
color: rgba(0, 0, 0, 0.25); &.is-plain {
background-color: #fff !important;
border-color: #ebeef5 !important;
color: #c0c4cc !important;
}
} }
& :hover { & :hover {
color: #000; color: #000;
@@ -59,7 +63,8 @@ body,
.view-body { .view-body {
text-align: left; text-align: left;
font-size: 14px; font-size: 14px;
padding: 10px; padding: 0 10px;
margin: 10px 0;
div { div {
outline: unset; outline: unset;

View File

@@ -1,31 +1,74 @@
<template> <template>
<div style="height: 100%;"> <div style="height: 100%;">
<div class="mv10 mh20 text-right" v-if="isEdit"> <div class="flex align-items-c justify-content-b mb10">
<!-- 重试按钮 --> <div class="fileName flex align-items-c">
<el-button type="" size="medium" @click="retryMiner" :disabled="finishedMiner" style="margin-right: 10px;" plain>重试</el-button> <svg-icon
<!-- 保存并处理按钮 --> icon-class="pdf"
<el-button type="primary" size="medium" @click="saveMarkDown" :disabled="finishedMiner">保存并处理</el-button> style="width: 20px;height: 20px"
class-name="mr10"
/>
{{ fileName }}
</div> </div>
<div :class="!isEdit ? 'mt10 flex' : 'flex'" style="height:calc(100% - 35px);flex:1"> <div style="margin-left: 50px">
<el-radio-group v-model="tab" @change="changeTab" class="group-medium">
<el-radio-button label="0" name="0">预览</el-radio-button>
<el-radio-button label="1" name="1">编辑</el-radio-button>
</el-radio-group>
</div>
<div class=" text-right" v-if="isEdit">
<!-- 重试按钮 -->
<el-button
size="medium"
class="default"
@click="retryMiner"
:disabled="finishedMiner"
style="margin-right: 10px;"
plain
>重试</el-button
>
<!-- 保存并处理按钮 -->
<el-button
type="primary"
size="medium"
@click="saveMarkDown"
:disabled="finishedMiner"
>保存并处理</el-button
>
</div>
</div>
<div
:class="!isEdit ? 'mt10 flex' : 'flex'"
style="height:calc(100%);flex:1"
>
<iframe <iframe
v-if="isShowPdf" v-if="isShowPdf"
id="iframe" id="iframe"
ref="iframe" ref="iframe"
:src="`${iframeSrc}/pdfjs-dist/web/viewer.html?file=${encodeURIComponent(prdUrl)}`" :src="
class="miner-u el-card is-always-shadow ml20" `${iframeSrc}/pdfjs-dist/web/viewer.html?file=${encodeURIComponent(
prdUrl
)}`
"
class="ebiz-pdf el-card "
></iframe> ></iframe>
<div style="flex:1;" class="mh20 miner-u-md" v-loading="finishedMiner" element-loading-text="正在识别中..."> <div
<el-tabs type="border-card" style="height: 100%;overflow: hidden" @tab-click="changeTab" v-model="tab"> style="flex:1;"
<el-tab-pane label="预览" style="overflow:scroll;" ref="scrollView" name="0"> class="ml10 ebiz-pdf-md"
v-loading="finishedMiner"
element-loading-text="正在识别中..."
>
<div class="el-card ebiz-pdf" style="height: 100%;overflow: hidden">
<div ref="scrollView" v-show="tab === '0'">
<div <div
v-html="markdownHtml" v-html="markdownHtml"
class="view-body" class="view-body"
id="viewBody" id="viewBody"
ref="viewBody" ref="viewBody"
style="height:calc(100vh - 230px);overflow-y: scroll;overflow-x:hidden " style="height:calc(100vh - 180px);overflow-y: scroll;overflow-x:hidden "
></div> ></div>
</el-tab-pane> </div>
<el-tab-pane label="编辑" :disabled="!isEdit" v-if="isEdit" name="1"> <div :disabled="!isEdit" v-if="isEdit" v-show="tab === '1'">
<div <div
class="lineH25 view-body" class="lineH25 view-body"
contenteditable contenteditable
@@ -33,10 +76,10 @@
ref="mdEditor" ref="mdEditor"
@blur="emitMarkDown" @blur="emitMarkDown"
v-html="markdown" v-html="markdown"
style="height:calc(100vh - 230px);overflow-y: scroll;overflow-x:hidden " style="height:calc(100vh - 180px);overflow-y: scroll;overflow-x:hidden "
></div> ></div>
</el-tab-pane> </div>
</el-tabs> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -64,6 +107,7 @@ export default {
name: 'index', name: 'index',
data() { data() {
return { return {
fileName: '',
endEmit: false, endEmit: false,
tab: '0', tab: '0',
mdPges: 0, mdPges: 0,
@@ -115,9 +159,15 @@ export default {
this.copyTable = tableElement.innerHTML this.copyTable = tableElement.innerHTML
tableElement.classList.remove('m-view') tableElement.classList.remove('m-view')
tableElement.setAttribute('contenteditable', 'true') tableElement.setAttribute('contenteditable', 'true')
let buttonContainer = tableElement.querySelector('.md-editor-setting') let buttonContainer = tableElement.querySelector(
'.md-editor-setting'
)
buttonContainer.innerHTML = null buttonContainer.innerHTML = null
this.generateButton(tableElement, buttonContainer, this.tableActionConfirm) this.generateButton(
tableElement,
buttonContainer,
this.tableActionConfirm
)
} }
}, },
{ {
@@ -133,7 +183,9 @@ export default {
text: '正在撤销中....' text: '正在撤销中....'
}) })
let chooseItem = this.findMatchingTable(tableElement) let chooseItem = this.findMatchingTable(tableElement)
let tableMatch = chooseItem.html.match(/<table>([\s\S]*)<\/table>/) let tableMatch = chooseItem.html.match(
/<table>([\s\S]*)<\/table>/
)
if (tableMatch) { if (tableMatch) {
let div = document.createElement('table') let div = document.createElement('table')
div.innerHTML = tableMatch[1] div.innerHTML = tableMatch[1]
@@ -158,9 +210,15 @@ export default {
click: tableElement => { click: tableElement => {
tableElement.classList.add('m-view') tableElement.classList.add('m-view')
tableElement.setAttribute('contenteditable', 'false') tableElement.setAttribute('contenteditable', 'false')
let buttonContainer = tableElement.querySelector('.md-editor-setting') let buttonContainer = tableElement.querySelector(
'.md-editor-setting'
)
buttonContainer.innerHTML = null buttonContainer.innerHTML = null
this.generateButton(tableElement, buttonContainer, this.tableActionButtons) this.generateButton(
tableElement,
buttonContainer,
this.tableActionButtons
)
} }
} }
// { // {
@@ -221,7 +279,7 @@ export default {
} }
if (documentId) { if (documentId) {
viewBody.scrollTo({ viewBody.scrollTo({
top: documentId.offsetTop - 16, top: documentId.offsetTop - 130,
behavior: 'smooth' behavior: 'smooth'
}) })
} }
@@ -253,7 +311,9 @@ export default {
const tableElement = e.target.closest('table') const tableElement = e.target.closest('table')
if (tableElement) { if (tableElement) {
// 检查是否已经存在按钮容器,避免重复创建 // 检查是否已经存在按钮容器,避免重复创建
let buttonContainer = tableElement.querySelector('.md-editor-setting') let buttonContainer = tableElement.querySelector(
'.md-editor-setting'
)
if (!buttonContainer) { if (!buttonContainer) {
buttonContainer = document.createElement('div') buttonContainer = document.createElement('div')
buttonContainer.style.position = 'absolute' buttonContainer.style.position = 'absolute'
@@ -276,7 +336,9 @@ export default {
mdHtml.addEventListener('mouseout', e => { mdHtml.addEventListener('mouseout', e => {
const tableElement = e.target.closest('table') const tableElement = e.target.closest('table')
if (!tableElement || !tableElement.contains(e.relatedTarget)) { if (!tableElement || !tableElement.contains(e.relatedTarget)) {
const buttonContainer = tableElement.querySelector('.md-editor-setting') const buttonContainer = tableElement.querySelector(
'.md-editor-setting'
)
if (buttonContainer) { if (buttonContainer) {
buttonContainer.remove() buttonContainer.remove()
} }
@@ -289,7 +351,11 @@ export default {
// 获取表格的可编辑状态 // 获取表格的可编辑状态
let contenteditable = tableElement.getAttribute('contenteditable') let contenteditable = tableElement.getAttribute('contenteditable')
// 根据可编辑状态选择按钮配置 // 根据可编辑状态选择按钮配置
let buttons = !actionButtons ? (contenteditable === 'false' ? this.tableActionButtons : this.tableActionConfirm) : actionButtons let buttons = !actionButtons
? contenteditable === 'false'
? this.tableActionButtons
: this.tableActionConfirm
: actionButtons
let pathId = tableElement.getAttribute('data-path-id') let pathId = tableElement.getAttribute('data-path-id')
// 循环按钮配置,动态生成按钮并绑定点击事件 // 循环按钮配置,动态生成按钮并绑定点击事件
@@ -300,7 +366,8 @@ export default {
button.appendChild(icon) button.appendChild(icon)
// 悬浮提示 // 悬浮提示
button.setAttribute('title', buttons[i].label) button.setAttribute('title', buttons[i].label)
button.className = 'el-button el-button--primary el-button--mini editor-button is-plain' button.className =
'el-button el-button--primary el-button--mini editor-button is-plain'
button.style.pointerEvents = 'auto' button.style.pointerEvents = 'auto'
button.addEventListener('click', () => { button.addEventListener('click', () => {
buttons[i].click(tableElement) buttons[i].click(tableElement)
@@ -360,7 +427,10 @@ export default {
}, },
// 更新表格属性 // 更新表格属性
updateTableAttributes(tableElement, chooseItem) { updateTableAttributes(tableElement, chooseItem) {
tableElement.setAttribute('data-path-id', this.selectionImagePath.replace(/\.[^/.]+$/, '')) tableElement.setAttribute(
'data-path-id',
this.selectionImagePath.replace(/\.[^/.]+$/, '')
)
let fileType = this.selectionImagePath.match(/\.[^/.]+$/)[0] let fileType = this.selectionImagePath.match(/\.[^/.]+$/)[0]
tableElement.setAttribute('data-path-type', fileType) tableElement.setAttribute('data-path-type', fileType)
}, },
@@ -369,7 +439,10 @@ export default {
;(table.blocks ? table.blocks : []).map(lines => { ;(table.blocks ? table.blocks : []).map(lines => {
lines.lines.map(spans => { lines.lines.map(spans => {
spans.spans.map(span => { spans.spans.map(span => {
this.selectionTable.push({ html: span.html, image_path: span.image_path }) this.selectionTable.push({
html: span.html,
image_path: span.image_path
})
}) })
}) })
}) })
@@ -444,7 +517,9 @@ export default {
// bbox 解析 传递 颜色 // bbox 解析 传递 颜色
getPDFDetailBbox() { getPDFDetailBbox() {
minerUBbox({ documentId: this.documentId }).then(res => { minerUBbox({ documentId: this.documentId }).then(res => {
this.bboxList = this.formatJson(JSON.parse(JSON.stringify(res.content.content))) this.bboxList = this.formatJson(
JSON.parse(JSON.stringify(res.content.content))
)
this.fillSelectionTable(JSON.parse(JSON.stringify(res.content.content))) this.fillSelectionTable(JSON.parse(JSON.stringify(res.content.content)))
// this.$refs.iframe 重新刷新iframe // this.$refs.iframe 重新刷新iframe
@@ -479,7 +554,11 @@ ${text}`
}) })
.replace(/<script/g, '< script') .replace(/<script/g, '< script')
this.markdownHtml = this.md.render(this.markdown.replace(/class="m-view"/g, '').replace(/ebiz-code/g, 'view-code')) this.markdownHtml = this.md.render(
this.markdown
.replace(/class="m-view"/g, '')
.replace(/ebiz-code/g, 'view-code')
)
}, },
// tab 切换 // tab 切换
changeTab(evt) { changeTab(evt) {
@@ -493,15 +572,23 @@ ${text}`
if (!pathId) { if (!pathId) {
let ite = this.findMatchingTable(item) let ite = this.findMatchingTable(item)
if (ite) { if (ite) {
item.setAttribute('data-path-id', ite.image_path.replace(/\.[^/.]+$/, '')) item.setAttribute(
item.setAttribute('data-path-type', ite.image_path.match(/\.[^/.]+$/)[0]) 'data-path-id',
ite.image_path.replace(/\.[^/.]+$/, '')
)
item.setAttribute(
'data-path-type',
ite.image_path.match(/\.[^/.]+$/)[0]
)
} }
} }
}) })
} }
// 给 copyMdHtml 里面的table 增加 class m-view // 给 copyMdHtml 里面的table 增加 class m-view
// copyMdHtml = copyMdHtml.re // copyMdHtml = copyMdHtml.re
this.markdownHtml = md.render(pre.replace(/class="m-view"/g, '').replace(/ebiz-code/g, 'view-code')) this.markdownHtml = md.render(
pre.replace(/class="m-view"/g, '').replace(/ebiz-code/g, 'view-code')
)
setTimeout(() => { setTimeout(() => {
this.changePage(this.page, evt) this.changePage(this.page, evt)
}, 100) }, 100)
@@ -509,7 +596,9 @@ ${text}`
// 初始md 文档 // 初始md 文档
async getPDFDetailMarkDown() { async getPDFDetailMarkDown() {
// responseText 判断是否包含ebiz-code // responseText 判断是否包含ebiz-code
const response = await fetch(minerUMarkDown({ documentId: this.documentId })) const response = await fetch(
minerUMarkDown({ documentId: this.documentId })
)
this.markdown = await response.text() this.markdown = await response.text()
// this.markdown 包含 ebiz-code // this.markdown 包含 ebiz-code
if (this.markdown.indexOf('<ebiz-code ') < 0) { if (this.markdown.indexOf('<ebiz-code ') < 0) {
@@ -541,6 +630,7 @@ ${text}`
this.finishedMiner = true this.finishedMiner = true
minerUQuery({ id: this.documentId }).then(res => { minerUQuery({ id: this.documentId }).then(res => {
let mineruStatus = res.content.content.mineruStatus let mineruStatus = res.content.content.mineruStatus
this.fileName = res.content.content.fileName
switch (mineruStatus) { switch (mineruStatus) {
case 0: case 0:
case '0': case '0':
@@ -597,7 +687,10 @@ ${text}`
for (let i = 0; i < viewCodes.length; i++) { for (let i = 0; i < viewCodes.length; i++) {
const viewCode = viewCodes[i] const viewCode = viewCodes[i]
const viewCodeTop = viewCode.offsetTop const viewCodeTop = viewCode.offsetTop
if (viewCodeTop >= viewBodyTop && viewCodeTop < viewBodyTop + viewBodyHeight / 2) { if (
viewCodeTop >= viewBodyTop &&
viewCodeTop < viewBodyTop + viewBodyHeight / 2
) {
currentPage = i + 1 currentPage = i + 1
break break
} }
@@ -645,13 +738,19 @@ ${text}`
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.miner-u { .fileName {
font-family: PingFangSC, PingFang SC;
font-weight: 600;
font-size: 12px;
color: #3a3f4f;
line-height: 17px;
text-align: left;
font-style: normal;
}
.ebiz-pdf {
outline: none; outline: none;
border: none; border-radius: 7px;
flex: 1; flex: 1;
border-radius: unset;
//width:500px;
//height:100%
} }
#md-editor { #md-editor {
@@ -662,11 +761,20 @@ ${text}`
outline: none; outline: none;
border: none; border: none;
} }
.miner-u-md { .ebiz-pdf-md {
/deep/ .el-tabs--border-card > .el-tabs__content { border-radius: 7px;
height: calc(100% - 30px); box-shadow: unset;
/deep/ .el-tabs--border-card {
box-shadow: unset;
border-radius: 7px;
& .el-tabs__header {
border: none;
}
& .el-tabs__content {
overflow: auto; overflow: auto;
} }
}
//height: calc(100% - 30px);
.tabs__content { .tabs__content {
} }
} }

View File

@@ -1,6 +1,6 @@
let envInfo = process.env let envInfo = process.env
let [admin, jifen] = [envInfo.VUE_APP_ADMIN, 'http://192.168.2.62:7196/'] // let [admin, jifen] = [envInfo.VUE_APP_ADMIN, 'http://192.168.2.62:7196/']
// let [admin, jifen] = ['/api', 'http://192.168.2.62:7196/'] let [admin, jifen] = ['/api', 'http://192.168.2.62:7196/']
export default { export default {
admin, admin,

1
src/icons/svg/pdf.svg Normal file
View File

@@ -0,0 +1 @@
<svg t="1745494296867" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4399" width="20" height="20"><path d="M620.9 67.2H236.5c-30.3 0-54.9 25-54.9 55.9v782.7c0 30.9 24.6 55.9 54.9 55.9h549c30.3 0 54.9-25 54.9-55.9v-615L620.9 67.2z" fill="#FF4242" p-id="4400"></path><path d="M802 925.9H220.1V109.7h379.6v218.9H802z" fill="#FFFFFF" p-id="4401"></path><path d="M802 922.6H220.1V106.4h379.6v218.8H802z" fill="#FF6464" p-id="4402"></path><path d="M348.9 650.4c35.1 0 52.6 14.9 52.6 44.8 0 30.1-17.8 45.2-53.1 45.2h-38.2v57.4h-22.5V650.4h61.2z m-38.6 70.8H347c11.1 0 19.2-2.1 24.4-6.2 5-4.1 7.6-10.7 7.6-19.8 0-9.1-2.7-15.7-7.8-19.4-5.2-4.1-13.2-6.2-24.2-6.2h-36.7v51.6zM476.1 650.4c23.7 0 41.7 6.6 54.1 20 11.6 12.4 17.3 30.3 17.3 53.7 0 23.1-6 41.1-17.8 53.9-12.4 13.2-30.3 19.8-54.1 19.8h-53.3V650.4h53.8z m-31.2 128.2h26.6c18.6 0 32.4-4.5 41.1-13.4 8.5-8.9 12.8-22.5 12.8-41.1 0-19-4.3-32.6-12.6-41.3-8.7-8.9-22.3-13.2-40.9-13.2h-27v109zM670.5 650.4v19.2h-77.6v42.9h73.3v19.2h-73.3v66.1h-22.5V650.4h100.1z" fill="#FFFFFF" p-id="4403"></path></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -83,12 +83,12 @@
<!-- 添加预处理结果预览对话框 --> <!-- 添加预处理结果预览对话框 -->
<el-drawer <el-drawer
:visible.sync="visible" :visible.sync="visible"
size="80%" size="75%"
title="预处理结果预览" title="预处理结果预览"
:wrapperClosable="false" :wrapperClosable="false"
:destroy-on-close="true" :destroy-on-close="true"
> >
<div style="height:calc(100% - 55px);"> <div style="height:calc(100% - 35px);">
<r-miner-u <r-miner-u
:documentId="documentId" :documentId="documentId"
@saveMarkDown="saveMarkDown" @saveMarkDown="saveMarkDown"
@@ -111,7 +111,7 @@ export default {
magic, magic,
visible: false, visible: false,
active: 0, active: 0,
documentId: '1364315544778543104' documentId: '1365038001244180480'
} }
}, },
props: {}, props: {},
@@ -170,12 +170,6 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
/deep/ .el-drawer__header {
margin-bottom: unset;
border-bottom: 1px solid #eee;
padding-bottom: 20px;
}
/deep/ .card-bottom { /deep/ .card-bottom {
position: relative; position: relative;
width: 100%; width: 100%;