feat(RenderMinerU): 优化表格识别和编辑功能

- 添加表格重新识别功能,支持对选定表格进行重新识别和编辑
- 优化表格编辑界面,增加撤销和重做功能
- 改进表格数据处理逻辑,提高识别准确性和编辑体验
-调整表格按钮样式和布局,增加图标和提示
This commit is contained in:
陈昱达
2025-04-18 16:13:04 +08:00
parent cda4562761
commit 4e938e0bba
5 changed files with 160 additions and 31 deletions

View File

@@ -2,7 +2,7 @@
<el-breadcrumb class="app-breadcrumb" separator-class="el-icon-arrow-right">
<transition-group name="breadcrumb">
<!-- <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">-->
<el-breadcrumb-item v-for="(item, index) in levelList" :key="index">
<el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
<span v-if="item.redirect === 'noRedirect' || index === levelList.length - 1" class="no-redirect fs16">{{ item.meta.title }}</span>
<span v-else>{{ item.meta.title }}</span>
</el-breadcrumb-item>

View File

@@ -20,9 +20,7 @@
<div v-html="markdownHtml" class="view-body" id="viewBody" ref="viewBody"></div>
</el-tab-pane>
<el-tab-pane label="编辑" :disabled="!isEdit" v-if="isEdit">
<div class="lineH25 view-body" contenteditable id="md-editor" @blur="emitMarkDown" v-html="markdown">
<!-- <pre id="viewBody"></pre>-->
</div>
<div class="lineH25 view-body" contenteditable id="md-editor" @blur="emitMarkDown" v-html="markdown"></div>
</el-tab-pane>
</el-tabs>
</div>
@@ -47,6 +45,9 @@ export default {
prdUrl: ``,
iframeSrc: window.location.origin,
bboxList: [],
// 对照表
selectionTable: [], // 表格对照表 记录表格与image_path 关系
selectionImagePath: '', // 当前表格对应的图片路径
markdown: '',
md,
markdownHtml: '',
@@ -55,14 +56,36 @@ export default {
tableActionButtons: [
{
label: '重新识别',
icon: 'el-icon-edit',
icon: 'el-icon-view',
click: tableElement => {
console.log('重新识别')
// 获取的 识别图片
this.selectionImagePath = ''
let chooseItem = this.findMatchingTable(tableElement)
if (!this.selectionImagePath) {
this.$message.error('未能识别当前表格图片')
return false
} else {
// this.finishedMiner = true
this.updateTableAttributes(tableElement, chooseItem)
let loading = this.$loading({
target: tableElement,
lockScroll: false,
// spinner: 'element-loading-spinner',
// background: 'rgba(0, 0, 0, 0.8)',
text: 'AI模型分析中....'
})
setTimeout(() => {
loading.close()
// tableElement.innerHTML = '<div>123</div>'
}, 3000)
}
}
},
{
label: '编辑',
icon: 'el-icon-edit',
icon: 'el-icon-edit-outline',
click: tableElement => {
this.copyTable = tableElement.innerHTML
tableElement.classList.remove('m-view')
@@ -76,7 +99,7 @@ export default {
tableActionConfirm: [
{
label: '返回',
icon: 'el-icon-edit',
icon: 'el-icon-refresh-left',
click: tableElement => {
tableElement.classList.add('m-view')
tableElement.setAttribute('contenteditable', 'false')
@@ -122,31 +145,15 @@ export default {
components: {},
filters: {},
methods: {
// 封装 按钮生成事件
generateButton(tableElement, buttonContainer, actionButtons) {
let contenteditable = tableElement.getAttribute('contenteditable')
let buttons = !actionButtons ? (contenteditable === 'false' ? this.tableActionButtons : this.tableActionConfirm) : actionButtons
// 循环按钮配置
for (let i = 0; i < buttons.length; i++) {
const button = document.createElement('button')
button.innerText = buttons[i].label
button.className = 'el-button el-button--primary el-button--mini editor-button'
button.style.pointerEvents = 'auto'
button.addEventListener('click', () => {
buttons[i].click(tableElement)
})
buttonContainer.appendChild(button)
}
},
// 生成视觉模型
viewHtmlModel() {
this.$nextTick(() => {
const mdHtml = document.getElementById('md-editor')
// 监听鼠标悬停事件,为表格元素添加浮层按钮
mdHtml.addEventListener('mouseover', e => {
const tableElement = e.target.closest('table')
if (tableElement) {
// 检查是否已经存在按钮容器
// 检查是否已经存在按钮容器,避免重复创建
let buttonContainer = tableElement.querySelector('.md-editor-setting')
if (!buttonContainer) {
buttonContainer = document.createElement('div')
@@ -155,6 +162,7 @@ export default {
buttonContainer.style.zIndex = '9999'
buttonContainer.className = 'md-editor-setting'
buttonContainer.setAttribute('contenteditable', 'false')
// 调用生成按钮的方法
this.generateButton(tableElement, buttonContainer)
// 设置按钮位置在表格正中间浮动
const rect = tableElement.getBoundingClientRect()
@@ -165,6 +173,7 @@ export default {
}
})
// 监听鼠标离开事件,移除浮层按钮
mdHtml.addEventListener('mouseout', e => {
const tableElement = e.target.closest('table')
if (!tableElement || !tableElement.contains(e.relatedTarget)) {
@@ -176,6 +185,115 @@ export default {
})
})
},
// 封装 按钮生成事件
generateButton(tableElement, buttonContainer, actionButtons) {
// 获取表格的可编辑状态
let contenteditable = tableElement.getAttribute('contenteditable')
// 根据可编辑状态选择按钮配置
let buttons = !actionButtons ? (contenteditable === 'false' ? this.tableActionButtons : this.tableActionConfirm) : actionButtons
// 循环按钮配置,动态生成按钮并绑定点击事件
for (let i = 0; i < buttons.length; i++) {
const icon = document.createElement('i')
const button = document.createElement('button')
icon.className = `${buttons[i].icon} public-icon`
button.appendChild(icon)
// 悬浮提示
button.setAttribute('title', buttons[i].label)
button.className = 'el-button el-button--primary el-button--mini editor-button is-plain'
button.style.pointerEvents = 'auto'
button.addEventListener('click', () => {
buttons[i].click(tableElement)
})
buttonContainer.appendChild(button)
}
},
// 查找匹配的表格
findMatchingTable(tableElement) {
let chooseItem = null
let pathId = tableElement.getAttribute('data-path-id')
if (pathId) {
let pathType = tableElement.getAttribute('data-path-type')
this.selectionImagePath = pathId + pathType
} else {
// 如果没有路径 ID则通过表格内容匹配对照表
let tableText = this.getTableText(tableElement)
chooseItem = this.selectionTable.find(item => {
if (item.html) {
let itemText = this.getTableTextFromHtml(item.html)
return tableText === itemText
}
return false
})
if (chooseItem) {
this.selectionImagePath = chooseItem.image_path
}
}
return chooseItem
},
// 获取表格文本
getTableText(tableElement) {
let stringTable = tableElement.innerHTML
let tbodyMatch = stringTable.match(/<tbody>([\s\S]*)<\/tbody>/)
if (tbodyMatch) {
let newTable = document.createElement('table')
newTable.innerHTML = tbodyMatch[1]
return newTable.innerText
}
return ''
},
// 从 HTML 中获取表格文本
getTableTextFromHtml(html) {
let tableMatch = html.match(/<table>([\s\S]*)<\/table>/)
if (tableMatch) {
let domTable = document.createElement('table')
domTable.innerHTML = tableMatch[1]
return domTable.innerText
}
return ''
},
// 更新表格属性
updateTableAttributes(tableElement, chooseItem) {
tableElement.setAttribute('data-path-id', this.selectionImagePath.replace(/\.[^/.]+$/, ''))
let fileType = this.selectionImagePath.match(/\.[^/.]+$/)[0]
tableElement.setAttribute('data-path-type', fileType)
},
linesMap(table) {
;(table.blocks ? table.blocks : []).map(lines => {
console.log(lines)
lines.lines.map(spans => {
spans.spans.map(span => {
this.selectionTable.push({ html: span.html, image_path: span.image_path })
})
})
})
},
setTableSelection(selection) {
selection.map(item => {
if (item.preproc_blocks && item.preproc_blocks.length > 0) {
item.preproc_blocks.forEach(block => {
if (block.type === 'table') {
this.linesMap(block)
}
})
}
// 处理丢弃块
if (item.discarded_blocks && item.discarded_blocks.length > 0) {
item.discarded_blocks.forEach(block => {
if (block.type === 'table') {
this.linesMap(block)
}
})
}
})
},
// 导出
emitMarkDown() {
let pre = document.getElementById('md-editor').innerText
@@ -225,6 +343,10 @@ export default {
getPDFDetailBbox() {
minerUBbox({ documentId: this.documentId }).then(res => {
this.bboxList = this.formatJson(JSON.parse(JSON.stringify(res.content.content)))
this.setTableSelection(JSON.parse(JSON.stringify(res.content.content)))
console.log(this.selectionTable, 'this.selectionTable')
// this.$refs.iframe 重新刷新iframe
this.$refs.iframe.contentWindow.location.reload()
this.getPDFDetailMarkDown()
@@ -245,7 +367,7 @@ export default {
this.markdown = this.markdown
.replace(/<table/g, () => {
const uniqueId = `table-${this.tableIdCounter++}`
return `<table contenteditable='false' id="${uniqueId}" class="m-view"`
return `<table contenteditable='false' class="m-view"`
})
.replace(/<script/g, '< script')
this.markdownHtml = this.md.render(this.markdown.replace(/class="m-view"/g, ''))