mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-09 10:56:50 +08:00
feat(RenderMinerU): 优化表格识别和编辑功能
- 添加表格重新识别功能,支持对选定表格进行重新识别和编辑 - 优化表格编辑界面,增加撤销和重做功能 - 改进表格数据处理逻辑,提高识别准确性和编辑体验 -调整表格按钮样式和布局,增加图标和提示
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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, ''))
|
||||
|
||||
Reference in New Issue
Block a user