扩展目录

This commit is contained in:
wu.jifen
2025-07-10 17:21:08 +08:00
parent 26892f7a7e
commit c7d432f6d5
5 changed files with 601 additions and 8 deletions

View File

@@ -0,0 +1,58 @@
import request from '@/assets/js/utils/request'
import getUrl from '@/assets/js/utils/get-url'
//单一目录详情
export function getDirectoryById(params) {
return request({
url: getUrl('/directoryEx/query'),
method: 'get',
params: params,
noLoading: true
})
}
// 目录内容修改
export function directoryUpdate(data) {
return request({
url: getUrl('/directoryEx/update'),
method: 'post',
data,
noLoading: true
})
}
// 目录新增
export function directoryCreate(data) {
return request({
url: getUrl('/directoryEx/create'),
method: 'post',
data
})
}
// 目录删除
export function directoryDelete(data) {
return request({
url: getUrl(`/directoryEx/delete`),
method: 'post',
data
})
}
// 获取目录树
export function getDirectoryTree(params) {
return request({
url: getUrl(`/directoryEx/getDirectoryTree`),
method: 'post',
params: params
})
}
// 同步目录元数据
export function markedMetadata(params) {
return request({
url: getUrl(`/directoryMetadataEx/markedMetadata`),
method: 'post',
params: params
})
}

View File

@@ -41,6 +41,7 @@
<el-radio-group v-model="model.segmentedMode">
<el-radio :label="0">通用分段模式</el-radio>
<el-radio :label="1">Q&A分段模式</el-radio>
<el-radio :label="2">目录型知识库</el-radio>
</el-radio-group>
</el-form-item>
@@ -123,7 +124,8 @@ export default {
id: null,
imageType: 'upload-img',
image: null,
visibleRange: 0
visibleRange: 0,
useDirectory: 0
},
rules: {
name: [
@@ -162,7 +164,8 @@ export default {
userIds: [],
image: null,
imageType: 'upload-img',
id: null
id: null,
useDirectory: 0
}
}
})
@@ -253,7 +256,8 @@ export default {
userIds: [],
image: null,
imageType: 'upload-img',
id: null
id: null,
useDirectory: 0
}
},
@@ -262,6 +266,10 @@ export default {
if (!valid) {
return false
}
if (this.model.segmentedMode === 2) {
this.model.segmentedMode = 0
this.model.useDirectory = 1
}
// this.model.visibleRange = 0/**/
;(!this.datasetId ? datasetCreate : datasetUpdate)(this.model).then(

View File

@@ -312,6 +312,9 @@ export default {
formData.append('file', file)
})
formData.append('datasetId', this.form.datasetId)
if (this.$route.query.directoryId) {
formData.append('directoryId', this.$route.query.directoryId)
}
let api =
this.form.radio === '1' ? uploadFileByCustom : uploadFileByTemplate
if (this.form.radio === '1') {

View File

@@ -115,7 +115,7 @@
</el-button>
</div>
</div>
<div class="mt20 card-body">
<div class="mt20 card-body" v-if="useDirectory !== 1">
<el-empty v-if="!hasList">
<div class="mt20">
<el-button
@@ -205,6 +205,29 @@
></r-table>
</div>
</div>
<div v-else>
<div style="margin-bottom: 12px; display: flex; gap: 8px;">
<el-button type="primary" size="small" @click="openCreateDialog()"
>新建根目录</el-button
>
<el-button type="primary" size="small" @click="syncDirMetadata()"
>同步目录元数据</el-button
>
</div>
<r-table
:columns="dirColumns"
:data="treeData"
:deletion="false"
:total="treeData.length"
/>
<directory-form
:visible.sync="dialogVisible"
:parentId="currentParentId"
:datasetId="$route.query.datasetId"
:directoryId="currentDirectoryId"
@update:visible="onDialogClose"
/>
</div>
<document-drawer
:visible.sync="drawer"
:descriptions="descriptions"
@@ -281,6 +304,12 @@ import MetaData from '@/views/knowledge/detail/components/metaData/Index.vue'
import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue'
import SearchSetting from '@/views/knowledge/detail/components/SearchSetting/Index.vue'
import { displayStatus } from '@/assets/js/utils/utilOptions'
import DirectoryForm from '@/views/knowledge/directory/directoryForm.vue'
import {
directoryDelete,
getDirectoryTree,
markedMetadata
} from '@/api/directory'
export default {
name: 'index',
// 父子组件共享
@@ -336,12 +365,18 @@ export default {
documentDetail: {
splitRules: '',
extractRules: ''
}
},
useDirectory: 0,
treeData: [],
dialogVisible: false,
currentParentId: '',
currentDirectoryId: ''
}
},
props: {},
watch: {},
components: {
DirectoryForm,
SearchSetting,
MetaData,
hitTest,
@@ -385,13 +420,14 @@ export default {
},
// 跳转去上传文件
jumpAddKnowledge() {
jumpAddKnowledge(directory) {
sessionStorage.removeItem('documentId')
let { datasetId } = this.$route.query
this.$router.push({
path: '/knowledge/detail/create',
query: {
datasetId: datasetId
datasetId: datasetId,
directoryId: directory ? directory.id : ''
}
})
},
@@ -419,6 +455,7 @@ export default {
this.knowledgeDesc = res.content.content.description
this.segmentedMode = res.content.content.segmentedMode
this.knowledgeImage = res.content.content.image
this.useDirectory = res.content.content.useDirectory
})
},
@@ -606,7 +643,101 @@ export default {
},
handleRelatedApp(item) {
// console.log(item)
},
// 合并文档到 children并加 type 字段
mergeDocumentsToChildren(node) {
node.type = 'directory'
if (Array.isArray(node.documents) && node.documents.length > 0) {
const docChildren = node.documents.map(doc => ({
...doc,
id: doc.id,
knowledgeName: doc.knowledgeName,
type: 'document',
children: []
}))
node.children = (node.children || []).concat(docChildren)
}
if (Array.isArray(node.children)) {
node.children.forEach(child => {
if (!child.type || child.type !== 'document') {
this.mergeDocumentsToChildren(child)
}
})
}
},
async loadTree() {
getDirectoryTree({ datasetId: this.$route.query.datasetId }).then(
response => {
const data = response.content.content
data.forEach(node => this.mergeDocumentsToChildren(node))
this.treeData = data
}
)
},
openCreateDialog(parent = null) {
this.currentDirectoryId = ''
this.currentParentId = parent ? parent.id : ''
this.dialogVisible = true
},
syncDirMetadata(parent = null) {
markedMetadata({ datasetId: this.$route.query.datasetId }).then(res => {
if (res) {
this.$message({
type: 'success',
message: '同步成功!'
})
}
})
},
onDialogClose(val) {
this.dialogVisible = val
if (!val) {
this.loadTree()
}
},
openEditDialog(directory) {
// 这里可以弹出编辑目录的表单,具体实现根据你的 DirectoryForm 组件而定
// 示例:
this.currentParentId = ''
this.currentDirectoryId = directory.id
this.dialogVisible = true
// 你可以根据需要传递更多编辑相关的数据
},
deleteDirectory(row) {
let ids = []
ids.push(row.id)
this.$messageBox(
() => {
directoryDelete(ids).then(res => {
if (res) {
this.$message({
type: 'success',
message: '删除成功!'
})
this.loadTree()
}
})
},
'是否确认删除' + row.name + '目录?',
'warning'
)
}
// /**
// * 跳转到上传知识页面
// * @param directory 目录节点对象,可选
// */
// jumpAddKnowledge(directory) {
// sessionStorage.removeItem('documentId')
// let { datasetId } = this.$route.query
// // 可根据需要将目录id传递给上传页面
// this.$router.push({
// path: '/knowledge/detail/create',
// query: {
// datasetId: datasetId,
// directoryId: directory ? directory.id : undefined
// }
// })
// }
},
filters: {
filterSegmentedMode(val) {
@@ -630,7 +761,11 @@ export default {
async mounted() {
this.getKnowledgeDetail()
// 获取知识库文件列表
if (this.useDirectory === 1) {
this.loadTree()
} else {
this.getKnowledgeFiledList()
}
// 获取用户下拉列表
this.getUserData()
@@ -835,6 +970,240 @@ export default {
}
}
]
},
dirColumns() {
return [
{
prop: 'name',
key: '名称'
// render: (h, params) => params.row.type === 'directory' ? params.row.name : ''
},
{
key: '知识文件名称',
prop: 'knowledgeName'
},
{
key: '知识文件来源',
prop: 'documentSource',
render: (h, params) => {
if (params.row.type !== 'document') {
return ''
}
let text = documentSourceOptions.find(
item => item.value === String(params.row.documentSource)
).label
return h(
'div',
{
class: 'flex align-items-c'
},
[
h(
'span',
{
class: 'mr5',
style: {
// display: params.row.useMineru === 1 ? '' : 'none',
width: '19px',
height: '19px',
fontSize: '13px',
borderRadius: '6px',
textAlign: 'center',
lineHeight: '19px',
color: '#fff',
background:
params.row.useMineru === 1 ? '#4f47f5' : 'unset'
}
},
params.row.useMineru === 1 ? '预' : ''
),
h('span', {}, text)
]
)
}
},
{
key: '状态',
prop: 'statusLabel'
},
{
key: '召回次数',
prop: 'hitCount',
render: (h, params) => {
return h('div', !params.row.hitCount ? '0' : params.row.hitCount)
}
},
{
key: '上传用户',
prop: 'createdUser',
width: '100',
render: (h, params) => {
return h(
'div',
!params.row.createdUser ? '-' : params.row.createdUser
)
}
},
{
key: '上传时间',
prop: 'createdDate',
width: '100'
},
{
key: '操作',
prop: 'knowledgeDesc',
isRedraw: true,
render: (h, params) => {
return h('div', [
// 目录类型按钮
params.row.type === 'directory'
? h('el-button', {
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-folder-add',
title: '创建子目录'
},
on: {
click: () => this.openCreateDialog(params.row)
}
})
: '',
params.row.type === 'directory'
? h('el-button', {
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-edit',
title: '编辑'
},
on: {
click: () => this.openEditDialog(params.row)
}
})
: '',
params.row.type === 'directory'
? h('el-button', {
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-delete',
title: '删除'
},
on: {
click: () => this.deleteDirectory(params.row)
}
})
: '',
// 文档类型按钮
params.row.type === 'document'
? h('el-button', {
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-tickets',
title: '查看详情'
},
on: {
click: () => this.viewDocumentDetail(params.row)
}
})
: '',
params.row.type === 'document'
? h(
'el-button',
{
class: 'floatSpan',
props: {
type: 'danger',
size: 'mini',
icon: 'el-icon-delete',
title: '删除'
},
on: {
click: () => this.deleteKnowledge(params.row)
}
}
// '删除'
)
: '',
params.row.type === 'document'
? h(
'el-button',
{
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-help',
title: '添加元数据',
disabled: params.row.documentStatus !== 1
},
on: {
click: () => this.handleAddMetadata(params.row)
}
}
// '标注元数据'
)
: '',
params.row.type === 'document'
? h(
'el-button',
{
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-download',
title: '下载原文件'
},
on: {
click: () => this.handleDownload(params.row)
}
}
// '标注元数据'
)
: '',
params.row.optStatus < 4 && params.row.type === 'document'
? h(
'el-button',
{
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-video-play',
title: '继续处理'
},
on: {
click: () => this.jumpToUpload(params)
}
}
// '文件拆分处理'
)
: '',
params.row.type === 'directory'
? h('el-button', {
class: 'floatSpan',
props: {
type: 'primary',
size: 'mini',
icon: 'el-icon-plus',
title: '上传知识'
},
on: {
click: () => this.jumpAddKnowledge(params.row)
}
})
: ''
])
}
}
]
}
}
}

View File

@@ -0,0 +1,155 @@
<template>
<r-dialog
:visible.sync="visible"
:title="(directoryId ? `修改` : `新增`) + '目录'"
destroy-on-close
width="500px"
>
<div slot="header" class="clearfix">
<h3>{{ directoryId ? '修改' : '新增' }}</h3>
</div>
<el-row>
<el-col>
<el-form
:model="model"
ref="model"
label-width="120px"
:rules="rules"
label-position="top"
>
<el-form-item label="目录名称:" prop="name">
<el-input v-model="model.name" size="medium"></el-input>
</el-form-item>
<!-- 可见范围-->
<el-form-item label="可见权限:" prop="visibleRange">
<otherSelect :model="model"></otherSelect>
</el-form-item>
</el-form>
</el-col>
</el-row>
<div slot="footer" :span="24">
<el-button
size="medium"
@click="resetForm(), $emit('update:visible', false)"
>取消</el-button
>
<el-button type="primary" size="medium" @click="save">
{{ directoryId ? '保存' : '创建' }}
</el-button>
</div>
</r-dialog>
</template>
<script>
import otherSelect from '@/views/knowledge/detail/components/otherSelect/otherIndex.vue'
import {
directoryCreate,
directoryUpdate,
getDirectoryById
} from '@/api/directory'
export default {
name: 'knowledgeForm',
components: { otherSelect },
props: {
visible: {
type: Boolean,
default: false
},
directoryId: {
type: String,
default: ''
},
parentId: {
type: String,
default: ''
},
datasetId: {
type: String,
default: ''
}
},
watch: {
visible: {
handler(val) {
this.$nextTick(() => {
this.$emit('update:visible', val)
if (this.directoryId) {
this.getDetail()
} else {
this.model = {
name: '',
visibleRange: 0,
userIds: [],
id: null,
parentId: this.parentId,
datasetId: this.datasetId
}
}
})
},
immediate: true
}
},
data() {
return {
model: {
name: '',
id: null,
visibleRange: 0,
userIds: [],
parentId: '',
datasetId: ''
},
rules: {
name: [{ required: true, message: '请输入目录名称', trigger: 'blur' }],
visibleRange: [{ required: true, message: '请选择可见权限' }]
}
}
},
methods: {
getDetail() {
if (!this.directoryId) return
getDirectoryById({ directoryId: this.directoryId }).then(res => {
this.model = {
...res.content.content,
visibleRange: res.content.content.visibleRange
? res.content.content.visibleRange
: 0
}
})
},
resetForm() {
this.model = {
name: '',
visibleRange: '',
userIds: [],
id: null,
parentId: '',
datasetId: '',
directoryId: ''
}
},
save() {
this.$refs.model.validate(valid => {
if (!valid) {
return false
}
// this.model.visibleRange = 0/**/
;(!this.directoryId ? directoryCreate : directoryUpdate)(
this.model
).then(res => {
if (res) {
// 添加保存成功的提示
this.$message.success('保存成功')
this.$emit('update:visible', false)
this.resetForm()
}
})
})
}
}
}
</script>