mirror of
http://112.124.100.131/ebiz-ai/ebiz-ai-knowledge-manage.git
synced 2025-12-10 11:26:50 +08:00
- 重构了侧边栏菜单的渲染逻辑,支持多级菜单 -优化了菜单项的样式和布局,提高了可读性和美观性- 增加了菜单项的点击事件处理,实现了菜单的动态展开和收缩 -调整了菜单项的路径处理方式,支持动态生成菜单路径- 优化了菜单项的激活状态管理,提高了用户体验
380 lines
9.9 KiB
Vue
380 lines
9.9 KiB
Vue
<!-- src/views/knowledge/detail/components/DocumentDrawer.vue -->
|
|
<template>
|
|
<el-drawer
|
|
:visible.sync="visible"
|
|
size="80%"
|
|
@close="$emit('update:visible', false)"
|
|
>
|
|
<!-- drawer title -->
|
|
<template #title>
|
|
<div class="flex align-items-c">
|
|
<div class="el-icon-document"></div>
|
|
<div class="ml10">{{ descriptions.dataset.knowledgeName }}</div>
|
|
<el-tag type="info" class="ml10" size="mini">
|
|
{{ descriptions.dataset.segmentedMode | filterSegmentedMode }}
|
|
</el-tag>
|
|
</div>
|
|
</template>
|
|
<div class="drawer-content">
|
|
<!-- 文件信息详情 -->
|
|
<el-card :shadow="'none'">
|
|
<el-descriptions size="small" :column="4">
|
|
<el-descriptions-item label="文件名称">
|
|
<i class="el-icon-document"></i
|
|
>{{ descriptions.dataset.knowledgeName }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="分段模式">
|
|
{{ descriptions.dataset.segmentedMode | filterSegmentedMode }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="上传时间">
|
|
{{ descriptions.createdDate }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="任务状态">
|
|
{{ descriptions.documentStatus | filterDocumentStatus }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="上传用户">
|
|
{{ descriptions.createdUser }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="高级模式">
|
|
{{ descriptions.documentSource ? '是' : '否' }}
|
|
</el-descriptions-item>
|
|
<el-descriptions-item label="任务号">
|
|
{{ descriptions.datasetId }}
|
|
</el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-card>
|
|
</div>
|
|
|
|
<!-- 屏蔽规则内容 -->
|
|
<!-- <el-divider></el-divider>
|
|
|
|
<div class="segment-info">
|
|
<div class="segment-header">
|
|
<h4>分段规则</h4>
|
|
</div>
|
|
<div class="rule-card">
|
|
<div class="rule-item">
|
|
<h5>是否使用预处理:</h5>
|
|
<span>{{ descriptions.usePreProcess | filterUseMineru }}</span>
|
|
</div>
|
|
<div class="rule-item">
|
|
<h5>是否使用OCR协助处理:</h5>
|
|
<span>{{ descriptions.useOcr | filterUseMineru }}</span>
|
|
</div>
|
|
<div class="rule-item">
|
|
<h5>知识拆分规则:</h5>
|
|
<span v-if="!documentDetail.splitRules">
|
|
-
|
|
</span>
|
|
<div v-else class="flex" style="flex-wrap: wrap">
|
|
<div v-for="item in documentDetail.splitRules" :key="item.id" class="rule-detail-item">
|
|
<div>
|
|
<p class="rule-label">样式</p>
|
|
<span class="rule-value">{{ item.titleLevel }}</span>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">关键词</p>
|
|
<span class="rule-value">{{ item.ruleRegex }}</span>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">备注</p>
|
|
<span class="rule-value">{{ item.description }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="rule-item">
|
|
<h5>知识题词规则:</h5>
|
|
<span v-if="!documentDetail.extractRules">
|
|
-
|
|
</span>
|
|
<div v-else class="flex" style="flex-wrap: wrap">
|
|
<div v-for="item in documentDetail.extractRules" :key="item.id" class="rule-detail-item">
|
|
<div>
|
|
<p class="rule-label">属性</p>
|
|
<span class="rule-value">{{ item.attribute }}</span>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">属性描述</p>
|
|
<span class="rule-value">{{ item.attributeDesc }}</span>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">关键词</p>
|
|
<span class="rule-value">{{ item.keyword }}</span>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">关键词示例</p>
|
|
<el-tooltip class="item" effect="dark" :content="item.example" placement="top">
|
|
<p class="rule-value">{{ item.example }}</p>
|
|
</el-tooltip>
|
|
</div>
|
|
<div>
|
|
<p class="rule-label">提示词</p>
|
|
<el-tooltip class="item" effect="dark" :content="item.prompt" placement="top">
|
|
<p class="rule-value">{{ item.prompt }}</p>
|
|
</el-tooltip>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div> -->
|
|
|
|
<section style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
|
|
<el-card shadow="none">
|
|
<!-- 分段内容 -->
|
|
<div class="segment-content-container">
|
|
<div class="segment-header mb15">
|
|
<div class="segment-summary">
|
|
<span
|
|
>{{
|
|
descriptions.data ? descriptions.data.length : 0
|
|
}}个分段</span
|
|
>
|
|
</div>
|
|
</div>
|
|
<text-model
|
|
v-if="descriptions.doc_form === 'text_model'"
|
|
:descriptions="descriptions"
|
|
:documentDetail="documentDetail"
|
|
:activeSegment="activeSegment"
|
|
/>
|
|
<q-a-model
|
|
v-else-if="descriptions.doc_form === 'qa_model'"
|
|
:descriptions="descriptions"
|
|
:documentDetail="documentDetail"
|
|
:activeSegment="activeSegment"
|
|
/>
|
|
</div>
|
|
</el-card>
|
|
<!-- 文件展示 -->
|
|
<el-card shadow="none">
|
|
<render-file :id="descriptions.id" />
|
|
</el-card>
|
|
</section>
|
|
</el-drawer>
|
|
</template>
|
|
|
|
<script>
|
|
import TextModel from './TextModel.vue'
|
|
import QAModel from './QAModel.vue'
|
|
import {
|
|
documentSourceOptions,
|
|
segmentedModeOptionsMap
|
|
} from '@/assets/js/utils/utilOptions'
|
|
import RenderFile from '@/components/RenderFile/Index.vue'
|
|
|
|
export default {
|
|
components: { TextModel, QAModel, RenderFile },
|
|
props: {
|
|
visible: Boolean,
|
|
descriptions: {
|
|
type: Object,
|
|
default: () => ({ data: [] })
|
|
},
|
|
documentDetail: {
|
|
type: Object,
|
|
default: () => ({})
|
|
},
|
|
activeSegment: {
|
|
type: Number,
|
|
default: 0
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
localActiveSegment: this.activeSegment,
|
|
documentSourceOptions
|
|
}
|
|
},
|
|
watch: {
|
|
activeSegment(newVal) {
|
|
this.localActiveSegment = newVal
|
|
},
|
|
// 深度监听descriptions变化
|
|
descriptions: {
|
|
handler(newVal) {
|
|
// 触发重新渲染的逻辑
|
|
this.$nextTick(() => {
|
|
this.localActiveSegment = 0 // 重置激活分段
|
|
this.$forceUpdate() // 强制刷新(仅在必要情况使用)
|
|
})
|
|
},
|
|
deep: true, // 必须开启深度监听
|
|
immediate: true // 初始化立即执行
|
|
}
|
|
},
|
|
filters: {
|
|
filterDocumentStatus(val) {
|
|
switch (val) {
|
|
case -1:
|
|
return '上传中'
|
|
case 0:
|
|
return '进行中'
|
|
case 1:
|
|
return '完成'
|
|
default:
|
|
return ''
|
|
}
|
|
},
|
|
filterSegmentedMode(val, simpleDesc = false) {
|
|
switch (val) {
|
|
case 0:
|
|
return simpleDesc ? '通用' : '通用分段模式'
|
|
case 1:
|
|
return simpleDesc ? 'Q&A' : ' Q&A分段模式'
|
|
default:
|
|
return ''
|
|
}
|
|
},
|
|
/**
|
|
* 是否使用预处理
|
|
* @param { number } val - 预处理状态
|
|
* @return { string } 预处理状态
|
|
*/
|
|
filterUseMineru(val) {
|
|
let item = segmentedModeOptionsMap.find(
|
|
item => item.value === String(val)
|
|
)
|
|
return item ? item.label : '否'
|
|
}
|
|
},
|
|
methods: {
|
|
// 获取文档来源标签
|
|
getDocumentSourceLabel(sourceValue) {
|
|
const source = this.documentSourceOptions.find(
|
|
item => item.value === String(sourceValue)
|
|
)
|
|
return source ? source.label : '未知来源'
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.drawer-content {
|
|
padding-bottom: 10px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.file-header {
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
|
|
.file-icon {
|
|
font-size: 36px;
|
|
margin-right: 15px;
|
|
color: #409eff;
|
|
}
|
|
|
|
.file-info {
|
|
h3 {
|
|
margin: 0 0 10px 0;
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
}
|
|
}
|
|
}
|
|
|
|
.segment-info {
|
|
margin-top: 20px;
|
|
padding: 15px;
|
|
background: #f5f7fa;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
|
|
.segment-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
|
|
h4 {
|
|
margin: 0;
|
|
font-size: 18px;
|
|
color: #333;
|
|
}
|
|
}
|
|
|
|
.rule-card {
|
|
//background: #fff;
|
|
//border-radius: 4px;
|
|
//padding: 15px;
|
|
//box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
|
|
|
|
.rule-item {
|
|
margin-bottom: 12px;
|
|
|
|
h5 {
|
|
display: inline-block;
|
|
margin: 0 8px 0 0;
|
|
font-weight: bold;
|
|
color: #666;
|
|
}
|
|
|
|
&:last-child {
|
|
margin-bottom: 0;
|
|
}
|
|
}
|
|
|
|
.rule-detail-item {
|
|
margin-top: 8px;
|
|
padding: 10px;
|
|
background: #f9f9f9;
|
|
border-radius: 8px;
|
|
border: 1px solid #e0e0e0;
|
|
margin-right: 10px;
|
|
|
|
div {
|
|
display: flex;
|
|
}
|
|
|
|
p {
|
|
margin: 5px 0;
|
|
}
|
|
|
|
.rule-label {
|
|
font-size: 14px;
|
|
color: #606266;
|
|
margin-bottom: 10px;
|
|
width: 100px;
|
|
}
|
|
|
|
.rule-value {
|
|
font-size: 14px;
|
|
color: #606266;
|
|
font-weight: 500;
|
|
margin-left: 15px;
|
|
width: 200px;
|
|
display: inline-block;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.segment-content-container {
|
|
margin-top: 20px;
|
|
}
|
|
|
|
.segment-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 15px;
|
|
|
|
h4 {
|
|
margin: 0;
|
|
font-size: 16px;
|
|
}
|
|
|
|
.segment-summary {
|
|
color: #606266;
|
|
}
|
|
}
|
|
</style>
|