Files
ebiz-ai-knowledge-manage/src/views/knowledge/detail/components/documentDetail/DocumentDrawer.vue
du.meimei b0c0446f52 feat(layout): 登录登出及菜单权限处理
- 重构了侧边栏菜单的渲染逻辑,支持多级菜单
-优化了菜单项的样式和布局,提高了可读性和美观性- 增加了菜单项的点击事件处理,实现了菜单的动态展开和收缩
-调整了菜单项的路径处理方式,支持动态生成菜单路径- 优化了菜单项的激活状态管理,提高了用户体验
2025-04-24 15:32:31 +08:00

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>