feat(RenderMinerU): 添加表格编辑功能

- 在表格上方添加编辑按钮
- 点击编辑后,表格变为可编辑状态- 编辑完成后,点击返回按钮,表格恢复为只读状态
- 优化了表格渲染逻辑,为每个表格添加唯一ID- 调整了表格样式,使其支持编辑功能
This commit is contained in:
陈昱达
2025-04-14 15:33:14 +08:00
parent b3af3feffe
commit 6c8212b031
9 changed files with 202 additions and 113 deletions

View File

@@ -1,7 +1,5 @@
import config from '@/config'
import urlMap from '@/config/urlMap'
console.log(config)
export default function getUrl(url, domainType = 'admin') {
let domain = ''
// if (domainType === 'admin') {

View File

@@ -335,6 +335,7 @@ body .el-collapse-item__wrap {
table {
border: 1px solid #f9f9f9;
position: relative;
//width: 100%;
margin: 5px;
border-collapse: collapse;
@@ -381,3 +382,7 @@ body .el-collapse-item__wrap {
opacity: 1; // 悬停时显示
}
}
.editor-button {
position: relative;
}

View File

@@ -16,7 +16,9 @@
<div v-html="markdownHtml" class="view-body" id="viewBody" ref="viewBody"></div>
</el-tab-pane>
<el-tab-pane label="编辑">
<div class="lineH25" contenteditable id="md-editor" @blur="emitMarkDown">{{ markdown }}</div>
<div class="lineH25 view-body" contenteditable id="md-editor" @blur="emitMarkDown" v-html="markdown">
<!-- <pre id="viewBody"></pre>-->
</div>
</el-tab-pane>
</el-tabs>
</div>
@@ -36,81 +38,123 @@ export default {
name: 'index',
data() {
return {
tableIdCounter: 0,
prdUrl: ``,
iframeSrc: window.location.origin,
bboxList: [],
markdown: '',
md,
markdownHtml: '',
page: 1
page: 1,
copyTable: null,
tableActionButtons: [
{
label: '重新识别',
icon: 'el-icon-edit',
click: tableElement => {
console.log('重新识别')
}
},
{
label: '编辑',
icon: 'el-icon-edit',
click: tableElement => {
this.copyTable = tableElement.innerHTML
tableElement.classList.remove('m-view')
tableElement.setAttribute('contenteditable', 'true')
let buttonContainer = tableElement.querySelector('.md-editor-setting')
buttonContainer.innerHTML = null
this.generateButton(tableElement, buttonContainer, this.tableActionConfirm)
}
}
],
tableActionConfirm: [
{
label: '返回',
icon: 'el-icon-edit',
click: tableElement => {
tableElement.classList.add('m-view')
tableElement.setAttribute('contenteditable', 'false')
let buttonContainer = tableElement.querySelector('.md-editor-setting')
buttonContainer.innerHTML = null
this.generateButton(tableElement, buttonContainer, this.tableActionButtons)
}
}
// {
// label: '取消',
// icon: 'el-icon-edit',
// click: tableElement => {}
// }
]
}
},
props: {
documentId: {
type: String,
default: '1359571867133448192'
default: '1361351897324294144'
},
isEdit: {
type: Boolean,
default: true
}
},
watch: {},
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() {
// 创建一个唯一的按钮容器
const buttonContainer = document.createElement('div')
buttonContainer.style.position = 'absolute'
buttonContainer.style.pointerEvents = 'none'
// document.body.appendChild(buttonContainer)
this.$nextTick(() => {
const mdHtml = document.getElementById('md-editor')
// 当鼠标滑动view-body下的table 时 增加浮层按钮
window.addEventListener('mouseover', e => {
// 检查是否在 viewBody 内部
const viewBody = document.getElementById('viewBody')
if (viewBody.contains(e.target)) {
// 检查目标元素是否为 table 或其子元素
mdHtml.addEventListener('mouseover', e => {
const tableElement = e.target.closest('table')
if (tableElement) {
// 清除之前的按钮
// buttonContainer.innerHTML = ''
//
// // 在这里添加浮层按钮的逻辑
// console.log('Mouse over table or TD element inside viewBody')
// // 生成两个按钮
// const button = document.createElement('button')
// button.innerText = '标注'
// button.style.position = 'absolute'
// // 按钮位置在表格正中间浮动
// // 设置按钮位置在鼠标位置
// const rect = tableElement.getBoundingClientRect()
// console.log(rect)
// // 按钮s生成在鼠标位置
// button.style.left = `-10px`
// button.style.top = `-10px`
//
// button.style.backgroundColor = 'transparent'
// button.style.border = 'none'
// button.style.cursor = 'pointer'
// button.style.padding = '0'
// button.style.fontSize = '16px'
// button.style.zIndex = '9999'
// button.style.pointerEvents = 'auto'
// button.addEventListener('click', () => {
// alert(1)
// })
// buttonContainer.appendChild(button)
// tableElement.appendChild(buttonContainer)
// 检查是否已经存在按钮容器
let buttonContainer = tableElement.querySelector('.md-editor-setting')
if (!buttonContainer) {
buttonContainer = document.createElement('div')
buttonContainer.style.position = 'absolute'
buttonContainer.style.pointerEvents = 'none'
buttonContainer.style.zIndex = '9999'
buttonContainer.className = 'md-editor-setting'
buttonContainer.setAttribute('contenteditable', 'false')
this.generateButton(tableElement, buttonContainer)
// 设置按钮位置在表格正中间浮动
const rect = tableElement.getBoundingClientRect()
buttonContainer.style.left = `10px` // 调整位置
buttonContainer.style.top = `-20px` // 调整位置
tableElement.appendChild(buttonContainer)
}
}
}
})
})
// 当鼠标离开 view-body 下的 table 时 删除按钮
window.addEventListener('mouseout', e => {
// 检查是否在 viewBody 内部
const viewBody = document.getElementById('viewBody')
if (!viewBody.contains(e.target) || !e.target.closest('table')) {
buttonContainer.innerHTML = ''
}
mdHtml.addEventListener('mouseout', e => {
const tableElement = e.target.closest('table')
if (!tableElement || !tableElement.contains(e.relatedTarget)) {
const buttonContainer = tableElement.querySelector('.md-editor-setting')
if (buttonContainer) {
buttonContainer.remove()
}
}
})
})
},
// 导出
@@ -164,18 +208,23 @@ export default {
})
},
changeTab() {
let pre = document.getElementById('md-editor').innerText
// pre= JSON.stringify(pre)
let copyMdHtml = md.render(pre)
let pre = document.getElementById('md-editor').innerHTML
// pre = JSON.stringify(pre)
// let copyMdHtml = md.render(pre)
// 给 copyMdHtml 里面的table 增加 class m-view
copyMdHtml = copyMdHtml.replace(/<table/g, '<table class="m-view"')
this.markdownHtml = copyMdHtml
// copyMdHtml = copyMdHtml.re
this.markdownHtml = md.render(pre.replace(/class="m-view"/g, ''))
},
async getPDFDetailMarkDown() {
const response = await fetch(minerUMarkDown({ documentId: this.documentId }))
this.markdown = await response.text()
this.markdownHtml = this.md.render(this.markdown).replace(/<table/g, '<table class="m-view"')
this.markdown = this.markdown
.replace(/<table/g, () => {
const uniqueId = `table-${this.tableIdCounter++}`
return `<table contenteditable='false' id="${uniqueId}" class="m-view"`
})
.replace(/<script/g, '< script')
this.markdownHtml = this.md.render(this.markdown.replace(/class="m-view"/g, ''))
},
// 向 iframe 发送消息
sendMessageToIframe(type, message) {
@@ -197,8 +246,6 @@ export default {
this.getPDFDetailBbox()
this.getPDFDetailMarkDown()
this.prdUrl = getPdfUrl({ documentId: this.documentId })
console.log(this.prdUrl)
},
mounted() {
// 监听 iframe 的 postMessage 事件

View File

@@ -22,11 +22,7 @@
:before-upload="handleBeforeUpload"
:show-file-list="false"
:file-list="fieldList"
:data="{
...form,
beMinerU: form.radio === '2' ? null : form.beMinerU,
beOcr: form.radio === '2' ? null : form.beOcr
}"
:data="form"
>
<el-empty v-if="!uploadLoading">
<template #description>

View File

@@ -46,9 +46,9 @@ export default {
name: 'create',
data() {
return {
visible: false,
visible: true,
active: 0,
documentId: ''
documentId: '1361352503568994304'
}
},
props: {},

View File

@@ -191,8 +191,6 @@ export default {
this.knowledgeName = res.content.content.name
this.knowledgeDesc = res.content.content.description
this.segmentedMode = res.content.content.segmentedMode
console.log(res)
})
},
@@ -224,7 +222,9 @@ export default {
}).then(res => {
this.list = res.content.content.list
this.total = res.content.content.total
this.hasList = true
if (!this.hasList && this.list.length > 0) {
this.hasList = true
}
})
},
pageChange(pageSize) {
@@ -255,7 +255,7 @@ export default {
}
},
created() {},
mounted() {
async mounted() {
this.getKnowledgeDetail()
// 获取知识库文件列表
this.getKnowledgeFiledList()

View File

@@ -16,10 +16,12 @@ export default {
{ prop: 'ruleType', key: '规则类型' },
{ prop: 'createdDate', key: '创建时间' },
{
key: '操作', render: (h, params) => {
return h('div', [h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleInfoVisiable(params.row) } }, '查看详情'),
h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleEdit(params.row) } }, '修改'),
h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleDelete(params.row) } }, '删除')
key: '操作',
render: (h, params) => {
return h('div', [
h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleInfoVisiable(params.row) } }, '查看详情'),
h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleEdit(params.row) } }, '修改'),
h('el-button', { props: { type: 'text', size: 'mini' }, on: { click: () => this.handleDelete(params.row) } }, '删除')
])
}
}
@@ -122,7 +124,7 @@ export default {
},
watch: {
form: {
handler() { },
handler() {},
deep: true
}
},
@@ -223,8 +225,15 @@ export default {
<!-- 创建时间 -->
<el-col :span="8">
<el-form-item label="创建时间">
<el-date-picker v-model="form.createdDate" type="daterange" unlink-panels range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期" :picker-options="form.pickerOptions">
<el-date-picker
v-model="form.createdDate"
type="daterange"
unlink-panels
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
:picker-options="form.pickerOptions"
>
</el-date-picker>
</el-form-item>
</el-col>
@@ -264,8 +273,14 @@ export default {
<!-- 分页 -->
<el-row>
<el-col :span="24" class="flex" style="justify-content: right;">
<el-pagination background layout="prev, pager, next" @current-change="handleCurrentChange"
:current-page="currentPage" :hide-on-single-page="true" :total="tableData.length">
<el-pagination
background
layout="prev, pager, next"
@current-change="handleCurrentChange"
:current-page="currentPage"
:hide-on-single-page="true"
:total="tableData.length"
>
</el-pagination>
</el-col>
</el-row>
@@ -273,8 +288,14 @@ export default {
<!-- 规则详情弹窗 -->
<el-drawer :visible.sync="diglogOptions.visible" size="50%" :title="diglogOptions.title">
<!-- diglog 弹窗内容组件 -->
<component class="container" v-if="diglogOptions.visible" :is="diglogOptions.currentComponent" :data="tableData"
:columns="columns" :currentRow="diglogOptions.currentRow" />
<component
class="container"
v-if="diglogOptions.visible"
:is="diglogOptions.currentComponent"
:data="tableData"
:columns="columns"
:currentRow="diglogOptions.currentRow"
/>
</el-drawer>
</div>
</template>

View File

@@ -45,24 +45,32 @@ export default {
let filteredList = this.tabList
// 按照顺序进行筛选,先按照知识库进行筛选
filteredList = this.form.knowledge ? filteredList.filter(item => {
return item.docTypeName === this.form.knowledge
}) : filteredList
filteredList = this.form.knowledge
? filteredList.filter(item => {
return item.docTypeName === this.form.knowledge
})
: filteredList
// 按照知识文件名称进行筛选
filteredList = this.form.knowledgeName ? filteredList.filter(item => {
return item.fileName === this.form.knowledgeName
}) : filteredList
filteredList = this.form.knowledgeName
? filteredList.filter(item => {
return item.fileName === this.form.knowledgeName
})
: filteredList
// 按照上传用户进行筛选
filteredList = this.form.uploadUser ? filteredList.filter(item => {
return item.createdUser === this.form.uploadUser
}) : filteredList
filteredList = this.form.uploadUser
? filteredList.filter(item => {
return item.createdUser === this.form.uploadUser
})
: filteredList
// 按照任务状态进行筛选
filteredList = this.form.taskStatus ? filteredList.filter(item => {
return item.processStatus === this.form.taskStatus
}) : filteredList
filteredList = this.form.taskStatus
? filteredList.filter(item => {
return item.processStatus === this.form.taskStatus
})
: filteredList
// 处理的状态格式化
filteredList = filteredList.map(item => {
@@ -71,9 +79,15 @@ export default {
})
// 按照任务时间进行筛选
filteredList = this.form.taskTime.length > 0 ? filteredList.filter(item => {
return new Date(item.uploadDate).getTime() >= new Date(this.form.taskTime[0]).getTime() && new Date(item.uploadDate).getTime() <= new Date(this.form.taskTime[1]).getTime()
}) : filteredList
filteredList =
this.form.taskTime.length > 0
? filteredList.filter(item => {
return (
new Date(item.uploadDate).getTime() >= new Date(this.form.taskTime[0]).getTime() &&
new Date(item.uploadDate).getTime() <= new Date(this.form.taskTime[1]).getTime()
)
})
: filteredList
// 默认返回所有列表
return filteredList
@@ -122,7 +136,6 @@ export default {
getDocByPage(payload).then(res => {
this.tabList = res.content.content.list ? res.content.content.list : []
console.log(`res:`, res.content.content.list)
})
},
handleReset() {
@@ -189,8 +202,14 @@ export default {
</el-col>
<el-col :span="8">
<el-form-item label="任务时间">
<el-date-picker v-model="form.taskTime" type="daterange" unlink-panels range-separator="至"
start-placeholder="开始日期" end-placeholder="结束日期">
<el-date-picker
v-model="form.taskTime"
type="daterange"
unlink-panels
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
>
</el-date-picker>
</el-form-item>
</el-col>
@@ -205,8 +224,7 @@ export default {
<r-table :columns="tableConfig.columns" :data="getFilterTableData" :deletion="false"></r-table>
<!-- 弹出提示框 里面是各种详情内容 -->
<el-drawer title="上传任务详情" :visible.sync="infoDialogVisible" size="80%"
:before-close="() => (infoDialogVisible = false)">
<el-drawer title="上传任务详情" :visible.sync="infoDialogVisible" size="80%" :before-close="() => (infoDialogVisible = false)">
<knowledge-info :form="activeForm" v-if="infoDialogVisible"></knowledge-info>
</el-drawer>
</div>

View File

@@ -1,10 +1,8 @@
<script>
export default {
name: 'index',
data() {
return {
}
return {}
},
props: {
form: {
@@ -27,8 +25,7 @@ export default {
beforeMount() {
console.log(`this.form:`, this.form)
},
methods: {
}
methods: {}
}
</script>
@@ -87,9 +84,16 @@ export default {
</el-form-item>
</el-col>
<el-col :span="3">
<el-button type="primary" size="small"
@click="() => { form.processStatus = form.processStatus === 1 ? 2 : 1 }">switch
status</el-button>
<el-button
type="primary"
size="small"
@click="
() => {
form.processStatus = form.processStatus === 1 ? 2 : 1
}
"
>switch status</el-button
>
</el-col>
</el-row>