Merge branch 'dev' into poc/bpic

This commit is contained in:
陈昱达
2025-05-26 13:29:49 +08:00
48 changed files with 1853 additions and 711 deletions

1
.env
View File

@@ -4,3 +4,4 @@ NODE_ENV = 'dev' // 如果是生产环境请记得切换为production
# flag # flag
VUE_APP_FLAG='dev' VUE_APP_FLAG='dev'
VUE_APP_ADMIN='http://39.104.123.254:7195' VUE_APP_ADMIN='http://39.104.123.254:7195'
VUE_APP_DOCS='http://39.104.123.254:7546/'

View File

@@ -265,8 +265,9 @@ export function uploadFileByTemplate(data) {
export function datasetQuerySegments(data) { export function datasetQuerySegments(data) {
return request({ return request({
url: getUrl(`/datasetDocumentEx/querySegments`), url: getUrl(`/datasetDocumentEx/querySegments`),
method: 'get', method: 'post',
params: data data,
noLoading: true
}) })
} }
@@ -421,6 +422,7 @@ export function uploadImage(data) {
}) })
} }
// 分段编辑
export function segmentUpdate(data) { export function segmentUpdate(data) {
return request({ return request({
url: getUrl(`/datasetDocumentEx/segment/update`), url: getUrl(`/datasetDocumentEx/segment/update`),
@@ -428,3 +430,63 @@ export function segmentUpdate(data) {
data data
}) })
} }
// 分段删除
export function segmentDelete(data) {
return request({
url: getUrl(`/datasetDocumentEx/segment/delete`),
method: 'get',
params: data
})
}
// 新增分段
export function segmentCreate(data) {
return request({
url: getUrl(`/datasetDocumentEx/segment/create`),
method: 'post',
data
})
}
// 分段模板
export function segmentTemplate(model) {
// model 分别时 qa general
return getUrl(`/template/download/${model}`)
}
// 导入分段
export function importSegment(data) {
return request({
url: getUrl(`/datasetDocumentEx/segment/batchImport`),
method: 'post',
data
})
}
// 导出分段
export function exportSegment(data) {
return getUrl(
`/datasetDocumentEx/segment/export?documentId=${data.documentId}`
)
}
// 分段启用禁用
export function switchStatus(data) {
return request({
url: getUrl(`/datasetDocumentEx/segment/switchStatus`),
method: 'post',
data,
noLoading: true
})
}
// 知识库关联智能体
export function relatedApps(data) {
return request({
url: getUrl(`/datasetsEx/relatedApps`),
method: 'get',
params: data
})
}
// 下载知识原文件
export function downloadOriginalFile(data) {
return getUrl(`/datasetDocumentEx/download/original_file?documentId=` + data)
}

View File

@@ -85,7 +85,8 @@ const agentEdit = data => {
const getAccessToken = data => { const getAccessToken = data => {
return request({ return request({
url: getUrl('/third/access_token'), url: getUrl('/third/access_token'),
method: 'get' method: 'get',
noLoading: true
}) })
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 906 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,22 @@
.el-dropdown-menu__item:focus,
.el-dropdown-menu__item:not(.is-disabled):hover {
background-color: $--color-primary;
color: #fff;
}
.el-dropdown-link {
cursor: pointer;
color: $--color-primary;
}
//
//.el-button {
// &.el-dropdown__caret-button {
// padding-left: 5px;
// padding-right: 5px;
// }
//}
.el-dropdown {
& .el-dropdown__caret-button {
padding-left: 5px;
padding-right: 5px;
}
}

View File

@@ -346,3 +346,19 @@
color: $--color-primary; color: $--color-primary;
} }
} }
.el-input-group__append .el-button,
.el-input-group__append .el-select,
.el-input-group__prepend .el-button,
.el-input-group__prepend .el-select {
margin: -10px 0;
}
.el-input-group__append,
.el-input-group__prepend {
background: #fff;
border-color: #fff;
padding: 0;
}
.el-select-dropdown.is-multiple .el-select-dropdown__item.selected {
color: $--color-primary;
}

View File

@@ -72,3 +72,34 @@
// //
//} //}
//.el-pagination.is-background .el-pager li:not(.disabled):hover //.el-pagination.is-background .el-pager li:not(.disabled):hover
.tableBtn {
padding: 5px;
&.is-plain {
&:hover {
background: $--color-primary;
color: #fff;
}
}
&.el-button--danger {
&.is-plain:focus,
&.is-plain:hover {
color: #fff;
background: #ff1a1a;
border-color: #ff1a1a;
}
}
}
.el-pagination__sizes {
& .el-select {
& .el-input {
&.el-input--mini {
& .el-input__inner {
height: 22px;
line-height: 22px;
}
}
}
}
}

View File

@@ -10,6 +10,7 @@
@import 'renderSass/message'; @import 'renderSass/message';
@import 'renderSass/upload'; @import 'renderSass/upload';
@import 'renderSass/slider'; @import 'renderSass/slider';
@import 'renderSass/drop';
html, html,
body, body,

View File

@@ -9,6 +9,9 @@
:closeOnClickModal="closeOnClickModal" :closeOnClickModal="closeOnClickModal"
:close-on-press-escape="closeOnPressEscape" :close-on-press-escape="closeOnPressEscape"
> >
<div slot="title">
<slot name="title">{{ title }}</slot>
</div>
<div class="render-dialog-body"> <div class="render-dialog-body">
<slot name="default"></slot> <slot name="default"></slot>
</div> </div>

View File

@@ -1,11 +1,12 @@
<template> <template>
<div style="height: 100%;"> <div style="height: 100%;">
<div class="flex align-items-c justify-content-b mb10"> <div class="flex align-items-c justify-content-b mb10">
<div class="fileName flex align-items-c"> <div class="fileName flex align-items-c ">
<svg-icon <svg-icon
icon-class="pdf" icon-class="pdf"
style="width: 20px;height: 20px" style="width: 20px;height: 20px"
class-name="mr10" class-name="mr10"
v-if='showPdf'
/> />
{{ fileName }} {{ fileName }}
</div> </div>
@@ -52,7 +53,7 @@
element-loading-text="读取文档中..." element-loading-text="读取文档中..."
> >
<iframe <iframe
v-if="isShowPdf" v-if="showPdf"
id="iframe" id="iframe"
ref="iframe" ref="iframe"
:src=" :src="
@@ -69,11 +70,35 @@
element-loading-text="正在识别中..." element-loading-text="正在识别中..."
> >
<div class="el-card ebiz-pdf" style="height: 100%;overflow: hidden"> <div class="el-card ebiz-pdf" style="height: 100%;overflow: hidden">
<div style="height: 47px;width: 100%;text-align: center;">
<div class="flex align-items-c justify-content-c miner-navbar fs14">
<el-icon
class="el-icon-caret-left cursor-pointer"
@click.native="changePageDown('down')"
>
</el-icon>
<input
style="width: 50px;text-align: center"
v-model="copyValue"
:min="0"
class="fs13 miner-input el-input"
@blur="blursChange"
></input>
<span class="mh5">/ </span>
<span>{{ mdJsons.length }}</span>
<el-icon
class="el-icon-caret-right cursor-pointer"
@click.native="changePageUp('up')"
>
></el-icon
>
</div>
</div>
<div ref="scrollView" v-show="tab === '0'"> <div ref="scrollView" v-show="tab === '0'">
<div <div
class="view-body" class="view-body"
id="viewBody" id="viewBody"
style="height:calc(100vh - 180px);overflow-y: scroll;overflow-x:hidden" style="height:calc(100vh - 227px);overflow-y: scroll;overflow-x:hidden"
v-html="markdownHtml" v-html="markdownHtml"
></div> ></div>
</div> </div>
@@ -122,9 +147,11 @@ export default {
name: 'index', name: 'index',
data() { data() {
return { return {
copyValue: 1,
mdJsons: {}, mdJsons: {},
finishenEnd: false, finishenEnd: false,
fileName: '', fileName: '',
showPdf:true,
recordId: '', //pdf 记录的id recordId: '', //pdf 记录的id
endEmit: false, endEmit: false,
tab: '0', tab: '0',
@@ -278,8 +305,6 @@ export default {
page: { page: {
handler(newVal, oldVal) { handler(newVal, oldVal) {
if (newVal) { if (newVal) {
// this.changePage(newVal, this.tab)
this.getPDFDetailMarkDown() this.getPDFDetailMarkDown()
} }
} }
@@ -314,19 +339,77 @@ export default {
}, },
//changePage //changePage
// 分页发生改变时 // 分页发生改变时
changePage(page) { changePage(type) {
let documentId = document.getElementById(`view-code-${page - 1}`) // if (this.page <= 0 || this.page >= this.mdJsons.length) {
let viewBody = document.getElementById('viewBody') // return false
if (this.tab === '1') { // }
documentId = document.getElementById(`ebiz-code-${page - 1}`) //
viewBody = document.getElementById('md-editor') // switch (type) {
// case 'down':
// this.page -= 1
// break
// case 'up':
// this.page += 1
// break
// },
//
// let documentId = document.getElementById(`view-code-${page - 1}`)
// let viewBody = document.getElementById('viewBody')
// if (this.tab === '1') {
// documentId = document.getElementById(`ebiz-code-${page - 1}`)
// viewBody = document.getElementById('md-editor')
// }
// if (documentId) {
// viewBody.scrollTo({
// top: documentId.offsetTop - 130,
// behavior: 'smooth'
// })
// }
},
changePageDown(type) {
if (this.page <= 0) {
return false
} }
if (documentId) {
viewBody.scrollTo({ switch (type) {
top: documentId.offsetTop - 130, case 'down':
behavior: 'smooth' this.page -= 1
}) break
case 'up':
this.page += 1
break
} }
this.copyValue = this.page
},
blursChange(e) {
if (!e.target.value.trim()) {
this.copyValue = this.page
}
if (e.target.value < 0) {
this.copyValue = this.page
}
if (e.target.value > this.mdJsons.length) {
this.copyValue = this.page
}
this.page = this.copyValue
},
changePageUp(type) {
if (this.page >= this.mdJsons.length) {
return false
}
switch (type) {
case 'down':
this.page -= 1
break
case 'up':
this.page += 1
break
}
this.copyValue = this.page
}, },
//重新识别表格 //重新识别表格
retryMinerImage(chooseItem, loading, tableElement) { retryMinerImage(chooseItem, loading, tableElement) {
@@ -580,7 +663,9 @@ export default {
JSON.parse(JSON.stringify(res.content.content.pdf_info)) JSON.parse(JSON.stringify(res.content.content.pdf_info))
) )
// this.$refs.iframe 重新刷新iframe // this.$refs.iframe 重新刷新iframe
this.$refs.iframe.contentWindow.location.reload() if( this.$refs.iframe){
this.$refs.iframe.contentWindow.location.reload()
}
this.getPDFDetailMarkDown() this.getPDFDetailMarkDown()
}) })
@@ -727,6 +812,11 @@ export default {
if (res) { if (res) {
this.mdPges = res.content.content.pages this.mdPges = res.content.content.pages
this.fileName = res.content.content.name this.fileName = res.content.content.name
// 隐藏非pdf文件
this.showPdf = this.fileName.indexOf('.pdf') > 0;
this.recordId = res.content.content.recordId this.recordId = res.content.content.recordId
switch (res.content.content.status) { switch (res.content.content.status) {
case 0: case 0:
@@ -841,6 +931,21 @@ export default {
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.miner-navbar {
margin-top: 11px;
border-bottom: 1px solid #ebeef5;
padding-bottom: 10px;
gap: 5px;
& .miner-input {
height: 20px ;
line-height: 20px;
border: 1px solid #BBBBBC;
outline:none;
border-radius: 2px;
}
}
.lineHeight25 { .lineHeight25 {
line-height: 25px; line-height: 25px;
} }

View File

@@ -17,7 +17,7 @@ const RenderSlot = {
'el-tooltip', 'el-tooltip',
{ {
props: { props: {
placement: 'left', placement: 'bottom',
content: first[0].data.props.title content: first[0].data.props.title
// effect: 'light' // effect: 'light'
} }

View File

@@ -58,13 +58,13 @@
class="normal-button" class="normal-button"
:disabled="disabled" :disabled="disabled"
icon="el-icon-delete" icon="el-icon-delete"
@click="del(scope.row, scope.$index)" @click.stop="del(scope.row, scope.$index)"
></el-button> ></el-button>
<el-button <el-button
class="normal-button" class="normal-button"
icon="el-icon-edit-outline" icon="el-icon-edit-outline"
:disabled="disabled" :disabled="disabled"
@click="edit(scope.row, scope.$index)" @click.stop="edit(scope.row, scope.$index)"
></el-button> ></el-button>
</div> </div>
<!--如果渲染的是selfBtn--> <!--如果渲染的是selfBtn-->
@@ -75,10 +75,11 @@
:disabled=" :disabled="
item.disabled !== undefined ? item.disabled : disabled item.disabled !== undefined ? item.disabled : disabled
" "
:class="item.class"
:type="btn.type ? btn.type : 'primary'" :type="btn.type ? btn.type : 'primary'"
:size="btn.size ? btn.size : 'mini'" :size="btn.size ? btn.size : 'mini'"
:key="btnIndex" :key="btnIndex"
@click="handlerMethods(scope.row, scope.$index, btn)" @click.stop="handlerMethods(scope.row, scope.$index, btn)"
:label="btn.name" :label="btn.name"
> >
{{ btn.name }} {{ btn.name }}
@@ -133,7 +134,7 @@
<el-button <el-button
type="primary" type="primary"
plain plain
@click=" @click.stop="
e => { e => {
addRow(scope.row, scope.$index) addRow(scope.row, scope.$index)
} }
@@ -147,7 +148,7 @@
<el-button <el-button
type="danger" type="danger"
plain plain
@click=" @click.stop="
e => { e => {
delRow(scope.row, scope.$index) delRow(scope.row, scope.$index)
} }

View File

@@ -1,6 +1,11 @@
<script> <script>
import { DIFY_URL } from '@/config/base-url' import { DIFY_URL } from '@/config/base-url'
import { agentAdd, agentDetail, agentEdit } from '@/api/intelligent-agent/list' import {
agentAdd,
agentDetail,
agentEdit,
getAccessToken
} from '@/api/intelligent-agent/list'
export default { export default {
name: 'workflow', name: 'workflow',
props: { props: {
@@ -11,6 +16,7 @@ export default {
}, },
data() { data() {
return { return {
timer: null,
agentDetail: {}, agentDetail: {},
resetName: '', resetName: '',
@@ -76,6 +82,15 @@ export default {
this.worker.instance.postMessage('init-worker', [ this.worker.instance.postMessage('init-worker', [
this.messageChannel.instance.port2 this.messageChannel.instance.port2
]) ])
// 每 5 分钟执行一次
// ✅ 先清理已有 timer防止重复创建
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
this.timer = setInterval(() => {
this.initTokenRefresh()
}, 1000 * 60 * 5)
}, },
destroyed() { destroyed() {
// 组件销毁时清除 web worker 和 messageChannel // 组件销毁时清除 web worker 和 messageChannel
@@ -83,6 +98,10 @@ export default {
this.worker.instance = void 0 this.worker.instance = void 0
this.messageChannel.instance.port1.close() this.messageChannel.instance.port1.close()
this.messageChannel.instance = void 0 this.messageChannel.instance = void 0
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
}, },
watch: { watch: {
'$route.query': { '$route.query': {
@@ -96,8 +115,6 @@ export default {
// 当路由参数 id 变化时,更新 dify 的 src // 当路由参数 id 变化时,更新 dify 的 src
if (thirdAppId) { if (thirdAppId) {
console.log(`current params:`, this.agent.params)
this.agent.src = `${DIFY_URL}/app/${thirdAppId}/workflow?${ this.agent.src = `${DIFY_URL}/app/${thirdAppId}/workflow?${
this.params this.params
}` }`
@@ -110,6 +127,21 @@ export default {
} }
}, },
methods: { methods: {
async initTokenRefresh() {
try {
const thirdContent = await getAccessToken()
const { refreshToken, accessToken } = thirdContent.content.content
// if (localStorage.getItem('refresh_token') !== refreshToken) {
localStorage.setItem('refresh_token', refreshToken)
// }
// if (localStorage.getItem('console_token') !== accessToken) {
localStorage.setItem('console_token', accessToken)
// }
} catch (error) {
console.error('Token refresh failed:', error)
}
},
handleAgentLoad() { handleAgentLoad() {
// 把 messageChannel port1 的所有权传递给 iframe // 把 messageChannel port1 的所有权传递给 iframe
this.$refs.agent.contentWindow.postMessage('init-iframe', '*', [ this.$refs.agent.contentWindow.postMessage('init-iframe', '*', [

View File

@@ -6,7 +6,9 @@
<span class="title">你好{{ userInfo.realName }}</span> <span class="title">你好{{ userInfo.realName }}</span>
<div class="subtitle">欢迎使用{{ title }}</div> <div class="subtitle">欢迎使用{{ title }}</div>
<div class="role-info"> <div class="role-info">
当前角色{{ userInfo.roleNames[0] || '未指定' }} 当前角色{{
userInfo.roleNames ? userInfo.roleNames[0] : '未指定'
}}
</div> </div>
</div> </div>
<div class="right-container"> <div class="right-container">
@@ -29,7 +31,7 @@
<span class="card-title">智能体</span> <span class="card-title">智能体</span>
<div class="card-content">智能体管理列表</div> <div class="card-content">智能体管理列表</div>
</div> </div>
<div class="card-item"> <div class="card-item" @click="openTag">
<span class="card-title">操作手册</span> <span class="card-title">操作手册</span>
<div class="card-content">智能管理平台使用手册</div> <div class="card-content">智能管理平台使用手册</div>
</div> </div>
@@ -426,6 +428,9 @@ export default {
this.$router.push({ this.$router.push({
path: url path: url
}) })
},
openTag() {
window.open(process.env.VUE_APP_DOCS)
} }
}, },
computed: { computed: {

View File

@@ -1,11 +1,15 @@
<template> <template>
<div class="navbar"> <div class="navbar">
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> <hamburger
:is-active="sidebar.opened"
class="hamburger-container"
@toggleClick="toggleSideBar"
/>
<breadcrumb class="breadcrumb-container" /> <breadcrumb class="breadcrumb-container" />
<div class="right-menu" v-if="$store.state.settings.sidebarLogo"> <div class="right-menu" v-if="$store.state.settings.sidebarLogo">
<el-dropdown class="avatar-container" trigger="click"> <el-dropdown class="avatar-container" trigger="click" size="medium">
<div class="avatar-wrapper"> <div class="avatar-wrapper">
<el-avatar :size="size" :src="circleUrl" class="user-avatar" /> <el-avatar :size="size" :src="circleUrl" class="user-avatar" />
<i class="el-icon-caret-bottom" /> <i class="el-icon-caret-bottom" />

View File

@@ -4,6 +4,7 @@
<el-dropdown <el-dropdown
class="avatar-container" class="avatar-container"
trigger="click" trigger="click"
size="medium"
placement="top-start" placement="top-start"
> >
<div class="avatar-wrapper"> <div class="avatar-wrapper">

View File

@@ -10,6 +10,7 @@
v-for="item in options" v-for="item in options"
:value="item.value" :value="item.value"
:label="item.label" :label="item.label"
:key="item.value"
></el-option> ></el-option>
</el-select> </el-select>
<div <div

View File

@@ -20,9 +20,24 @@ export default {
} }
} }
}, },
watch: {
'dialog.agent': {
handler(val) {
this.image = val.image
this.imageType = val.imageType
this.background = val.backgroundColor
},
immediate: true,
deep: true
}
},
data() { data() {
return { return {
isImage: '0', isImage: '0',
image: '',
imageType: '',
popover: false, popover: false,
background: '', background: '',
chooseBack: [ chooseBack: [
@@ -79,8 +94,17 @@ export default {
}, },
chooseGround(colors) { chooseGround(colors) {
this.$set(this.dialog.agent, 'backgroundColor', colors) this.background = colors
}, },
saveEmoji() {
this.dialog.agent.image = this.image
this.dialog.agent.imageType = this.imageType
this.$set(this.dialog.agent, 'backgroundColor', this.background)
this.popover = false
},
/** /**
* 提交表单 * 提交表单
*/ */
@@ -104,8 +128,9 @@ export default {
}, },
// 选择emoji // 选择emoji
selectEmoji(e) { selectEmoji(e) {
this.dialog.agent.image = e.data this.image = e.data
this.dialog.agent.imageType = 'emoji' this.imageType = 'emoji'
// this.dialog.agent.imageType = 'emoji'
}, },
// 选择是否是上传图片 // 选择是否是上传图片
changeUploadImage(e) { changeUploadImage(e) {
@@ -129,11 +154,8 @@ export default {
label-position="top" label-position="top"
label-width="80px" label-width="80px"
> >
<div class="flex "> <div class="flex align-items-c ">
<el-form-item label="名称与图标" prop="appName" style="flex:1"> <el-form-item label="名称与图标" prop="imageId" class="mt30">
<el-input v-model="dialog.agent.appName" size="medium" />
</el-form-item>
<el-form-item label="" prop="imageId" class="mt30 ml20">
<el-popover trigger="click" v-model="popover"> <el-popover trigger="click" v-model="popover">
<div style="width: 28vw"> <div style="width: 28vw">
<el-radio-group <el-radio-group
@@ -150,22 +172,34 @@ export default {
<div class="mt10" v-if="isImage === '0'"> <div class="mt10" v-if="isImage === '0'">
<VEmojiPicker @select="selectEmoji" class="emoji " /> <VEmojiPicker @select="selectEmoji" class="emoji " />
<div <div
v-if="dialog.agent.image" v-if="image"
class="flex mt10 back-content justify-content-b" class="flex mt10 back-content justify-content-b"
> >
<template <template
v-for="item in chooseBack" v-for="item in chooseBack"
v-if="dialog.agent.imageType === 'emoji'" v-if="imageType === 'emoji'"
> >
<div <div
class="emoji-background" class="emoji-background"
:style="`background:${item}`" :style="`background:${item}`"
@click="chooseGround(item)" @click="chooseGround(item)"
:class="item === background ? 'activeBack' : ''"
> >
{{ dialog.agent.image }} {{ image }}
</div> </div>
</template> </template>
</div> </div>
<div class="flex align-items-c justify-content-b">
<!-- <el-button size="medium" style="flex:1">取消</el-button>-->
<el-button
@click="saveEmoji"
size="medium"
type="primary"
style="flex:1"
>确认
</el-button>
</div>
</div> </div>
<!-- 图片切割--> <!-- 图片切割-->
@@ -201,12 +235,27 @@ export default {
<div v-if="dialog.agent.imageType === 'emoji'"> <div v-if="dialog.agent.imageType === 'emoji'">
{{ dialog.agent.image }} {{ dialog.agent.image }}
</div> </div>
<div v-else style="width: 100%"> <div
<img :src="dialog.agent.image" alt="" style="width: 100%;" /> v-else-if="dialog.agent.imageType === 'image'"
style="width: 100%;height: 100%;overflow: hidden;border-radius: 8px"
>
<img
v-if="dialog.agent.image"
:src="dialog.agent.image"
alt=""
style="width: 100%;height: 100%"
/>
</div>
<div v-else style="font-size: 30px" class=" fw600 white">
{{ dialog.agent.appName[0] }}
</div> </div>
</div> </div>
</el-popover> </el-popover>
</el-form-item> </el-form-item>
<el-form-item label="" prop="appName" style="flex:1" class="mt60">
<el-input v-model="dialog.agent.appName" size="medium" />
</el-form-item>
</div> </div>
<el-form-item label="选择应用类型" required prop="appType"> <el-form-item label="选择应用类型" required prop="appType">
@@ -272,6 +321,28 @@ export default {
</el-form> </el-form>
</div> </div>
</template> </template>
<style>
.emoji {
width: 100% !important;
height: 100%;
& #Categories {
& .category {
&.active {
border-bottom: 3px solid var(--color-primary);
}
}
}
& #InputSearch {
& .container-search {
& input {
outline: none;
border: 1px solid var(--color-primary);
background: #fff;
}
}
}
}
</style>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/sass/renderSass/theme.scss'; @import '@/assets/sass/renderSass/theme.scss';
@@ -302,27 +373,12 @@ export default {
text-align: center; text-align: center;
//margin-left: 10px; //margin-left: 10px;
margin-bottom: 10px; margin-bottom: 10px;
}
.emoji { &.activeBack {
width: 100% !important; border: 1px dashed #676f83;
height: 100%;
& #Categories {
& .category {
&.active {
border-bottom: 3px solid var(--color-primary);
}
}
}
& #InputSearch {
& .container-search {
& input {
outline: none;
border: 1px solid var(--color-primary);
background: #fff;
}
}
} }
} }
.card-container { .card-container {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;

View File

@@ -16,6 +16,7 @@ export default {
}, },
data() { data() {
return { return {
agentType,
agentConfig: { agentConfig: {
title: '', title: '',
component: 'agent', component: 'agent',
@@ -26,12 +27,17 @@ export default {
visibleRange: 0 visibleRange: 0
} }
}, },
searchAppType: '',
searchOption: { searchOption: {
nameLike: '', nameLike: '',
appType: '',
handleSearch: async () => { handleSearch: async () => {
this.page = 1 this.page = 1
this.list = [] this.list = []
await this.fetchAgentList({ nameLike: this.searchOption.nameLike }) await this.fetchAgentList({
nameLike: this.searchOption.nameLike,
appType: this.searchOption.appType
})
} }
}, },
/** /**
@@ -201,7 +207,30 @@ export default {
@keydown.enter.native="searchOption.handleSearch" @keydown.enter.native="searchOption.handleSearch"
> >
<template slot="prepend"> <template slot="prepend">
<el-button slot="append" icon="el-icon-search"></el-button> <el-select
style="width: 140px"
v-model="searchOption.appType"
placeholder="请选择"
slot="prepend"
clearable
@change="searchOption.handleSearch"
>
<el-option label="全部分类" value=""></el-option>
<el-option
v-for="item in agentType"
:label="item.label"
:value="item.value"
:key="item.value"
></el-option>
</el-select>
</template>
<template slot="append">
<el-button
slot="append"
icon="el-icon-search"
@click="searchOption.handleSearch"
></el-button>
</template> </template>
</el-input> </el-input>
</el-col> </el-col>
@@ -247,7 +276,10 @@ export default {
}` }`
" "
> >
<div v-if="listItem.imageType === 'image'"> <div
v-if="listItem.imageType === 'image'"
style="width: 100%;height: 100%"
>
<img <img
:src="listItem.image" :src="listItem.image"
alt="" alt=""
@@ -315,10 +347,10 @@ export default {
<el-button <el-button
class="line-button" class="line-button"
size="medium" size="medium"
icon="el-icon-odometer" icon="el-icon-more"
@click.stop="jumpToLogs(listItem.id)" @click.stop="jumpToLogs(listItem.id)"
type="primary" type="primary"
>日志与监测 >更多
</el-button> </el-button>
</div> </div>
</el-card> </el-card>
@@ -528,10 +560,10 @@ export default {
text-align: left; text-align: left;
font-style: normal; font-style: normal;
height: 35px; height: 18px;
margin: 0; margin: 0;
display: -webkit-box; display: -webkit-box;
-webkit-line-clamp: 2; -webkit-line-clamp: 1;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;

View File

@@ -263,6 +263,14 @@ export default {
{{ index + keyword }} {{ index + keyword }}
#{{ keyword }} #{{ keyword }}
</el-tag> </el-tag>
<p
class="fs12 r mt5 theme-line-back fw600"
style="background-clip:text;color:transparent"
v-if="contentItem.knowledgeName"
>
命中文档{{ contentItem.knowledgeName }}
</p>
</section> </section>
<!-- score --> <!-- score -->
<span class="score"> <span class="score">

View File

@@ -36,7 +36,7 @@
<template slot="title"> <template slot="title">
<div class="flex align-items-c"> <div class="flex align-items-c">
<img <img
src="@/assets/images/konwledge/knowledge-5.png" :src="`${static}/loadImage/knowledge-5.png`"
alt="" alt=""
style="height: 20px" style="height: 20px"
/> />
@@ -79,6 +79,7 @@ export default {
props: {}, props: {},
data() { data() {
return { return {
static: process.env.VUE_APP_STATIC,
// 0-向量检索 1-全文检索 2-混合检索 // 0-向量检索 1-全文检索 2-混合检索
searchMethod: 0, searchMethod: 0,
embeddingItem: {}, embeddingItem: {},

View File

@@ -22,7 +22,7 @@
@click="chooseFixSearch(item)" @click="chooseFixSearch(item)"
> >
<img <img
src="@/assets/images/konwledge/knowledge-2.png" :src="`${static}/loadImage/knowledge-2.png`"
alt="" alt=""
style="height: 30px" style="height: 30px"
/> />
@@ -162,6 +162,7 @@ export default {
}, },
data() { data() {
return { return {
static: process.env.VUE_APP_STATIC,
form: { form: {
// 是否启用rerank模型 // 是否启用rerank模型
rerankingEnable: true, rerankingEnable: true,

View File

@@ -1,10 +1,10 @@
<!-- src/views/knowledge/detail/components/DocumentDrawer.vue --> <!-- src/views/knowledge/detail/components/DocumentDrawer.vue -->
<template> <template>
<el-drawer <el-drawer
:visible.sync="visible" :visible.sync="drawerVisible"
size="80%" size="80%"
:wrapperClosable="false" :wrapperClosable="false"
@close="$emit('update:visible', false)" @close="drawerVisible = false"
> >
<!-- drawer title --> <!-- drawer title -->
<template #title> <template #title>
@@ -54,24 +54,22 @@
<script> <script>
import knowledgeInfo from '@/views/track/views/knowledge-info/Index.vue' import knowledgeInfo from '@/views/track/views/knowledge-info/Index.vue'
import TextModel from './TextModel.vue'
import QAModel from './QAModel.vue' import QAModel from './QAModel.vue'
import { import {
documentSourceOptions, documentSourceOptions,
segmentedModeOptionsMap segmentedModeOptionsMap
} from '@/assets/js/utils/utilOptions' } from '@/assets/js/utils/utilOptions'
import RenderFile from '@/components/RenderFile/Index.vue' import RenderFile from '@/components/RenderFile/Index.vue'
import knowledgePng_2 from '@/assets/images/konwledge/knowledge-2.png'
import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue' import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue'
export default { export default {
components: { components: {
MetadataOperator, MetadataOperator,
TextModel,
QAModel, QAModel,
RenderFile, RenderFile,
knowledgeInfo knowledgeInfo
}, },
emit: ['update:visible'],
props: { props: {
visible: Boolean, visible: Boolean,
descriptions: { descriptions: {
@@ -89,12 +87,21 @@ export default {
}, },
data() { data() {
return { return {
knowledgePng_2,
localActiveSegment: this.activeSegment, localActiveSegment: this.activeSegment,
documentSourceOptions, documentSourceOptions,
metadataDialogVisible: false metadataDialogVisible: false
} }
}, },
computed: {
drawerVisible: {
get() {
return this.visible
},
set(value) {
this.$emit('update:visible', value)
}
}
},
watch: { watch: {
activeSegment(newVal) { activeSegment(newVal) {
this.localActiveSegment = newVal this.localActiveSegment = newVal

View File

@@ -19,35 +19,53 @@
</div> </div>
<div <div
class="actions ml10 flex align-items-c mr10" class="actions flex align-items-c mr10 "
style="gap: 10px" style="gap: 10px;margin-top: -2px"
v-if="!noEdit" v-if="!noEdit"
> >
<!-- 删除 编辑--> <!-- 删除 编辑-->
<!-- <el-icon class="el-icon-edit" @click.native.stop=""></el-icon>--> <el-icon
<!-- <el-icon--> class="el-icon-edit mr10"
<!-- class="el-icon-delete"--> @click.native.stop="handleSegmentClick(index)"
<!-- @click.native.stop="deleteSegment"--> ></el-icon>
<!-- ></el-icon>--> <el-icon
<!-- <el-switch--> class="el-icon-delete mr10"
<!-- size="mini"--> @click.native.stop="deleteSegment(segment, index)"
<!-- @click.native.stop=""--> ></el-icon>
<!-- v-model="segment.enabled"--> <el-switch
<!-- ></el-switch>--> size="mini"
@click.native.stop=""
@change="$event => changeEnable($event, segment.id)"
v-model="segment.enabled"
></el-switch>
</div> </div>
</div> </div>
<!-- {{ descriptions.doc_form }}-->
<div> <!-- 普通分段-->
<div v-if="descriptions.doc_form === 'text_model'">
<div>
<p class="context">{{ segment.content }}</p>
</div>
<div
class="segment-keywords flex"
v-if="segment.keywords && segment.keywords.length"
>
<p
v-for="(item, index) in segment.keywords"
:key="index"
class="mr10"
>
#{{ item }}
</p>
</div>
</div>
<!-- QA分段-->
<div v-else>
<div class="context"> <div class="context">
<p>Q {{ segment.content }}</p> <p>Q {{ segment.content }}</p>
<p>A {{ segment.answer }}</p> <p>A {{ segment.answer }}</p>
</div> </div>
</div> </div>
<!-- <div class="segment-keywords flex" v-if="segment.keywords && segment.keywords.length">-->
<!-- <p v-for="(item, index) in segment.keywords" :key="index" class="mr10">#{{ item }}</p>-->
<!-- </div>-->
<!-- <span class="segment-chars">{{ segment.characters || 0 }} characters</span>-->
</div> </div>
</div> </div>
@@ -70,53 +88,58 @@
" "
> >
<div class="segment-content"> <div class="segment-content">
<!-- Q & A-->
<div> <div>
<div> <div>
<p>QUESTION</p> <p class="" v-if="descriptions.doc_form !== 'text_model'">
<p contenteditable class="resetHtml" ref="content"> QUESTION
</p>
<p contenteditable class="resetHtml fs13" ref="content">
{{ descriptions.data[activeSegment].content }} {{ descriptions.data[activeSegment].content }}
</p> </p>
</div> </div>
<div> <div v-if="descriptions.doc_form !== 'text_model'">
<p>ANSWER</p> <p class="">ANSWER</p>
<p contenteditable class="resetHtml" ref="answer"> <p contenteditable class="resetHtml fs13" ref="answer">
{{ descriptions.data[activeSegment].answer }} {{ descriptions.data[activeSegment].answer }}
</p> </p>
</div> </div>
</div> </div>
<div <div
class="flex align-items-c mt20" class="flex align-items-c mt20 fs13"
v-if=" v-if="
descriptions.data[activeSegment].keywords && descriptions.data[activeSegment].keywords &&
descriptions.data[activeSegment].keywords.length descriptions.data[activeSegment].keywords.length
" "
style="flex-wrap: wrap" style="flex-wrap: wrap"
> >
<span>关键词 </span> <span class="mb10">关键词 </span>
<el-tag <el-tag
v-for="(item, index) in descriptions.data[activeSegment].keywords" v-for="(item, index) in descriptions.data[activeSegment].keywords"
:key="index" :key="index"
class="mr10" class="mr10 mb10"
size="medium" size="medium"
type="info" type="info"
:closable="!noEdit" :closable="
@close="tagClose(item)" descriptions.data[activeSegment].keywords.length > 1 && !noEdit
"
@close="tagClose(item, index)"
> >
{{ item }} {{ item }}
</el-tag> </el-tag>
<el-input <el-input
class="input-new-tag" class="input-new-tag mb5"
v-if="createdTag" v-if="createdTag"
v-model="inputValue" v-model="inputValue"
ref="saveTagInput" ref="saveTagInput"
size="small" size="mini"
@keyup.enter.native="handleInputConfirm" @keyup.enter.native="handleInputConfirm"
/> />
<el-button <el-button
v-if="!noEdit && !createdTag" v-if="!noEdit && !createdTag"
size="medium" size="medium"
@click="showInput" @click="showInput"
class="fs12" class="fs12 mb10"
style="padding: 7px;border-radius: 4px;font-size: 12px" style="padding: 7px;border-radius: 4px;font-size: 12px"
>添加标签</el-button >添加标签</el-button
> >
@@ -133,7 +156,7 @@
</div> </div>
</template> </template>
<script> <script>
import { segmentUpdate } from '@/api/generatedApi' import { segmentUpdate, segmentDelete } from '@/api/generatedApi'
export default { export default {
name: 'QAModel', name: 'QAModel',
@@ -152,6 +175,7 @@ export default {
default: () => ({}) default: () => ({})
} }
}, },
watch: {},
data() { data() {
return { return {
createdTag: false, createdTag: false,
@@ -160,10 +184,23 @@ export default {
dialogVisible: false dialogVisible: false
} }
}, },
inject: ['changeEnable'],
mounted() {},
methods: { methods: {
deleteSegment() { deleteSegment(segment, index) {
this.$messageBox( this.$messageBox(
() => {}, () => {
segmentDelete({
documentId: this.parentForm.id,
segmentId: segment.id
}).then(res => {
if (res) {
this.$message.success('删除成功')
this.descriptions.data.splice(index, 1)
}
})
},
'是否删除当前分段,删除后不可恢复', '是否删除当前分段,删除后不可恢复',
'warning', 'warning',
'提示' '提示'
@@ -173,7 +210,7 @@ export default {
let params = { let params = {
keywords: this.descriptions.data[this.activeSegment].keywords, keywords: this.descriptions.data[this.activeSegment].keywords,
content: this.$refs.content.innerHTML, content: this.$refs.content.innerHTML,
answer: this.$refs.answer.innerHTML answer: this.$refs.answer ? this.$refs.answer.innerHTML : undefined
} }
this.saveSegment(params, () => { this.saveSegment(params, () => {
this.$message.success('保存成功') this.$message.success('保存成功')
@@ -183,20 +220,15 @@ export default {
showInput() { showInput() {
this.createdTag = true this.createdTag = true
}, },
tagClose() { tagClose(item, index) {
this.descriptions.data[this.activeSegment].keywords.splice( this.descriptions.data[this.activeSegment].keywords.splice(index, 1)
this.descriptions.data[this.activeSegment].keywords.indexOf( // console.log(this.descriptions.data[this.activeSegment].keywords)
this.inputValue
),
1
)
let params = { let params = {
keywords: this.descriptions.data[this.activeSegment].keywords, keywords: this.descriptions.data[this.activeSegment].keywords,
content: this.$refs.content.innerHTML, content: this.$refs.content.innerHTML,
answer: this.$refs.answer.innerHTML answer: this.$refs.answer ? this.$refs.answer.innerHTML : undefined
} }
this.saveSegment(params) // this.saveSegment(params)
}, },
handleInputConfirm() { handleInputConfirm() {
@@ -206,7 +238,7 @@ export default {
this.inputValue this.inputValue
], ],
content: this.$refs.content.innerHTML, content: this.$refs.content.innerHTML,
answer: this.$refs.answer.innerHTML answer: this.$refs.answer ? this.$refs.answer.innerHTML : undefined
} }
this.saveSegment(params) this.saveSegment(params)
}, },
@@ -252,6 +284,7 @@ export default {
width: 100%; width: 100%;
//height: 400px; //height: 400px;
overflow-y: auto; overflow-y: auto;
overflow-x: hidden;
} }
.context { .context {
color: #3a3f4f; color: #3a3f4f;
@@ -265,6 +298,21 @@ export default {
border-radius: 2px; border-radius: 2px;
transition: background-color 0.3s; transition: background-color 0.3s;
border-bottom: 1px solid #f3f5f7; border-bottom: 1px solid #f3f5f7;
position: relative;
.actions {
position: absolute;
display: none; /* 默认隐藏 */
background: #fff;
padding: 3px 5px;
border-radius: 5px;
right: 10px;
top: 15px;
}
&:hover .actions {
display: flex; /* 悬停或激活时显示操作按钮 */
gap: 10px;
}
&:hover { &:hover {
background: #f3f5f7; background: #f3f5f7;
} }

View File

@@ -1,317 +0,0 @@
<template>
<div class="segment-split-view">
<div class="segment-list">
<!-- <el-checkbox-group v-model="selectedSegments">-->
<div
class="segment-list-item"
v-for="(segment, index) in descriptions.data"
:key="index"
:class="{ active: activeSegment === index }"
@click="handleSegmentClick(index)"
>
<div class="flex align-items-c justify-content-b" style="gap: 8px">
<div class="flex align-items-c " style="gap: 8px">
<!-- <el-checkbox class="mr pt15" :label="index">-->
<span class="el-icon-s-unfold"></span>
<span class="segment-number"
>分段 - {{ (index + 1).toString().padStart(2, '0') }}</span
>
<span v-if="segment.word_count > 0">
· {{ segment.word_count }}个字符 ·</span
>
<span> {{ segment.hit_count }} 次召回次数</span>
</div>
<div
class="actions ml10 flex align-items-c mr10"
style="gap: 10px"
v-if="!noEdit"
>
<!-- 删除 编辑-->
<!-- <el-icon class="el-icon-edit" @click.native.stop=""></el-icon>-->
<!-- <el-icon-->
<!-- class="el-icon-delete"-->
<!-- @click.native.stop="deleteSegment"-->
<!-- ></el-icon>-->
<!-- <el-switch-->
<!-- size="mini"-->
<!-- @click.native.stop=""-->
<!-- v-model="segment.enabled"-->
<!-- ></el-switch>-->
</div>
</div>
<!-- </el-checkbox>-->
<div>
<div>
<p class="context">{{ segment.content }}</p>
</div>
<div
class="segment-keywords flex"
v-if="segment.keywords && segment.keywords.length"
>
<p
v-for="(item, index) in segment.keywords"
:key="index"
class="mr10"
>
#{{ item }}
</p>
</div>
</div>
</div>
<!-- </el-checkbox-group>-->
</div>
<!-- 弹窗 -->
<el-drawer
title="分段详情"
:wrapperClosable="false"
:visible.sync="dialogVisible"
:modal="false"
append-to-body
:before-close="handleClose"
>
<div
style="height:calc(100% - 32px);overflow-x: hidden;overflow-y: auto"
v-if="
activeSegment !== null &&
descriptions.data &&
descriptions.data.length > 0
"
>
<div class="segment-content">
<p contenteditable class="resetHtml" ref="content">
{{ descriptions.data[activeSegment].content }}
</p>
<div
class="flex align-items-c mt20"
v-if="
descriptions.data[activeSegment].keywords &&
descriptions.data[activeSegment].keywords.length
"
style="flex-wrap: wrap"
>
<span>关键词 </span>
<el-tag
v-for="(item, index) in descriptions.data[activeSegment].keywords"
:key="index"
class="mr10 ellipsis"
size="medium"
:closable="!noEdit"
type="info"
@close="tagClose(item)"
>
{{ item }}
</el-tag>
<el-input
class="input-new-tag"
v-if="createdTag"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="handleInputConfirm"
/>
<el-button
v-if="!noEdit && !createdTag"
size="medium"
@click="showInput"
class="fs12"
style="padding: 7px;border-radius: 4px;font-size: 12px"
>添加标签</el-button
>
</div>
</div>
</div>
<div class="text-right">
<el-button @click="dialogVisible = false" size="medium">关闭</el-button>
<el-button @click="saveUS" size="medium" type="primary" v-if="!noEdit"
>保存</el-button
>
</div>
</el-drawer>
</div>
</template>
<script>
import { segmentUpdate } from '@/api/generatedApi'
export default {
name: 'TextModel',
props: {
noEdit: {
type: Boolean,
default: false
},
visible: Boolean,
descriptions: {
type: Object,
default: () => ({ data: [] })
},
parentForm: {
type: Object,
default: () => ({})
}
},
data() {
return {
createdTag: false,
inputValue: '',
activeSegment: null,
dialogVisible: false,
selectedSegments: []
}
},
methods: {
deleteSegment() {
this.$messageBox(
() => {},
'是否删除当前分段,删除后不可恢复',
'warning',
'提示'
)
},
saveUS() {
let params = {
keywords: this.descriptions.data[this.activeSegment].keywords,
content: this.$refs.content.innerHTML,
answer: null
}
this.saveSegment(params, () => {
this.$message.success('保存成功')
})
},
showInput() {
this.createdTag = true
},
tagClose() {
this.descriptions.data[this.activeSegment].keywords.splice(
this.descriptions.data[this.activeSegment].keywords.indexOf(
this.inputValue
),
1
)
let params = {
keywords: this.descriptions.data[this.activeSegment].keywords,
content: this.$refs.content.innerHTML,
answer: null
}
this.saveSegment(params)
},
handleInputConfirm() {
let params = {
keywords: [
...this.descriptions.data[this.activeSegment].keywords,
this.inputValue
],
content: this.$refs.content.innerHTML,
answer: null
}
this.saveSegment(params)
},
saveSegment(params, fun) {
params.documentId = this.parentForm.id
params.segmentId = this.descriptions.data[this.activeSegment].id
segmentUpdate(params).then(res => {
if (res) {
this.descriptions.data[this.activeSegment] = JSON.parse(
JSON.stringify(res.content.content)
)
// res.content.content.keywords
// this.descriptions.data[this.activeSegment].content =
// res.content.content.content
// this.descriptions.data[this.activeSegment].answer =
// res.content.content.answer
this.createdTag = false
this.inputValue = ''
if (fun) {
fun()
}
}
})
},
handleSegmentClick(index) {
this.activeSegment = index
this.dialogVisible = true
},
handleClose() {
this.dialogVisible = false
}
}
}
</script>
<style scoped lang="scss">
.segment-split-view {
display: block;
}
.context {
width: auto;
overflow: hidden;
//省略号
text-overflow: ellipsis;
white-space: nowrap;
color: #3a3f4f;
font-size: 14px;
}
.segment-list {
width: 100%;
height: 100%;
overflow-y: auto;
}
.segment-list-item {
color: #70778d;
cursor: pointer;
padding: 15px 0 20px 15px;
border-radius: 2px;
transition: background-color 0.3s;
font-size: 14px;
border-bottom: 1px solid #f3f5f7;
//margin-bottom: 10px;
&:hover {
background: #f3f5f7;
}
&.active {
background: #f3f5f7;
}
p {
margin: 15px 0;
}
.segment-number {
//color: #0a84ff;
}
.segment-keywords {
font-weight: 400;
font-size: 12px;
color: #70778d;
flex-wrap: wrap;
p {
margin: 0 10px 0 0;
}
}
}
.segment-content {
padding: 20px;
background: #f9f9f9;
border-radius: 15px;
//white-space: pre-wrap;
line-height: 35px;
color: #666;
}
.input-new-tag {
width: 100px;
}
</style>

View File

@@ -0,0 +1,216 @@
<template>
<div class="add-segment-container">
<div class="add-segment-content">
<div class="add-segment-text fs13">
<!-- Q&A-->
<div v-if="descriptions.doc_form === 'qa_model'">
<div class="mv10">Question</div>
<el-input
type="textarea"
class="text-input-q-a"
v-model="question"
placeholder="请填写分段内容"
></el-input>
<div class="mv10">Answer</div>
<el-input
type="textarea"
class="text-input-q-a"
v-model="answer"
placeholder="请填写分段内容"
></el-input>
</div>
<!-- model-->
<div v-else>
<el-input
type="textarea"
class="text-input"
v-model="question"
placeholder="请填写分段内容"
></el-input>
</div>
</div>
</div>
<div class="add-segment-bottom ">
<div class=" mt5 fs13 mb5" style="flex:none">关键词</div>
<div
class="add-segment-tags mb10 fs14 flex align-items-s justify-content-s "
>
<div
class="flex align-items-s mb10"
style="max-height: 80px;overflow: auto;gap: 10px;flex-wrap: wrap;align-items: self-start"
>
<el-tag
v-for="(item, index) in keywords"
size="medium"
:closable="keywords.length > 1"
type="info"
:key="index"
@close="keywords.splice(index, 1)"
>{{ item }}</el-tag
>
<el-input
class="input-new-tag"
v-if="createdTag"
v-model="inputValue"
ref="saveTagInput"
size="small"
@keyup.enter.native="pushKeyWords"
/>
<el-button
v-if="!createdTag"
size="small"
@click="showInput"
class="fs12"
style="padding: 7px;border-radius: 4px;font-size: 12px"
>添加标签</el-button
>
</div>
</div>
<div class="flex align-items-c justify-content-b">
<el-checkbox v-model="continueAdd">连续新增</el-checkbox>
<div>
<el-button size="medium" @click="close">取消</el-button>
<el-button
class="line-button"
size="medium"
@click="handleInputConfirm"
>保存</el-button
>
</div>
</div>
</div>
</div>
</template>
<script>
import { segmentCreate } from '@/api/generatedApi'
export default {
name: 'addSegment',
data() {
return {
continueAdd: false,
question: '',
answer: '',
createdTag: false,
inputValue: '',
keywords: []
}
},
props: {
descriptions: {
type: Object,
default: () => ({ data: [] })
},
documentId: {
type: String,
default: () => ''
}
},
methods: {
pushKeyWords() {
this.keywords.push(this.inputValue)
this.createdTag = false
},
showInput() {
this.createdTag = true
},
handleInputConfirm() {
let params = {
documentId: this.documentId,
segment: {
keywords: this.keywords,
content: this.question,
answer: this.answer
}
}
segmentCreate(params).then(res => {
if (res) {
this.$message.success('新增分段成功')
this.descriptions.data.push({
...res.content.content
})
if (!this.continueAdd) {
this.close()
}
}
})
// this.saveSegment(params)
},
close() {
this.$emit('close', true)
},
addSegment() {
this.$emit('addSegment', this.text)
this.text = ''
}
}
}
</script>
<style scoped lang="scss">
::v-deep .text-input {
height: 100%;
.el-textarea__inner {
padding: 5px 8px;
height: calc(100vh - 310px);
//border: unset;
//resize: unset;
//height: 100%;
}
}
::v-deep .text-input-q-a {
height: 100%;
.el-textarea__inner {
padding: 5px 8px;
height: calc(100vh - 700px);
//border: unset;
//resize: unset;
//height: 100%;
}
}
.add-segment-container {
height: 100%;
overflow-y: auto;
overflow-x: hidden;
&::-webkit-scrollbar {
width: 0;
}
& .add-segment-content {
//background: rebeccapurple;
//overflow-y: hidden;
overflow-x: hidden;
& .add-segment-text {
height: calc(100vh - 310px);
//height: 100%;
//height: 999px;
//background: blue;
}
}
& .add-segment-bottom {
width: 100%;
padding: 10px 0 0 0;
position: sticky;
background: #fff;
bottom: 0;
& .add-segment-tags {
height: 100px;
//background: red;
}
}
}
.input-new-tag {
width: 100px;
}
</style>

View File

@@ -0,0 +1,160 @@
<template>
<div class="container batchAdd-container">
<!-- 文件上传区域 -->
<div
@click.stop="createFile"
@dragover.prevent="handleDragOver"
@dragleave.prevent="handleDragLeave"
@drop.prevent="handleDrop"
class="upload-container"
:class="{ 'drag-over': isDragOver }"
>
<el-empty v-if="fileList.length === 0">
<template #image>
<img :src="uploadPng" alt="" style="width: 50px;height: 50px;" />
</template>
<template #description>
<div class="flex flex-direction-c">
<span class="upload-tip">点击或将文件拖拽到这里上传</span>
</div>
</template>
</el-empty>
<div v-else @click.stop="">
<div
class="file-preview-container align-items-c justify-content-b mh20"
v-for="item in fileList"
>
<div class="flex align-items-c fs12">
<img
:src="uploadPng"
alt="CSV Icon"
style="width: 25px;height: 30px"
/>
<span class="file-name fs12 ml20 fw500">{{ item.name }}</span>
</div>
<div>
<el-button type="primary" size="medium" @click.stop="removeFile(0)"
>移除</el-button
>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import uploadPng from '@/assets/images/konwledge/upload.png'
export default {
name: 'batchAddSegment',
data() {
return {
uploadPng,
fileList: [], // 文件列表
isDragOver: false
}
},
watch: {
fileList: {
handler(newValue, oldValue) {
if (newValue.length > 0) {
this.$emit('getFileList', newValue)
} else {
this.$emit('getFileList', [])
}
}
}
},
methods: {
// 生成filed
createFile() {
let input = document.createElement('input')
input.type = 'file'
input.accept = '.xlsx,.doc,.docx,.pdf,.txt'
input.onchange = e => {
const newFiles = Array.from(e.target.files)
if (this.fileList.length + newFiles.length > 1) {
this.$message.error('最多只能上传1个文件')
return
}
this.fileList = [...this.fileList, ...newFiles]
}
input.click()
},
// 新增:移除文件
removeFile(index) {
this.fileList.splice(index, 1)
},
handleDragOver() {
this.isDragOver = true
},
handleDragLeave() {
this.isDragOver = false
},
handleDrop(event) {
this.isDragOver = false
const files = event.dataTransfer.files
if (this.fileList.length + files.length > 1) {
this.$message.error('最多只能上传1个文件')
return
}
this.fileList = [...this.fileList, ...Array.from(files)]
}
}
}
</script>
<style scoped lang="scss">
.file-preview-container {
display: flex;
align-items: center;
//background-color: #f5f5f5; // 灰色背景
padding: 15px 10px;
border-radius: 4px;
}
.file-name {
margin-left: 10px;
color: #333;
}
.upload-container {
border-radius: 6px;
border-style: dashed;
border-width: 1px;
border-color: #d9d9d9;
text-align: center;
&:hover {
border-color: var(--color-primary);
}
&.drag-over {
border-color: var(--color-primary);
background-color: #ecf5ff;
}
}
.upload-tip {
font-family: PingFangSC, PingFang SC;
font-weight: 500;
font-size: 14px;
color: #5f5e68;
font-style: normal;
}
.upload-tip-field {
font-family: PingFangSC, PingFang SC;
font-weight: 400;
font-size: 13px;
color: #b1b5c7;
font-style: normal;
}
</style>

View File

@@ -54,10 +54,10 @@
> >
<div class="metadata-form"> <div class="metadata-form">
<div class="form-item"> <div class="form-item">
<label class="form-label">元数据类型</label> <label class="form-label">元数据</label>
<el-select <el-select
v-model="dialog.metadataId" v-model="dialog.metadataId"
placeholder="请选择元数据类型" placeholder="请选择元数据"
filterable filterable
class="full-width" class="full-width"
size="medium" size="medium"
@@ -143,10 +143,10 @@
> >
<div class="metadata-form"> <div class="metadata-form">
<div class="form-item"> <div class="form-item">
<label class="form-label">元数据类型</label> <label class="form-label">元数据</label>
<el-input <el-input
v-model="editDialog.metadataKey" v-model="editDialog.metadataKey"
placeholder="元数据类型" placeholder="元数据"
class="full-width" class="full-width"
size="medium" size="medium"
disabled disabled
@@ -210,8 +210,6 @@ import {
updateMetaDataDoc updateMetaDataDoc
} from '@/api/generatedApi' } from '@/api/generatedApi'
import MeteData from '@/views/knowledge/detail/components/metaData/Index.vue' import MeteData from '@/views/knowledge/detail/components/metaData/Index.vue'
import { data } from 'autoprefixer'
export default { export default {
name: 'MetadataOperator', name: 'MetadataOperator',
components: { MeteData }, components: { MeteData },
@@ -239,7 +237,6 @@ export default {
}, },
created() {}, created() {},
methods: { methods: {
data,
init(id) { init(id) {
this.documentId = id this.documentId = id
this.getDocList() this.getDocList()
@@ -314,7 +311,7 @@ export default {
// 这里可以添加保存逻辑 // 这里可以添加保存逻辑
this.dialog.visible = false this.dialog.visible = false
} else { } else {
this.$message.warning('请选择元数据类型并输入值') this.$message.warning('请选择元数据并输入值')
} }
}, },
toMetaData() { toMetaData() {

View File

@@ -1,49 +1,102 @@
<template> <template>
<div id="preprocessing-container " class="mt20"> <div id="preprocessing-container " class="mt20">
<el-form label-width="180px" :model="form" ref="processForm"> <el-form label-width="180px" :model="form" ref="processForm">
<el-form-item label="数据来源:" required prop="radio" position="top" class="el-form--label-top"> <el-form-item
<el-radio-group v-model="form.radio" size="medium" @change="getFileType"> label="数据来源:"
<el-radio-button label="1" size="medium">使用本地文件</el-radio-button> required
<el-radio-button label="2" size="medium">使用通用知识文件模板</el-radio-button> prop="radio"
position="top"
class="el-form--label-top"
>
<el-radio-group
v-model="form.radio"
size="medium"
@change="getFileType"
>
<el-radio-button label="1" size="medium"
>使用本地文件</el-radio-button
>
<el-radio-button label="2" size="medium"
>使用通用知识文件模板</el-radio-button
>
</el-radio-group> </el-radio-group>
<div class="mt10" v-if="form.radio === '2'"> <div class="mt10" v-if="form.radio === '2'">
<el-button type="primary" size="medium" class="fs14" @click="downloadTemplate">下载知识文件模板</el-button> <el-button
type="primary"
size="medium"
class="fs14"
@click="downloadTemplate"
>下载知识文件模板</el-button
>
</div> </div>
</el-form-item> </el-form-item>
<!-- 文件上传--> <!-- 文件上传-->
<el-form-item label="" required prop="file" label-width="0" class="el-form--label-top"> <el-form-item
label=""
required
prop="file"
label-width="0"
class="el-form--label-top"
>
<div <div
@click="createFiled" @click.stop="createFiled"
@dragover.prevent="handleDragOver" @dragover.prevent="handleDragOver"
@dragleave.prevent="handleDragLeave" @dragleave.prevent="handleDragLeave"
@drop.prevent="handleDrop" @drop.prevent="handleDrop"
class="upload-demo" class="upload-demo"
:class="{ 'drag-over': isDragOver }" :class="{ 'drag-over': isDragOver }"
> >
<el-empty v-if="!filed"> <el-empty v-if="fileList.length === 0">
<template #image> <template #image>
<img :src="uloadPng" alt="" style='width: 50px;height: 50px;'></img> <img :src="uloadPng" alt="" style="width: 50px;height: 50px;" />
</template> </template>
<template #description> <template #description>
<div class='flex flex-direction-c'> <div class="flex flex-direction-c">
<span class='upload-tip'>点击或将文件拖拽到这里上传</span> <span class="upload-tip">点击或将文件拖拽到这里上传</span>
<span class='upload-tip-field'>支持扩展名.xlsx.doc.pdf.txt.docx</span> <span class="upload-tip-field"
>支持扩展名.xlsx.doc.pdf.txt.docx</span
>
</div> </div>
</template> </template>
</el-empty> </el-empty>
<el-result <div v-else>
v-else <el-result
icon="success" v-if="fileList.length === 1"
title="文件上传成功" icon="success"
:sub-title="`已上传文件:${filed.name}`" title="文件上传成功"
style="height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;" :sub-title="`已上传文件:${fileList[0].name}`"
> style="height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center;"
<template slot="extra"> >
<el-button type="primary" size="medium" @click.stop="createFiled">重新上传</el-button> <template slot="extra">
</template> <el-button
</el-result> type="primary"
size="medium"
@click.stop="removeFile(0)"
>移除</el-button
>
</template>
</el-result>
<el-result v-else class="more-files">
<template slot="icon">
<div class="text-left">
<el-button class="line-button" size="medium">
文件上传</el-button
>
</div>
</template>
<template slot="extra" style="width: 100%;">
<r-table
:data="fileList"
:columns="columns"
style="width: 100%;"
@removeFiled="removeFiled"
:deletion="false"
></r-table>
</template>
</el-result>
</div>
</div> </div>
</el-form-item> </el-form-item>
@@ -52,21 +105,40 @@
<el-form-item label="是否进行预处理:" required prop="beMinerU"> <el-form-item label="是否进行预处理:" required prop="beMinerU">
<template slot="label"> <template slot="label">
是否进行预处理 是否进行预处理
<el-tooltip class="item" effect="dark" content="通过整合最先进的文档解析模型来提高内容提取质量" placement="top"> <el-tooltip
class="item"
effect="dark"
content="通过整合最先进的文档解析模型来提高内容提取质量"
placement="top"
>
<i class="el-icon-info ml5" style="color: #909399;"></i> <i class="el-icon-info ml5" style="color: #909399;"></i>
</el-tooltip> </el-tooltip>
</template> </template>
<el-switch v-model="form.beMinerU" size="medium"> <el-switch
v-model="form.beMinerU"
size="medium"
:disabled="fileList.length > 1"
>
<!-- <el-radio :label="true" size="medium"></el-radio>--> <!-- <el-radio :label="true" size="medium"></el-radio>-->
<!-- <el-radio :label="false" size="medium"></el-radio>--> <!-- <el-radio :label="false" size="medium"></el-radio>-->
</el-switch> </el-switch>
</el-form-item> </el-form-item>
<el-form-item label="是否ocr协助处理" v-if="form.beMinerU" required prop="beOcr"> <el-form-item
label="是否ocr协助处理"
v-if="form.beMinerU"
required
prop="beOcr"
>
<template slot="label"> <template slot="label">
是否ocr协助处理 是否ocr协助处理
<el-tooltip class="item" effect="dark" content="能更好的协助处理图片、表格类数据" placement="top"> <el-tooltip
class="item"
effect="dark"
content="能更好的协助处理图片、表格类数据"
placement="top"
>
<i class="el-icon-info ml5" style="color: #909399;"></i> <i class="el-icon-info ml5" style="color: #909399;"></i>
</el-tooltip> </el-tooltip>
@@ -87,16 +159,18 @@
<!-- </el-drawer>--> <!-- </el-drawer>-->
</div> </div>
</template> </template>
<script> <script>
import { uploadFileByCustom, uploadFileByTemplate } from '@/api/generatedApi' import { uploadFileByCustom, uploadFileByTemplate } from '@/api/generatedApi'
import { downloadKnowledgeTemplate } from '@/api/knowledge/task-page' import { downloadKnowledgeTemplate } from '@/api/knowledge/task-page'
import uloadPng from '@/assets/images/konwledge/upload.png' import uloadPng from '@/assets/images/konwledge/upload.png'
export default { export default {
name: 'preprocessing', name: 'preprocessing',
data() { data() {
return { return {
uloadPng, uloadPng,
filed: null, fileList: [], // 文件列表
uploadLoading: false, uploadLoading: false,
headers: {}, headers: {},
fieldList: [], fieldList: [],
@@ -106,31 +180,84 @@ export default {
beOcr: false, beOcr: false,
datasetId: this.$route.query.datasetId datasetId: this.$route.query.datasetId
}, },
previewDialogVisible: false, // 添加对话框显示控制变量 previewDialogVisible: false,
documentId: '', documentId: '',
isDragOver: false isDragOver: false
} }
}, },
props: {},
watch: { watch: {
'form.beMinerU': { fileList: {
handler(value) { handler(val) {
// 如果不进行预处理不进行ocr if (val.length > 1) {
if (!value) { this.form.beMinerU = false
this.form.beOcr = false
} }
}, },
deep: true deep: true
} }
}, },
components: {}, computed: {
filters: {}, columns: vm => {
return [
{
type: 'index',
title: '序号'
},
{
title: '文件名称',
prop: 'name'
},
{
title: '文件大小',
prop: 'size',
render: (h, params) => {
return h('span', vm.formatFileSize(params.row.size))
}
},
{
title: '文件类型',
prop: 'type',
render: (h, params) => {
// 根据文件类型展示 是什么类型文件
switch (params.row.type) {
case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
return h('span', 'Excel')
case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
return h('span', 'Word')
case 'application/pdf':
return h('span', 'PDF')
case 'text/plain':
return h('span', 'TXT')
}
return h('span', params.row.type)
}
},
{
title: '操作',
selfBtn: [
{
name: '移除',
size: 'mini',
type: 'primary',
method: 'removeFiled',
class: 'tableBtn'
}
]
}
]
}
},
methods: { methods: {
removeFiled(item) {
this.removeFile(item.index)
},
formatFileSize(size) {
return (size / 1024 / 1024).toFixed(2) + 'MB'
},
getFileType() { getFileType() {
this.$emit('getFileType', this.form.radio) this.$emit('getFileType', this.form.radio)
}, },
downloadTemplate() { downloadTemplate() {
console.log(`下载模板的链接是:${downloadKnowledgeTemplate().url}`)
window.open(downloadKnowledgeTemplate().url, '_blank') window.open(downloadKnowledgeTemplate().url, '_blank')
}, },
@@ -138,18 +265,40 @@ export default {
createFiled() { createFiled() {
let input = document.createElement('input') let input = document.createElement('input')
input.type = 'file' input.type = 'file'
input.multiple = true // 支持多文件选择
// 对文件的类型做出限制 // 对文件的类型做出限制
input.accept = '.xlsx,.doc,.docx,.pdf,.txt' input.accept = '.xlsx,.doc,.docx,.pdf,.txt'
input.onchange = e => { input.onchange = e => {
this.filed = e.target.files[0] const newFiles = Array.from(e.target.files)
if (this.fileList.length + newFiles.length > 10) {
this.$message.error('最多只能上传10个文件')
return
}
// 校验 最新上传的文件是否之前上传过
for (let i = 0; i < newFiles.length; i++) {
for (let j = 0; j < this.fileList.length; j++) {
if (newFiles[i].name === this.fileList[j].name) {
this.$message.error('请勿重复上传文件,请检查文件')
return
}
}
}
this.fileList = [...this.fileList, ...newFiles] // 将新选择的文件添加到文件列表
} }
input.click() input.click()
}, },
// 新增:移除文件
removeFile(index) {
this.fileList.splice(index, 1)
},
uploadFiled(back) { uploadFiled(back) {
if (!this.filed) { if (this.fileList.length === 0) {
this.$message({ this.$message({
type: 'error', type: 'error',
message: '请上传文件' message: '请上传文件'
@@ -159,17 +308,20 @@ export default {
// 0否 1是 // 0否 1是
let formData = new FormData() let formData = new FormData()
formData.append('file', this.filed) this.fileList.forEach(file => {
formData.append('file', file)
})
formData.append('datasetId', this.form.datasetId) formData.append('datasetId', this.form.datasetId)
let api = this.form.radio === '1' ? uploadFileByCustom : uploadFileByTemplate let api =
this.form.radio === '1' ? uploadFileByCustom : uploadFileByTemplate
if (this.form.radio === '1') { if (this.form.radio === '1') {
formData.append('useMinerU', this.form.beMinerU ? '1': '0') formData.append('useMinerU', this.form.beMinerU ? '1' : '0')
formData.append('useOcr', this.form.beOcr? '1': '0') formData.append('useOcr', this.form.beOcr ? '1' : '0')
} }
api(formData).then(response => { api(formData).then(response => {
if(response){ if (response) {
this.documentId = response.content.content this.documentId = response.content.content
if(back){ if (back) {
back(this.documentId) back(this.documentId)
} else { } else {
// 向上导入documentId // 向上导入documentId
@@ -183,10 +335,9 @@ export default {
} }
} }
} }
}) })
}, },
handleDragOver() { handleDragOver() {
this.isDragOver = true this.isDragOver = true
}, },
@@ -198,8 +349,13 @@ export default {
handleDrop(event) { handleDrop(event) {
this.isDragOver = false this.isDragOver = false
const files = event.dataTransfer.files const files = event.dataTransfer.files
this.filed = files[0] if (this.fileList.length + files.length > 10) {
this.$message.error('最多只能上传10个文件')
return
}
this.fileList = [...this.fileList, ...Array.from(files)] // 将拖拽的文件添加到文件列表
}, },
handleUploadSuccess(response, file) { handleUploadSuccess(response, file) {
this.fieldList = [file] this.fieldList = [file]
this.uploadLoading = false this.uploadLoading = false
@@ -236,30 +392,35 @@ export default {
// 返回 true 继续上传,返回 false 停止上传 // 返回 true 继续上传,返回 false 停止上传
return true return true
} }
}, }
created() {},
mounted() {},
computed: {}
} }
</script> </script>
<style>
.more-files > .el-result__extra,
.more-files > .el-result__icon {
width: 100%;
}
</style>
<style scoped lang="scss"> <style scoped lang="scss">
@import '@/assets/sass/renderSass/theme.scss'; @import '@/assets/sass/renderSass/theme.scss';
.flex-direction-c{ .flex-direction-c {
flex-direction: column; flex-direction: column;
line-height: 20px; line-height: 20px;
} }
.upload-tip{ .upload-tip {
font-family: PingFangSC, PingFang SC; font-family: PingFangSC, PingFang SC;
font-weight: 500; font-weight: 500;
font-size: 14px; font-size: 14px;
color: #5F5E68; color: #5f5e68;
font-style: normal; font-style: normal;
} }
.upload-tip-field{ .upload-tip-field {
font-family: PingFangSC, PingFang SC; font-family: PingFangSC, PingFang SC;
font-weight: 400; font-weight: 400;
font-size: 13px; font-size: 13px;
color: #B1B5C7; color: #b1b5c7;
font-style: normal; font-style: normal;
} }
.upload-demo { .upload-demo {

View File

@@ -283,7 +283,6 @@ export default {
}, },
async getRuleList() { async getRuleList() {
let res = await getRulesList({ ruleType: 1 }) let res = await getRulesList({ ruleType: 1 })
console.log(res)
this.ruleList = res.content.content this.ruleList = res.content.content
}, },
// 获取详情 // 获取详情
@@ -311,7 +310,6 @@ export default {
}) })
}, },
queryExistingRules(val) { queryExistingRules(val) {
console.log(val)
if (val) { if (val) {
this.getDetail(val) this.getDetail(val)
} }

View File

@@ -63,6 +63,7 @@
<!-- 添加预览组件 --> <!-- 添加预览组件 -->
<split-preview <split-preview
:documentList="documentList"
:documentId="documentId" :documentId="documentId"
:visible.sync="previewVisible" :visible.sync="previewVisible"
:preview-data="previewData" :preview-data="previewData"
@@ -71,6 +72,7 @@
@confirm="handlePreviewConfirm" @confirm="handlePreviewConfirm"
@handleReUpload="handleReUpload" @handleReUpload="handleReUpload"
@handleClose="handleClose" @handleClose="handleClose"
@changePage="changePage"
/> />
</div> </div>
</template> </template>
@@ -88,6 +90,7 @@ export default {
}, },
data() { data() {
return { return {
splitIndex: 0,
dialogVisible: false, dialogVisible: false,
activeIndex: 0, activeIndex: 0,
previewVisible: false, // 控制预览组件显示 previewVisible: false, // 控制预览组件显示
@@ -112,6 +115,10 @@ export default {
} }
}, },
props: { props: {
documentList: {
type: Array,
default: () => []
},
documentId: { documentId: {
type: String, type: String,
default: '' default: ''
@@ -120,6 +127,10 @@ export default {
watch: {}, watch: {},
filters: {}, filters: {},
methods: { methods: {
async changePage(index) {
this.previewData = await this.getPreviewOperation(this.documentId, index)
},
handleClick(index) { handleClick(index) {
this.activeIndex = index this.activeIndex = index
if (index === 1) { if (index === 1) {
@@ -131,10 +142,15 @@ export default {
// 构建API请求参数 // 构建API请求参数
buildExecSplitParams(documentId) { buildExecSplitParams(documentId) {
const params = { let params = {
documentId: documentId, documentId: documentId,
beAuto: this.activeIndex === 0 beAuto: this.activeIndex === 0
} }
let splitDocId = documentId.split(',')
if (splitDocId.length > 1) {
params.documentId = undefined
params.documentIds = splitDocId
}
if (!params.beAuto && this.$refs.customTable.ruleId) { if (!params.beAuto && this.$refs.customTable.ruleId) {
params.rulesId = this.$refs.customTable.ruleId params.rulesId = this.$refs.customTable.ruleId
@@ -161,7 +177,11 @@ export default {
}, },
// 获取拆分预览 // 获取拆分预览
async getPreviewOperation(documentId) { async getPreviewOperation(documentId, index) {
let splitDocId = documentId.split(',')
if (splitDocId.length > 1) {
documentId = splitDocId[index ? index : 0]
}
const res = await splitResultPreview({ documentId }) const res = await splitResultPreview({ documentId })
if (res.content.result !== '0') { if (res.content.result !== '0') {
const errorMsg = const errorMsg =

View File

@@ -6,6 +6,26 @@
width="60%" width="60%"
:before-close="handleClose" :before-close="handleClose"
> >
<template slot="title">
<div class="flex align-items-c" style="gap:10px">
<span>拆分结果预览</span>
<el-dropdown @command="command" trigger="click" size="medium">
<span class="el-dropdown-link">
{{ documentList[activeIndex].name
}}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="(item, index) in documentList"
:command="index"
:key="item.id"
>{{ item.name }}</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
</div>
</template>
<div v-loading="loading" class="preview-content"> <div v-loading="loading" class="preview-content">
<template v-if="!loading && previewData"> <template v-if="!loading && previewData">
<el-tree <el-tree
@@ -23,7 +43,13 @@
</div> </div>
<span slot="footer" class="dialog-footer"> <span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleReUpload">重新上传</el-button> <el-button size="medium" @click="handleReUpload">重新上传</el-button>
<el-button size="medium" type="primary" @click="handleConfirm" <!-- <el-button size="medium" @click="upFiled">前一个</el-button>-->
<!-- <el-button size="medium" @click="downFiled">后一个</el-button>-->
<el-button
v-if="documentList.length === 1"
size="medium"
type="primary"
@click="handleConfirm"
>下一步</el-button >下一步</el-button
> >
<el-button <el-button
@@ -44,6 +70,10 @@ import { embedding } from '@/api/generatedApi'
export default { export default {
name: 'SplitPreview', name: 'SplitPreview',
props: { props: {
documentList: {
type: Array,
default: () => []
},
documentId: { documentId: {
type: String, type: String,
default: '' default: ''
@@ -66,6 +96,7 @@ export default {
}, },
data() { data() {
return { return {
activeIndex: 0,
defaultProps: { defaultProps: {
children: 'children', children: 'children',
label: 'paragraphTitle' label: 'paragraphTitle'
@@ -73,6 +104,19 @@ export default {
} }
}, },
methods: { methods: {
upFiled() {
this.$emit('changePage', 'up')
},
downFiled() {
this.$emit('changePage', 'down')
},
command(index) {
if (index === this.activeIndex) {
return false
}
this.activeIndex = index
this.$emit('changePage', this.activeIndex)
},
emitKnowledgeDataset() { emitKnowledgeDataset() {
this.$router.push({ this.$router.push({
path: '/knowledge/reviewKnowledge', path: '/knowledge/reviewKnowledge',
@@ -105,7 +149,8 @@ export default {
handleConfirm() { handleConfirm() {
this.$emit('confirm') this.$emit('confirm')
} }
} },
watch: {}
} }
</script> </script>

View File

@@ -76,7 +76,7 @@
:key="index" :key="index"
> >
<div class="section-title"> <div class="section-title">
拆分规则 {{ index + 1 }} 题词规则 {{ index + 1 }}
<div> <div>
<el-button <el-button
v-if="!isPreview && form.ruleList.length > 1" v-if="!isPreview && form.ruleList.length > 1"

View File

@@ -67,6 +67,7 @@
:extract-results="extractResults" :extract-results="extractResults"
:is-auto-extract="activeIndex === 0" :is-auto-extract="activeIndex === 0"
:loading="previewLoading" :loading="previewLoading"
:documentList="documentList"
@confirm="handlePreviewConfirm" @confirm="handlePreviewConfirm"
/> />
</div> </div>
@@ -113,7 +114,12 @@ export default {
documentId: '' documentId: ''
} }
}, },
props: {}, props: {
documentList: {
type: Array,
default: () => []
}
},
watch: {}, watch: {},
filters: {}, filters: {},
methods: { methods: {
@@ -128,10 +134,15 @@ export default {
// 构建执行题词的参数 // 构建执行题词的参数
buildExecExtractParams(documentId) { buildExecExtractParams(documentId) {
const params = { let params = {
documentId: documentId, documentId: documentId,
beAuto: this.activeIndex === 0 beAuto: this.activeIndex === 0
} }
let splitDocIds = documentId.split(',')
if (splitDocIds.length > 1) {
params.documentId = undefined
params.documentIds = splitDocIds
}
if (!params.beAuto && this.$refs.customTable.ruleId) { if (!params.beAuto && this.$refs.customTable.ruleId) {
params.rulesId = this.$refs.customTable.ruleId params.rulesId = this.$refs.customTable.ruleId

View File

@@ -51,6 +51,7 @@
class="mt10" class="mt10"
v-else v-else
:documentId="documentId" :documentId="documentId"
:documentList="this.documentList"
@saveMarkDown="saveMarkDown" @saveMarkDown="saveMarkDown"
></r-miner-u> ></r-miner-u>
</div> </div>
@@ -58,11 +59,16 @@
<step-split-config <step-split-config
ref="splitConfig" ref="splitConfig"
v-if="active === 1" v-if="active === 1"
:documentList="this.documentList"
@previewConfirmed="handlePreviewConfirm" @previewConfirmed="handlePreviewConfirm"
@handleReUpload="handleReUpload" @handleReUpload="handleReUpload"
:documentId="documentId" :documentId="documentId"
></step-split-config> ></step-split-config>
<step-words ref="words" v-if="active === 2"></step-words> <step-words
ref="words"
v-if="active === 2"
:documentList="this.documentList"
></step-words>
</transition> </transition>
</div> </div>
</div> </div>
@@ -120,7 +126,7 @@ import StepPreprocessing from './components/preprocessing.vue'
import SplitConfig from '@/views/knowledge/detail/components/split/Index.vue' import SplitConfig from '@/views/knowledge/detail/components/split/Index.vue'
import Words from '@/views/knowledge/detail/components/words/Index.vue' import Words from '@/views/knowledge/detail/components/words/Index.vue'
import magic from '@/assets/images/konwledge/magic.png' import magic from '@/assets/images/konwledge/magic.png'
import { directEmbedding } from '@/api/generatedApi' import { datasetDocumentEx, directEmbedding } from '@/api/generatedApi'
// import StepC // import StepC
export default { export default {
name: 'create', name: 'create',
@@ -130,7 +136,8 @@ export default {
visible: false, visible: false,
active: 0, active: 0,
documentId: '1365038001244180480', documentId: '1365038001244180480',
isMd: false isMd: false,
documentList: []
} }
}, },
props: {}, props: {},
@@ -185,9 +192,32 @@ export default {
} }
}) })
}, },
getDocumentId(id) { async getDocumentId(id) {
this.documentId = id this.documentId = id
let splitDocIds = this.documentId.split(',')
for (let i = 0; i < splitDocIds.length; i++) {
let content = await this.getFileDetail(splitDocIds[i])
this.documentList.push({
name: content.knowledgeName,
id: content.id
})
}
}, },
// 获取文件详情 主要是名字与ID
async getFileDetail(documentId) {
const res = await datasetDocumentEx({ documentId })
if (res.content.result !== '0') {
const errorMsg =
'获取文件详情失败: ' + (res.content.resultMessage || '未知错误')
this.$message.error(errorMsg)
throw new Error(errorMsg)
}
return res.content.content
},
async nextStep() { async nextStep() {
if (this.active === 0) { if (this.active === 0) {
this.$refs.stepPreProcessing.uploadFiled() this.$refs.stepPreProcessing.uploadFiled()
@@ -211,13 +241,17 @@ export default {
} else { } else {
this.active = 0 this.active = 0
} }
this.documentList = []
} }
}, },
created() {}, created() {},
mounted() { async mounted() {
let { documentId, datasetId, activeLevel, isMd } = this.$route.query let { documentId, datasetId, activeLevel, isMd } = this.$route.query
if (documentId) { if (documentId) {
// 继续处理时 调用接口查询文件信息
this.documentId = documentId this.documentId = documentId
await this.getDocumentId(documentId)
} }
if (activeLevel !== undefined) { if (activeLevel !== undefined) {
this.active = Number(activeLevel) this.active = Number(activeLevel)

View File

@@ -1,7 +1,7 @@
<template> <template>
<div class=" render-container"> <div class=" render-container">
<div class="clearfix flex align-items-c justify-content-b "> <div class="clearfix flex align-items-c justify-content-b ">
<div class=" flex align-items-c j"> <div class=" flex align-items-c justify-content-b" style="flex:1">
<div class="hover-back mr5"> <div class="hover-back mr5">
<el-icon <el-icon
class="el-icon-arrow-left" class="el-icon-arrow-left"
@@ -10,11 +10,8 @@
></el-icon> ></el-icon>
</div> </div>
<img <img :src="knowledgeImage" class="header-icon" />
:src="knowledgeImage ? knowledgeImage : knowledgePng_1" <div class="ml10" style="flex:1">
class="header-icon"
/>
<div class="ml20" style="flex:1">
<div class="flex align-items-c"> <div class="flex align-items-c">
<div class="mr20 header" v-if="!editKnowledge"> <div class="mr20 header" v-if="!editKnowledge">
{{ knowledgeName ? knowledgeName : '' }} {{ knowledgeName ? knowledgeName : '' }}
@@ -32,32 +29,48 @@
v-if="!editKnowledge" v-if="!editKnowledge"
/> />
<div v-else> <div v-else>
<el-button <el-button type="primary" size="medium" @click="saveKnowledgeName"
type="primary"
size="medium"
class="render-button"
@click="saveKnowledgeName"
>保存</el-button >保存</el-button
> >
<el-button <el-button size="medium" @click="cancelKnowledgeName"
size="medium"
class="render-button"
@click="cancelKnowledgeName"
>取消</el-button >取消</el-button
> >
</div> </div>
<span class="segment-content">{{ <span class="segment-content">{{
segmentedMode | filterSegmentedMode segmentedMode | filterSegmentedMode
}}</span> }}</span>
<el-dropdown
size="medium"
placement="right"
v-if="relatedAppList.length > 0"
@command="handleRelatedApp"
>
<span class="segment-content cursor-pointer"
>{{ relatedAppList.length }} 个关联应用</span
>
<el-dropdown-menu>
<el-dropdown-item
v-for="item in relatedAppList"
:command="item"
:key="item.id"
disabled
>
<span>{{ item.appName }}</span>
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</div>
<div class="flex align-items-c mt10 ">
<p class="fs14 knowledgeDesc" style="line-height: 20px">
描述{{ knowledgeDesc }}
</p>
</div> </div>
<p class="mt10 fs14" style="line-height: 20px">
描述{{ knowledgeDesc }}
</p>
<!-- <p class="mt10 fs14" style="line-height: 20px">分段模式{{ segmentedMode | filterSegmentedMode }}</p>--> <!-- <p class="mt10 fs14" style="line-height: 20px">分段模式{{ segmentedMode | filterSegmentedMode }}</p>-->
</div> </div>
</div> </div>
<div style="flex:1" class="text-right"> <div style="margin-left: auto" class="text-right">
<!-- <el-button type="primary" size="medium" class="normal-button" @click="jumpEditKnowledge">修改知识库</el-button>--> <!-- <el-button type="primary" size="medium" class="normal-button" @click="jumpEditKnowledge">修改知识库</el-button>-->
<el-button <el-button
type="primary" type="primary"
@@ -252,7 +265,9 @@ import {
datasetQuerySegments, datasetQuerySegments,
datasetsExPages, datasetsExPages,
datasetUpdate, datasetUpdate,
getDatasetById downloadOriginalFile,
getDatasetById,
relatedApps
} from '@/api/generatedApi' } from '@/api/generatedApi'
import { getUserList } from '@/api/generatedApi/system' import { getUserList } from '@/api/generatedApi/system'
import { import {
@@ -261,7 +276,6 @@ import {
} from '@/assets/js/utils/utilOptions' } from '@/assets/js/utils/utilOptions'
import DocumentDrawer from './components/documentDetail/DocumentDrawer.vue' import DocumentDrawer from './components/documentDetail/DocumentDrawer.vue'
import knowledgeForm from '@/views/knowledge/detail/components/knowledgeForm.vue' import knowledgeForm from '@/views/knowledge/detail/components/knowledgeForm.vue'
import knowledgePng_1 from '@/assets/images/konwledge/knowledge-1.png'
import hitTest from '@/views/knowledge/detail/components/HitTest/Index.vue' import hitTest from '@/views/knowledge/detail/components/HitTest/Index.vue'
import MetaData from '@/views/knowledge/detail/components/metaData/Index.vue' import MetaData from '@/views/knowledge/detail/components/metaData/Index.vue'
import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue' import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue'
@@ -269,8 +283,16 @@ import SearchSetting from '@/views/knowledge/detail/components/SearchSetting/Ind
import { displayStatus } from '@/assets/js/utils/utilOptions' import { displayStatus } from '@/assets/js/utils/utilOptions'
export default { export default {
name: 'index', name: 'index',
// 父子组件共享
provide() {
return {
viewDocumentDetail: row => this.viewDocumentDetail(row)
}
},
data() { data() {
return { return {
relatedAppList: [],
displayStatus, displayStatus,
hitTestConfig: { hitTestConfig: {
title: '命中测试', title: '命中测试',
@@ -284,7 +306,6 @@ export default {
title: '标注元数据', title: '标注元数据',
visible: false visible: false
}, },
knowledgePng_1,
activeName: -1, activeName: -1,
drawer: false, drawer: false,
drawerForm: false, drawerForm: false,
@@ -377,13 +398,6 @@ export default {
// 跳转到知识库编辑 // 跳转到知识库编辑
jumpEditKnowledge() { jumpEditKnowledge() {
this.drawerForm = true this.drawerForm = true
// let { datasetId } = this.$route.query
// this.$router.push({
// path: '/knowledge/knowledge-create',
// query: {
// datasetId: datasetId
// }
// })
}, },
/** /**
* 检索设置 * 检索设置
@@ -456,24 +470,16 @@ export default {
}, },
// 查看文档详情 // 查看文档详情
viewDocumentDetail(row) { viewDocumentDetail(row) {
// 调用查询分段信息接口 this.descriptions = {
datasetQuerySegments({ documentId: row.id }).then(res => { ...row,
if (res) { dataset: {
this.descriptions = { knowledgeName: this.knowledgeName,
dataset: { segmentedMode: this.segmentedMode,
knowledgeName: this.knowledgeName, knowledgeImage: this.knowledgeImage
segmentedMode: this.segmentedMode,
knowledgeImage: this.knowledgeImage
},
...row,
...res.content.content
}
this.drawer = true
// 调用datasetDocumentEx接口获取分词规则和词频规则
this.getDocumentExInfo(row.id)
} }
}) }
this.drawer = true
this.getDocumentExInfo(row.id)
}, },
jumpToUpload(params) { jumpToUpload(params) {
@@ -531,6 +537,11 @@ export default {
console.error('获取文档详情失败', err) console.error('获取文档详情失败', err)
}) })
}, },
// 下载原文件
handleDownload(row) {
let documentId = row.id
window.open(downloadOriginalFile(documentId))
},
// 提取规则文本处理可能是JSON字符串的情况 // 提取规则文本处理可能是JSON字符串的情况
extractRuleText(rule) { extractRuleText(rule) {
@@ -584,6 +595,17 @@ export default {
}, },
close() { close() {
this.metadataOperatorDrawer.visible = false this.metadataOperatorDrawer.visible = false
},
getRelatedApps() {
relatedApps({ id: this.$route.query.datasetId }).then(res => {
if (res) {
this.relatedAppList = res.content.content.intelligentAppDTOS
}
})
},
handleRelatedApp(item) {
// console.log(item)
} }
}, },
filters: { filters: {
@@ -611,14 +633,16 @@ export default {
this.getKnowledgeFiledList() this.getKnowledgeFiledList()
// 获取用户下拉列表 // 获取用户下拉列表
this.getUserData() this.getUserData()
let documentId = sessionStorage.getItem('documentId')
if (documentId) { // 获取关联智能体
setTimeout(() => { this.getRelatedApps()
let row = this.list.filter(item => item.id === documentId) // let documentId = sessionStorage.getItem('documentId')
this.viewDocumentDetail(row[0]) // if (documentId) {
sessionStorage.removeItem('documentId') // setTimeout(() => {
}, 1000) // let row = this.list.filter(item => item.id === documentId)
} // this.viewDocumentDetail(row[0])
// sessionStorage.removeItem('documentId')
// }, 1000)
}, },
computed: { computed: {
datasetId() { datasetId() {
@@ -646,17 +670,28 @@ export default {
class: 'flex align-items-c' class: 'flex align-items-c'
}, },
[ [
h('svg-icon', { h(
props: { 'span',
iconClass: params.row.useMineru === 1 ? 'miner' : 'none' {
props: {
// iconClass: params.row.useMineru === 1 ? 'miner' : 'none'
},
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'
}
}, },
class: 'mr5', params.row.useMineru === 1 ? '预' : ''
style: { ),
// display: params.row.useMineru === 1 ? '' : 'none',
width: '15px',
fontSize: '15px'
}
}),
h('span', {}, text) h('span', {}, text)
] ]
) )
@@ -762,6 +797,22 @@ export default {
} }
// '标注元数据' // '标注元数据'
), ),
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.optStatus < 4
? h( ? h(
'el-button', 'el-button',
@@ -1003,7 +1054,7 @@ export default {
line-height: 17px; line-height: 17px;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
margin-left: 20px; margin-left: 10px;
padding: 2px 5px; padding: 2px 5px;
} }
@@ -1044,4 +1095,13 @@ export default {
border-radius: 5px; border-radius: 5px;
} }
} }
.knowledgeDesc {
display: -webkit-box; // 支持多行省略
-webkit-line-clamp: 1; // 限制为两行
-webkit-box-orient: vertical; // 垂直方向排列
overflow: hidden; // 隐藏超出部分
text-overflow: ellipsis; // 显示省略号
max-width: 80%; // 限制宽度
}
</style> </style>

View File

@@ -68,7 +68,7 @@
placement="top" placement="top"
width="400" width="400"
trigger="hover" trigger="hover"
content="设置分段之间的重叠长度可以保留分段之间的语义关系提升召回效果。建议设置为最大分段长度的1096-25%。" content="设置分段之间的重叠长度可以保留分段之间的语义关系提升召回效果。建议设置为最大分段长度的10%-25%。"
> >
<el-icon <el-icon
class="el-icon-question" class="el-icon-question"
@@ -141,9 +141,24 @@
style="width: 49.5%;height: calc(100vh - 110px)" style="width: 49.5%;height: calc(100vh - 110px)"
class="el-card review" class="el-card review"
> >
<div class="title"> <div class="title flex align-items-c" style="gap: 10px">
{{ documentDetail.knowledgeName }} <el-dropdown @command="command" trigger="click" size="medium">
<span class="el-dropdown-link">
{{
documentDetail.length > 0
? documentDetail[activeIndex].name
: ''
}}<i class="el-icon-arrow-down el-icon--right"></i>
</span>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item
v-for="(item, index) in documentDetail"
:command="index"
:key="item.id"
>{{ item.name }}</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<span class="block" v-if="viewsDetail.total_segments"> <span class="block" v-if="viewsDetail.total_segments">
预估块{{ viewsDetail.total_segments }} 预估块{{ viewsDetail.total_segments }}
</span> </span>
@@ -256,7 +271,8 @@ export default {
chunkOverlap: 400 chunkOverlap: 400
}, },
datasetDetail: {}, datasetDetail: {},
documentDetail: {}, activeIndex: 0,
documentDetail: [],
viewsDetail: {} viewsDetail: {}
} }
}, },
@@ -265,12 +281,24 @@ export default {
components: {}, components: {},
filters: {}, filters: {},
methods: { methods: {
command(index) {
if (index === this.activeIndex) {
return
}
this.activeIndex = index
this.review_logs()
},
resetForm() { resetForm() {
this.form = JSON.parse(JSON.stringify(this.reset)) this.form = JSON.parse(JSON.stringify(this.reset))
}, },
review_logs() { review_logs() {
let { documentId, active } = this.$route.query let { documentId, active } = this.$route.query
let splitDocIds = documentId.split(',')
let api = segmentEstimate let api = segmentEstimate
switch (active) { switch (active) {
case '0': case '0':
@@ -287,7 +315,7 @@ export default {
break break
} }
api({ api({
documentId, documentId: splitDocIds[this.activeIndex],
segmentConfig: { segmentConfig: {
...this.form, ...this.form,
removeExtraSpaces: this.form.removeExtraSpaces ? 1 : 0, removeExtraSpaces: this.form.removeExtraSpaces ? 1 : 0,
@@ -299,13 +327,18 @@ export default {
}, },
// 获取文档详情 // 获取文档详情
getDocumentDetail() { async getDocumentDetail() {
let { documentId } = this.$route.query let { documentId } = this.$route.query
datasetDocumentEx({ documentId }).then(res => {
if (res) { let splitDocIds = documentId.split(',')
this.documentDetail = res.content.content
} for (let i = 0; i < splitDocIds.length; i++) {
}) let content = await datasetDocumentEx({ documentId: splitDocIds[i] })
this.documentDetail.push({
name: content.content.content.knowledgeName,
id: content.content.content.id
})
}
}, },
// 获取知识库详情 // 获取知识库详情
@@ -320,6 +353,8 @@ export default {
// 保存 处理 // 保存 处理
saveUs() { saveUs() {
let { documentId, active } = this.$route.query let { documentId, active } = this.$route.query
let splitDocIds = documentId.split(',')
let api = directEmbedding let api = directEmbedding
switch (active) { switch (active) {
case '0': case '0':
@@ -336,14 +371,21 @@ export default {
break break
} }
api({ let params = {
documentId, documentId,
segmentConfig: { segmentConfig: {
...this.form, ...this.form,
removeExtraSpaces: this.form.removeExtraSpaces ? 1 : 0, removeExtraSpaces: this.form.removeExtraSpaces ? 1 : 0,
removeUrlsEmails: this.form.removeUrlsEmails ? 1 : 0 removeUrlsEmails: this.form.removeUrlsEmails ? 1 : 0
} }
}).then(res => { }
if (splitDocIds.length > 1) {
params.documentIds = splitDocIds
params.documentId = undefined
}
api(params).then(res => {
if (res) { if (res) {
this.$router.push({ this.$router.push({
path: '/knowledge/detail', path: '/knowledge/detail',
@@ -403,7 +445,7 @@ export default {
& .review { & .review {
& .title { & .title {
height: 40px; height: 40px;
line-height: 40px; //line-height: 40px;
border-bottom: 1px solid #ebeef5; border-bottom: 1px solid #ebeef5;
font-weight: 600; font-weight: 600;
font-size: 15px; font-size: 15px;

View File

@@ -49,7 +49,7 @@
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="ledge-list mt20"> <div class="ledge-list mt10 ">
<el-card <el-card
v-for="(item, index) in datasetList" v-for="(item, index) in datasetList"
class="item datasetList" class="item datasetList"
@@ -57,13 +57,9 @@
:key="index" :key="index"
@click.native.stop="knowLedgeDetail(item)" @click.native.stop="knowLedgeDetail(item)"
> >
<div class="dataset-header"> <div class="dataset-header mb10">
<div class="folder-content"> <div class="folder-content">
<img <img :src="item.image" alt="" class="folder" />
:src="item.image ? item.image : getKnowledgeImage(index)"
alt=""
class="folder"
/>
</div> </div>
<div class="dataset-body" style="flex:1"> <div class="dataset-body" style="flex:1">
<h4 class="dataset-title">{{ item.name }}</h4> <h4 class="dataset-title">{{ item.name }}</h4>
@@ -71,10 +67,11 @@
</div> </div>
</div> </div>
<div class="flex align-items-c justify-content-b mh20 mv10"> <div class="flex align-items-c justify-content-b mh20 mv5">
<div class="theme-primary-desc-text-drank fs12"> <div class="theme-primary-desc-text-drank fs12">
{{ item.segmentedMode | filterSegmentedMode }} {{ item.segmentedMode | filterSegmentedMode }}
</div> </div>
<div class="opacity-button"> <div class="opacity-button">
<el-button <el-button
class="default " class="default "
@@ -109,25 +106,11 @@
<script> <script>
import { docManageDataset, datasetDelete } from '@/api/generatedApi/index.js' import { docManageDataset, datasetDelete } from '@/api/generatedApi/index.js'
import knowledgeForm from '@/views/knowledge/detail/components/knowledgeForm.vue' import knowledgeForm from '@/views/knowledge/detail/components/knowledgeForm.vue'
import knowledgePng_1 from '@/assets/images/konwledge/knowledge-1.png'
import knowledgePng_2 from '@/assets/images/konwledge/knowledge-2.png'
import knowledgePng_3 from '@/assets/images/konwledge/knowledge-3.png'
import knowledgePng_4 from '@/assets/images/konwledge/knowledge-4.png'
import knowledgePng_5 from '@/assets/images/konwledge/knowledge-5.png'
import knowledgePng_6 from '@/assets/images/konwledge/knowledge-6.png'
import knowledgePng_7 from '@/assets/images/konwledge/knowledge-7.png'
export default { export default {
name: 'index', name: 'index',
data() { data() {
return { return {
datasetId: '', datasetId: '',
knowledgePng_1,
knowledgePng_2,
knowledgePng_3,
knowledgePng_4,
knowledgePng_5,
knowledgePng_6,
knowledgePng_7,
datasetList: [], datasetList: [],
nameLike: '', nameLike: '',
drawer: false, drawer: false,
@@ -139,7 +122,8 @@ export default {
knowledgeForm: { knowledgeForm: {
name: 'knowledgeForm', name: 'knowledgeForm',
component: knowledgeForm component: knowledgeForm
} },
relatedAppList: []
} }
}, },
props: {}, props: {},
@@ -159,6 +143,7 @@ export default {
this.datasetList = res.content.content this.datasetList = res.content.content
}) })
}, },
createdKnowLedge(item) { createdKnowLedge(item) {
this.datasetId = item ? item.id : '' this.datasetId = item ? item.id : ''
this.drawer = true this.drawer = true
@@ -202,18 +187,6 @@ export default {
// }).then(() => { // }).then(() => {
// //
// }) // })
},
getKnowledgeImage(index) {
const images = [
knowledgePng_1,
knowledgePng_2,
knowledgePng_3,
knowledgePng_4,
knowledgePng_5,
knowledgePng_6,
knowledgePng_7
]
return images[index % images.length]
} }
}, },
filters: { filters: {
@@ -390,10 +363,10 @@ export default {
text-align: left; text-align: left;
font-style: normal; font-style: normal;
height: 35px; height: 18px;
margin: 0; margin: 0;
display: -webkit-box; // 支持多行省略 display: -webkit-box; // 支持多行省略
-webkit-line-clamp: 2; // 限制为两行 -webkit-line-clamp: 1; // 限制为两行
-webkit-box-orient: vertical; // 垂直方向排列 -webkit-box-orient: vertical; // 垂直方向排列
overflow: hidden; // 隐藏超出部分 overflow: hidden; // 隐藏超出部分
text-overflow: ellipsis; // 显示省略号 text-overflow: ellipsis; // 显示省略号

View File

@@ -118,6 +118,10 @@ export default {
type: String, type: String,
default: '添加用户' default: '添加用户'
}, },
roleListData: {
type: Array,
default: () => []
},
visible: { visible: {
type: Boolean, type: Boolean,
default: false default: false
@@ -145,14 +149,20 @@ export default {
email: '', email: '',
sysUserRoleDTOs: [] sysUserRoleDTOs: []
}, },
roleListData: [],
selectedRoleIds: [], // 新增用于绑定选中的角色ID数组 selectedRoleIds: [], // 新增用于绑定选中的角色ID数组
rules: { rules: {
realName: [ realName: [{ required: true, message: '请输入真实姓名' }],
{ required: true, message: '请输入真实姓名', trigger: 'blur' } userName: [{ required: true, message: '请输入用户名称' }],
email: [
{ required: true, message: '请输入邮箱' },
// 邮箱格式校验 正则
{
type: 'email',
message: '请输入正确的邮箱地址'
}
], ],
userName: [ sysUserRoleDTOs: [
{ required: true, message: '请输入用户名称', trigger: 'blur' } { required: true, message: '请选择用户角色', trigger: 'blur' }
] ]
}, },
roleOptions: [ roleOptions: [
@@ -167,31 +177,18 @@ export default {
handler(val) { handler(val) {
if (val && Object.keys(val).length > 0) { if (val && Object.keys(val).length > 0) {
this.form = { ...val } this.form = { ...val }
this.selectedRoleIds = this.form.sysUserRoleDTOs this.selectedRoleIds = this.form.sysUserRoleDTOs.map(item => {
return item.roleId
})
} }
}, },
immediate: true immediate: true
} }
}, },
created() { created() {
this.getRoleListData() // this.getRoleListData()
}, },
methods: { methods: {
// 获取角色列表
getRoleListData() {
this.loading = true
getRoleList({})
.then(response => {
this.roleListData = response.content.content || []
})
.catch(error => {
this.$message.error('获取角色列表出错', error)
})
.finally(() => {
this.loading = false
})
},
handleClose() { handleClose() {
this.$refs.form.resetFields() this.$refs.form.resetFields()
this.$emit('update:visible', false) this.$emit('update:visible', false)
@@ -205,7 +202,7 @@ export default {
this.$refs.form.validate(valid => { this.$refs.form.validate(valid => {
if (valid) { if (valid) {
this.loading = true // this.loading = true
const submitData = { ...this.form } const submitData = { ...this.form }
// 根据是否是编辑模式调用不同的API // 根据是否是编辑模式调用不同的API
@@ -213,24 +210,18 @@ export default {
? updateUser(submitData) ? updateUser(submitData)
: addUser(submitData) : addUser(submitData)
apiRequest apiRequest.then(() => {
.then(() => { this.$message.success(this.isEdit ? '修改成功' : '添加成功')
this.$message.success(this.isEdit ? '修改成功' : '添加成功') this.$emit('submit', submitData)
this.$emit('submit', submitData) this.handleClose()
this.handleClose() })
})
.catch(() => {
this.$message.error(this.isEdit ? '修改用户出错' : '添加用户出错')
})
.finally(() => {
this.loading = false
})
} }
}) })
}, },
// 处理角色选择变化 // 处理角色选择变化
handleRolesChange(roleIds) { handleRolesChange(roleIds) {
this.form.sysUserRoleDTOs = roleIds.map(id => ({ roleId: id })) this.form.sysUserRoleDTOs = roleIds.map(id => ({ roleId: id }))
this.$refs.form.validateField('sysUserRoleDTOs')
}, },
clearForm() { clearForm() {
this.form = {} this.form = {}

View File

@@ -67,6 +67,7 @@
:title="dialogTitle" :title="dialogTitle"
:is-edit="isEdit" :is-edit="isEdit"
:is-view="isView" :is-view="isView"
:roleListData="roleListData"
:user-data="currentUserData" :user-data="currentUserData"
@submit="handleSubmit" @submit="handleSubmit"
/> />
@@ -90,6 +91,7 @@ import {
changeUserStatus, changeUserStatus,
resetPassword resetPassword
} from '@/api/generatedApi/system' } from '@/api/generatedApi/system'
import { getRoleList } from '@/api/system/role'
export default { export default {
name: 'UserManage', name: 'UserManage',
@@ -99,6 +101,7 @@ export default {
}, },
data() { data() {
return { return {
roleListData: [],
loading: false, loading: false,
dialogVisible: false, dialogVisible: false,
resetPasswordVisible: false, resetPasswordVisible: false,
@@ -127,7 +130,35 @@ export default {
{ prop: 'realName', key: '真实姓名' }, { prop: 'realName', key: '真实姓名' },
{ prop: 'mobile', key: '手机号' }, { prop: 'mobile', key: '手机号' },
{ prop: 'email', key: '邮箱' }, { prop: 'email', key: '邮箱' },
{ prop: 'userRoles', key: '用户角色' }, {
prop: 'userRoles',
key: '用户角色',
render: (h, p) => {
let text = []
p.row.sysUserRoleDTOs.map(item => {
this.roleListData.find(role => {
console.log(role, item)
if (role.id === item.roleId) {
text.push(role.roleName)
}
})
})
return h('div', [
text.map(item => {
return h(
'el-tag',
{
props: {
size: 'mini'
},
class: 'mr5'
},
item
)
})
])
}
},
{ {
prop: 'status', prop: 'status',
key: '状态', key: '状态',
@@ -222,9 +253,20 @@ export default {
} }
}, },
created() { created() {
this.getRoleListData()
this.getUserList() this.getUserList()
}, },
methods: { methods: {
// 获取角色列表
getRoleListData() {
this.loading = true
getRoleList({}).then(response => {
if (response) {
this.roleListData = response.content.content || []
}
})
},
// 获取用户列表 // 获取用户列表
getUserList() { getUserList() {
this.loading = true this.loading = true

View File

@@ -5,7 +5,8 @@ import {
} from '@/api/generatedApi' } from '@/api/generatedApi'
import KnowledgeInfo from '@/views/track/views/knowledge-info/Index.vue' import KnowledgeInfo from '@/views/track/views/knowledge-info/Index.vue'
import { getUserList } from '@/api/generatedApi/system' import { getUserList } from '@/api/generatedApi/system'
import knowledgePng_2 from '@/assets/images/konwledge/knowledge-2.png' import knowledgePng_2 from '../../../public/loadImage/knowledge-2.png'
export default { export default {
components: { components: {
KnowledgeInfo KnowledgeInfo

View File

@@ -1,20 +1,52 @@
<script> <script>
import { datasetQuerySegments, getPdfUrl, queryTask } from '@/api/generatedApi' import {
import TextModel from '@/views/knowledge/detail/components/documentDetail/TextModel.vue' datasetQuerySegments,
importSegment,
queryTask,
segmentTemplate,
exportSegment,
switchStatus
} from '@/api/generatedApi'
import QAModel from '@/views/knowledge/detail/components/documentDetail/QAModel.vue' import QAModel from '@/views/knowledge/detail/components/documentDetail/QAModel.vue'
import RenderFile from '@/components/RenderFile/Index.vue' import RenderFile from '@/components/RenderFile/Index.vue'
import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue' import MetadataOperator from '@/views/knowledge/detail/components/metaData/MetadataOperator.vue'
import AddSegment from '@/views/knowledge/detail/components/documentDetail/addSegment.vue'
import BatchAddSegment from '@/views/knowledge/detail/components/documentDetail/batchAddSegment.vue'
import { Form } from 'element-ui'
export default { export default {
name: 'index', name: 'index',
components: { MetadataOperator, QAModel, TextModel, RenderFile }, components: {
MetadataOperator,
QAModel,
RenderFile,
AddSegment,
BatchAddSegment
},
data() { data() {
return { return {
segmentPage: 1,
segmentLimit: 10,
segmentTotal: 101,
searchText: '',
keyWords: '',
batchAddSegmentDialog: false,
iframeSrc: window.location.origin, iframeSrc: window.location.origin,
newForm: {}, newForm: {},
descriptions: null descriptions: null,
addSegmentDialog: false,
batchSegmentList: []
} }
}, },
provide() {
return {
changeEnable: this.changeEnable
}
},
inject: ['viewDocumentDetail'],
props: { props: {
noEdit: { noEdit: {
type: Boolean, type: Boolean,
@@ -75,18 +107,98 @@ export default {
} }
}, },
methods: { methods: {
toSplit() { changeEnable(state, id) {
this.$router.push({ let params = {
path: '/knowledge/detail/create', documentId: this.form.id,
query: { segmentIds: [id],
documentId: this.form.id, status: state ? 0 : 1 //枚举值0-启用 1-禁用
datasetId: this.form.datasetId, }
activeLevel: 1 switchStatus(params)
},
inputSegment() {
if (!this.searchText.trim()) {
this.keyWords = ''
this.segmentPage = 1
this._getSplitResultPreview()
}
},
searchSegment() {
this.keyWords = this.searchText
this.segmentPage = 1
this._getSplitResultPreview()
},
sizeChange(size) {
this.segmentPage = 1
this.segmentLimit = size
this._getSplitResultPreview()
},
currentChange(page) {
this.segmentPage = page
this._getSplitResultPreview()
},
importSegmentToKnowledge() {
let form = new FormData()
form.append('documentId', this.form.id)
if (this.batchSegmentList.length === 0) {
this.$message.error('请先选择文件')
return
}
this.batchSegmentList.map(item => {
form.append('file', item)
})
importSegment(form).then(res => {
if (res) {
this.$message.success('导入成功')
this.batchAddSegmentDialog = false
this.batchSegmentList = []
this._getSplitResultPreview()
} }
}) })
}, },
getPdfUrl, getFileList(list) {
this.batchSegmentList = list
},
downLoadSegmentTemplate() {
let model = null
switch (this.newForm.segmentedMode) {
case 0:
model = 'general'
break
case 1:
model = 'qa'
break
default:
model = 'general'
return ''
}
window.open(segmentTemplate(model))
},
command(type) {
switch (type) {
case 'newAdd':
// 批量新增
this.batchAddSegmentDialog = true
break
case 'exportSeg':
// 导出分段
window.open(exportSegment({ documentId: this.form.id }))
break
}
},
// 新增分段
addSegment() {
if (this.newForm.optStatus !== 4) {
return false
}
// this._getSplitResultPreview()
this.addSegmentDialog = true
},
_getTaskDetail() { _getTaskDetail() {
queryTask({ id: this.form.id }).then(res => { queryTask({ id: this.form.id }).then(res => {
const { content } = res.content const { content } = res.content
@@ -94,8 +206,19 @@ export default {
}) })
}, },
_getSplitResultPreview() { _getSplitResultPreview() {
datasetQuerySegments({ documentId: this.form.id }).then(res => { if (this.descriptions && this.descriptions.data) {
this.descriptions.data = []
}
let params = {
documentId: this.form.id,
page: this.segmentPage,
pageSize: this.segmentLimit,
keyword: this.keyWords
// keyword: this.searchText
}
datasetQuerySegments(params).then(res => {
this.descriptions = res.content.content this.descriptions = res.content.content
this.segmentTotal = res.content.content.total
}) })
}, },
openMetaDrawer() { openMetaDrawer() {
@@ -123,11 +246,11 @@ export default {
<template> <template>
<div <div
class=" upload-info-container" class="upload-info-container"
:class="!fullscreen ? 'render-container' : ''" :class="!fullscreen ? 'render-container' : ''"
> >
<div class="form-container"> <div class="form-container ph10">
<el-descriptions class="" :column="4"> <el-descriptions class="mt10" :column="4">
<el-descriptions-item label="知识库"> <el-descriptions-item label="知识库">
{{ newForm.datasetName }} {{ newForm.datasetName }}
</el-descriptions-item> </el-descriptions-item>
@@ -163,24 +286,92 @@ export default {
</div> </div>
<div class="card-body"> <div class="card-body">
<el-row :gutter="20"> <div class="flex align-items-c mt10" style="gap:20px">
<el-dropdown
trigger="click"
v-if="!noEdit"
split-button
size="medium"
type="primary"
@click="addSegment"
class="line-button"
:class="newForm.optStatus !== 4 ? 'is-disabled' : ''"
@command="command"
>
新增分段
<el-dropdown-menu slot="dropdown" :disabled="newForm.optStatus !== 4">
<el-dropdown-item
command="newAdd"
:disabled="newForm.optStatus !== 4"
>批量新增</el-dropdown-item
>
<el-dropdown-item
command="exportSeg"
:disabled="newForm.optStatus !== 4"
>分段导出</el-dropdown-item
>
</el-dropdown-menu>
</el-dropdown>
<el-input
style="width: 50vh;"
size="small"
placeholder="按下回车搜索分段内容"
clearable
v-model="searchText"
@input="inputSegment"
@keydown.enter.native="searchSegment"
></el-input>
</div>
<el-row :gutter="20" class="mt10">
<!-- 左侧表单内容和知识内容 --> <!-- 左侧表单内容和知识内容 -->
<el-col :span="12"> <el-col
:span="
newForm.knowledgeName && newForm.knowledgeName.indexOf('.pdf') >= 0
? 12
: 24
"
>
<!-- 知识内容 --> <!-- 知识内容 -->
<div class="content-card el-card mt20"> <div class="content-card el-card ">
<div class="knowledge-content" v-if="descriptions"> <div
<text-model v-if="descriptions"
:noEdit="noEdit" class="knowledge-content"
v-if="descriptions.doc_form === 'text_model'" v-loading="!descriptions.data"
:descriptions="descriptions" >
:parentForm="form"
/>
<q-a-model <q-a-model
:class="segmentTotal > 0 ? '' : ''"
:noEdit="noEdit" :noEdit="noEdit"
v-else-if="descriptions.doc_form === 'qa_model'"
:descriptions="descriptions" :descriptions="descriptions"
:parentForm="form" :parentForm="form"
:style="{
height: 'calc(100% - 40px)',
overflowX: 'hidden',
overflowY: 'auto'
}"
/> />
<div
style="height: 40px;width:100%;position: sticky;bottom: -1px;color:Red;background: #fff;"
class="flex align-items-c justify-content-b"
>
<div>
<el-pagination
background
small
@size-change="sizeChange"
@current-change="currentChange"
:total="segmentTotal"
:currentPage="segmentPage"
layout="prev,sizes, pager, next"
:page-sizes="[10, 20, 30, 40, 50]"
/>
</div>
<!-- <div v-for="item in getSegmentPages()">-->
<!-- {{ item }}-->
<!-- </div>-->
</div>
</div> </div>
<div v-else class="p20 flex align-items-c"> <div v-else class="p20 flex align-items-c">
<div class="mr10 fs14">暂无知识内容</div> <div class="mr10 fs14">暂无知识内容</div>
@@ -196,8 +387,13 @@ export default {
</el-col> </el-col>
<!-- 右侧原文内容 --> <!-- 右侧原文内容 -->
<el-col :span="12"> <el-col
<div class="content-card el-card full-height mt20"> :span="12"
v-if="
newForm.knowledgeName && newForm.knowledgeName.indexOf('.pdf') >= 0
"
>
<div class="content-card el-card full-height ">
<!-- <metadata-operator--> <!-- <metadata-operator-->
<!-- @openMetaDrawer="openMetaDrawer"--> <!-- @openMetaDrawer="openMetaDrawer"-->
<!-- ></metadata-operator>--> <!-- ></metadata-operator>-->
@@ -206,10 +402,66 @@ export default {
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
<el-drawer
title="新增分段"
:visible.sync="addSegmentDialog"
:wrapperClosable="false"
width="50%"
append-to-body
:modal="false"
>
<add-segment
:descriptions="descriptions"
:document-id="form.id"
@close="addSegmentDialog = false"
></add-segment>
</el-drawer>
<r-dialog
title="批量新增"
:visible.sync="batchAddSegmentDialog"
append-to-body
width="40%"
destroy-on-close
>
<template slot="title">
<div class="flex align-items-c">
<div>批量新增</div>
<el-button
size="mini"
type="text"
class="ml20"
icon="el-icon-download"
@click="downLoadSegmentTemplate"
>下载模板</el-button
>
</div>
</template>
<batch-add-segment
:document-id="form.id"
@close="batchAddSegmentDialog = false"
@getFileList="getFileList"
></batch-add-segment>
<div slot="footer">
<el-button @click="batchAddSegmentDialog = false" size="medium"
>取消</el-button
>
<el-button
size="medium"
type="primary"
:disabled="batchSegmentList.length < 1"
@click="importSegmentToKnowledge"
>导入</el-button
>
</div>
</r-dialog>
</div> </div>
</template> </template>
<style lang="scss" scoped> <style lang="scss" scoped>
@import '@/assets/sass/renderSass/theme.scss';
.form-container { .form-container {
background: #fff; background: #fff;
padding: 5px; padding: 5px;
@@ -218,12 +470,13 @@ export default {
} }
.content-card { .content-card {
margin-bottom: 20px; //margin-bottom: 20px;
border-radius: 8px; border-radius: 8px;
overflow: hidden; overflow: hidden;
.knowledge-content { .knowledge-content {
height: calc(100vh - 240px); position: relative;
height: calc(100vh - 290px);
overflow-y: auto; overflow-y: auto;
//&::-webkit-scrollbar { //&::-webkit-scrollbar {
// width: 4px; // width: 4px;
@@ -232,7 +485,7 @@ export default {
} }
.full-height { .full-height {
height: calc(100vh - 240px); height: calc(100vh - 290px);
padding-bottom: 20px; padding-bottom: 20px;
} }
@@ -249,4 +502,20 @@ export default {
.clearfix:after { .clearfix:after {
clear: both; clear: both;
} }
::v-deep .line-button {
background: $--color-primary-button-gradient;
overflow: hidden;
border-radius: 8px;
&.is-disabled {
& .el-button {
cursor: no-drop;
}
}
& .el-button-group {
& .el-button {
background: unset;
border: unset;
}
}
}
</style> </style>