Merge branch 'dev' into system

# Conflicts:
#	src/router/generatedRouter/index.js
This commit is contained in:
du.meimei
2025-04-22 21:04:24 +08:00
22 changed files with 484 additions and 61 deletions

View File

@@ -286,3 +286,12 @@ export function mdIndex(params) {
back: true
})
}
// 上传到知识库
export function embedding(data) {
return request({
url: getUrl(`/datasetDocumentEx/split/embedding`),
method: 'post',
data
})
}

View File

@@ -5,6 +5,7 @@
@import './element-ui.scss';
@import './sidebar.scss';
@import './public.scss';
@import './renderUi.scss';
* {
margin: 0;

View File

@@ -91,24 +91,24 @@
overflow: hidden;
}
}
.el-dialog__body {
padding: 30px 15px;
width: 96%;
margin: auto;
max-height: 55vh;
overflow: auto;
}
.el-dialog__footer {
text-align: right;
}
.el-dialog__header {
font-weight: 600;
.el-dialog__title {
font-size: 20px;
color: #0096fd;
line-height: 28px;
}
}
//.el-dialog__body {
// padding: 30px 15px;
// width: 96%;
// margin: auto;
// max-height: 55vh;
// overflow: auto;
//}
//.el-dialog__footer {
// text-align: right;
//}
//.el-dialog__header {
// font-weight: 600;
// .el-dialog__title {
// font-size: 20px;
// color: #0096fd;
// line-height: 28px;
// }
//}
.el-collapse-item__header.is-active {
border-bottom: 1px solid #ebeef5;

View File

@@ -0,0 +1,99 @@
@import 'theme';
.render-button {
padding: 8px 21px;
border-radius: 8px;
}
.el-button {
&:hover {
border-color: var(--color-primary-light);
background: transparent;
color: var(--color-primary);
}
&:focus {
border-color: $--color-primary-light;
background: transparent;
color: var(--color-primary);
}
&:active {
border-color: $--color-primary-light;
background: transparent;
color: var(--color-primary);
}
}
.el-button--text {
color: var(--color-primary);
border: none;
&:hover {
color: $--color-primary-light;
border: none;
}
&:focus {
color: $--color-primary-light;
border: none;
}
&:active {
color: $--color-primary-light;
border: none;
}
}
.el-button--primary {
background-color: var(--color-primary);
border-color: var(--color-primary);
color: #fff;
&.is-disabled {
background-color: var(--color-primary-disabled);
border-color: transparent;
&:hover {
background-color: var(--color-primary-disabled);
border-color: transparent;
}
}
&:hover {
background-color: $--color-primary-light;
border-color: $--color-primary-light;
color: #fff;
}
&:active {
background-color: darken($--color-primary, 5%);
border-color: $--color-primary-light;
color: #fff;
}
&:focus {
background-color: darken($--color-primary, 5%);
border-color: $--color-primary-light;
color: #fff;
}
}
.el-button--danger {
background: var(--color-primary-danger);
color: #fff;
&:hover {
background: $--color-primary-danger-light;
color: #fff;
border-color: $--color-primary-danger-light;
}
&:active {
background: $--color-primary-danger-light;
color: #fff;
border-color: $--color-primary-danger-light;
}
&:focus {
background: $--color-primary-danger-light;
color: #fff;
border-color: $--color-primary-danger-light;
}
&.is-disabled {
background: $--color-primary-danger-disabled;
color: #fff;
border-color: transparent;
&:hover {
background: $--color-primary-danger-disabled;
color: #fff;
border-color: transparent;
}
}
}

View File

@@ -0,0 +1,36 @@
//新版本ui
.el-dialog {
border-radius: 8px;
.el-dialog__header {
padding: 15px 15px 0 15px;
color: #000000;
font-size: 16px;
font-weight: 600;
font-family: PingFangSC, PingFang SC;
.el-dialog__headerbtn {
&:hover {
.el-dialog__close {
color: $--color-primary;
}
}
&:focus {
.el-dialog__close {
color: $--color-primary;
}
}
}
}
.el-dialog__body {
padding: 15px;
.render-dialog-body {
max-height: 50vh;
overflow-y: scroll;
&::-webkit-scrollbar {
width: 0;
}
}
}
.el-dialog__footer {
padding: 0 15px 15px 15px;
}
}

View File

@@ -0,0 +1,13 @@
//主题色
$--color-primary: #0a6dff; //主题色
$--color-primary-light: lighten($--color-primary, 5%); //高亮颜色
$--color-primary-disabled: #155aef24;
$--color-primary-danger: #ff0000;
$--color-primary-danger-light: lighten($--color-primary-danger, 5%); //高亮颜色
$--color-primary-danger-disabled: #ff000024;
:root {
--swiper-theme-color: #0a6dff;
--color-primary: #0a6dff;
--color-primary-disabled: #155aef24;
--color-primary-danger: #ff0000;
}

View File

@@ -0,0 +1,3 @@
@import 'renderSass/theme';
@import 'renderSass/button';
@import 'renderSass/dialog';

View File

@@ -1,8 +1,7 @@
#app {
.main-container {
min-height: 100%;
transition: margin-left .28s;
transition: margin-left 0.28s;
margin-left: $sideBarWidth;
position: relative;
}
@@ -71,11 +70,11 @@
}
}
.is-active>.el-submenu__title {
.is-active > .el-submenu__title {
color: $subMenuActiveText !important;
}
& .nest-menu .el-submenu>.el-submenu__title,
& .nest-menu .el-submenu > .el-submenu__title,
& .el-submenu .el-menu-item {
min-width: $sideBarWidth !important;
background-color: $subMenuBg !important;
@@ -111,7 +110,7 @@
.el-submenu {
overflow: hidden;
&>.el-submenu__title {
& > .el-submenu__title {
padding: 0 !important;
.svg-icon {
@@ -126,8 +125,8 @@
.el-menu--collapse {
.el-submenu {
&>.el-submenu__title {
&>span {
& > .el-submenu__title {
& > span {
height: 0;
width: 0;
overflow: hidden;
@@ -150,7 +149,7 @@
}
.sidebar-container {
transition: transform .28s;
transition: transform 0.28s;
width: $sideBarWidth !important;
}
@@ -164,7 +163,6 @@
}
.withoutAnimation {
.main-container,
.sidebar-container {
transition: none;
@@ -174,13 +172,13 @@
// when menu collapsed
.el-menu--vertical {
&>.el-menu {
& > .el-menu {
.svg-icon {
margin-right: 16px;
}
}
.nest-menu .el-submenu>.el-submenu__title,
.nest-menu .el-submenu > .el-submenu__title,
.el-menu-item {
&:hover {
// you can use $subMenuHover
@@ -189,7 +187,7 @@
}
// the scroll bar appears when the subMenu is too long
>.el-menu--popup {
> .el-menu--popup {
max-height: 100vh;
overflow-y: auto;

View File

@@ -18,24 +18,7 @@ $width-list: 5 8 10 20 30 40 50 60 65 70 80 86 100 110 120 140 150 155 160 180 1
// 内外边距列表
$distance-list: 0 1 2 5 6 8 9 10 12 15 20 25 30 35 40 45 50 60 80 86 90 100 120 140;
$distance-class-list: m,
mv,
mh,
mt,
ml,
mr,
mb,
p,
pv,
ph,
pt,
pl,
pr,
pb,
top,
left,
right,
bottom;
$distance-class-list: m, mv, mh, mt, ml, mr, mb, p, pv, ph, pt, pl, pr, pb, top, left, right, bottom;
//圆角弧度
$radius: 1 2 3 4 5 6 7 8 9 10 12 13 14 15 18 20 50 100;

View File

@@ -0,0 +1,63 @@
<template>
<el-dialog :visible.sync="visible" :title="title" :append-to-body="appendToBody">
<div class="render-dialog-body">
<slot name="default"></slot>
</div>
<div slot="footer">
<slot name="footer">
<el-button size="medium" class="render-button" @click="cancel">{{ cancelButtonText }}</el-button>
<el-button size="medium" class="render-button" type="primary" @click="confirm">{{ confirmButtonText }}</el-button>
</slot>
</div>
</el-dialog>
</template>
<script>
export default {
name: 'index',
data() {
return {}
},
props: {
appendToBody: {
type: Boolean,
default: false
},
visible: {
type: Boolean,
default: false
},
title: {
type: String,
default: '标题'
},
confirmButtonText: {
type: String,
default: '确定'
},
cancelButtonText: {
type: String,
default: '取消'
}
},
watch: {},
components: {},
filters: {},
methods: {
cancel() {
this.$emit('cancel')
this.$emit('update:visible', false)
},
confirm() {
this.$emit('confirm')
this.$emit('update:visible', false)
}
},
created() {},
mounted() {},
computed: {}
}
</script>
<style scoped lang="scss">
#index-container {
}
</style>

View File

@@ -16,6 +16,7 @@ import utils from '@/assets/js/common'
// 生成的数据交互api
import generatedFormat from '@/assets/js/generatedFormat'
import generatedComponents from './generatedComponents'
import RenderDialog from '@/components/RenderDialog/index.vue'
Vue.prototype.$generatedFormat = generatedFormat
Vue.prototype.$utils = utils
Vue.prototype.$generatedDictList = generatedFormat.formatList
@@ -30,6 +31,7 @@ import '@/assets/js/utils/permission' // permission control
Vue.use(ElementUI, { locale })
//二次封装的el-table
Vue.component('RTable', RenderTable)
Vue.component('RDialog', RenderDialog)
Vue.component('RSwiper', RenderSwiper)
Vue.component('RMinerU', RenderMinerU)
// 富文本编辑器

View File

@@ -74,6 +74,15 @@ export default [
title: '知识库新增',
icon: 'el-icon-s-home'
}
},
{
path: '/knowledge/detail/segments',
name: 'knowledge-segments',
component: () => import('@/views/knowledge/detail/components/viewSegments/index.vue'),
meta: {
title: '分段查看',
icon: 'el-icon-s-home'
}
}
]
}
@@ -138,6 +147,28 @@ export default [
}
]
},
{
path: '/dify',
name: 'dify',
component: layout,
redirect: '/dify/workflow',
meta: {
title: 'Dify',
icon: 'el-icon-home',
affix: true
},
children: [
{
path: '/dify/workflow',
name: 'dify-workflow',
component: () => import('@/views/dify/views/workflow/index.vue'),
meta: {
title: 'Dify',
icon: 'el-icon-home'
}
}
]
},
{
path: '/system',
name: 'system',

18
src/views/dify/index.vue Normal file
View File

@@ -0,0 +1,18 @@
<script>
export default {
name: 'dify',
data() {
return {
dify: {
src: '/dify'
}
}
}
}
</script>
<template>
<div class="container"></div>
</template>
<style lang="scss" scoped></style>

View File

@@ -0,0 +1,77 @@
<script>
import { computed } from 'vue'
export default {
name: 'workflow',
data() {
return {
dify: {
// 默认不展示 header 和 sidebar
params: {
sidebar: '0',
header: '0',
publish: '0'
},
isVisible: false,
// dify 的 workflow 地址格式 http://localhost:3000/dify/app/235427ea-803b-482b-bdff-dd717801ca76/workflow
// app 是展示所有的内容
src: `/`
}
}
},
computed: {
params() {
const _params = []
Object.keys(this.dify.params).forEach(key => {
_params.push(`${key}=${this.dify.params[key]}`)
})
return _params.join('&')
}
},
// http://192.168.3.229:3000/apps
created() {
// 检测是否存在 workflow id 如果不存在则不展示内容
const { id, header, sidebar, publish } = this.$route.query
if (id) {
this.dify.src = `/app/${id}/workflow?${this.params}`
this.dify.isVisible = true
}
// 获取 header 和 sidebar 的内容, 重置参数状态
this.dify.params.header = header || '0'
this.dify.params.sidebar = sidebar || '0'
this.dify.params.publish = publish || '0'
},
watch: {
'$route.query': {
handler() {
// 获取 header 和 sidebar 的内容, 重置参数状态
const { id, header, sidebar, publish } = this.$route.query
this.dify.params.header = header || '0'
this.dify.params.sidebar = sidebar || '0'
this.dify.params.publish = publish || '0'
// 当路由参数 id 变化时,更新 dify 的 src
if (id) {
console.log(`current params:`, this.dify.params)
this.dify.src = `/app/${id}/workflow?${this.params}`
this.dify.isVisible = true
} else {
this.dify.isVisible = false
}
},
deep: true
}
}
}
</script>
<template>
<div class="container">
<el-card :body-style="{ padding: 0 }" shadow="hover">
<iframe v-if="dify.isVisible" ref="dify" :src="dify.src" frameborder="0" style="width: 100%; height: 85vh;" />
<el-empty v-else />
</el-card>
</div>
</template>

View File

@@ -23,7 +23,7 @@
</div>
<!-- 弹窗 -->
<el-dialog title="问答详情" :visible.sync="dialogVisible" width="50%" append-to-body :before-close="handleClose">
<r-dialog title="问答详情" :visible.sync="dialogVisible" width="50%" append-to-body :before-close="handleClose">
<div v-if="activeSegment !== null && descriptions.data && descriptions.data.length > 0">
<div class="segment-content">
<div>
@@ -49,9 +49,9 @@
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false" class="render-button"> </el-button>
</span>
</el-dialog>
</r-dialog>
</div>
</template>
<script>

View File

@@ -20,26 +20,26 @@
</div>
<!-- 弹窗 -->
<el-dialog title="分段详情" :visible.sync="dialogVisible" width="50%" append-to-body :before-close="handleClose">
<r-dialog title="分段详情" :visible.sync="dialogVisible" width="50%" append-to-body :before-close="handleClose">
<div v-if="activeSegment !== null && descriptions.data && descriptions.data.length > 0">
<div class="segment-content">
{{ descriptions.data[activeSegment].content }}
<div
class="flex align-items-c mt20"
v-if="descriptions.data[activeSegment].keywords && descriptions.data[activeSegment].keywords.length"
style="width: max-content"
style="flex-wrap: wrap"
>
<span>关键词 </span>
<el-tag v-for="(item, index) in descriptions.data[activeSegment].keywords" :key="index" class="mr10" size="mini" type="primary">
<el-tag v-for="(item, index) in descriptions.data[activeSegment].keywords" :key="index" class="mr10 ellipsis" size="mini" type="primary">
{{ item }}
</el-tag>
</div>
</div>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="dialogVisible = false"> </el-button>
<el-button @click="dialogVisible = false" class="render-button"> </el-button>
</span>
</el-dialog>
</r-dialog>
</div>
</template>
<script>

View File

@@ -59,6 +59,7 @@
<!-- 添加预览组件 -->
<split-preview
:documentId="documentId"
:visible.sync="previewVisible"
:preview-data="previewData"
:is-auto-split="activeIndex === 0"
@@ -104,7 +105,12 @@ export default {
]
}
},
props: {},
props: {
documentId: {
type: String,
default: ''
}
},
watch: {},
filters: {},
methods: {

View File

@@ -9,16 +9,23 @@
</div>
<span slot="footer" class="dialog-footer">
<el-button size="medium" @click="handleReUpload">重新上传</el-button>
<el-button size="medium" type="primary" @click="handleConfirm">完成</el-button>
<el-button size="medium" type="primary" @click="handleConfirm">下一步</el-button>
<el-button size="medium" type="primary" @click="emitKnowledgeDataset">直接上传至知识库</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import { embedding } from '@/api/generatedApi'
export default {
name: 'SplitPreview',
props: {
documentId: {
type: String,
default: ''
},
visible: {
type: Boolean,
default: false
@@ -44,6 +51,19 @@ export default {
}
},
methods: {
emitKnowledgeDataset() {
embedding({ documentId: this.documentId }).then(res => {
if (res) {
this.$router.push({
path: '/knowledge/detail/segments',
query: {
documentId: this.documentId,
datasetId: this.$route.query.datasetId
}
})
}
})
},
handleNodeClick() {},
handleClose() {
this.$emit('update:visible', false)

View File

@@ -0,0 +1,40 @@
<template>
<div>
<KnowledgeInfo :form="{ id: this.$route.query.documentId }"></KnowledgeInfo>
<div style="position: absolute;bottom:0;right:10px;width: 100%;height:50px;background: #fff;text-align: right">
<el-button size="medium" @click="back">返回</el-button>
</div>
</div>
</template>
<script>
import KnowledgeInfo from '@/views/track/views/knowledge-info/Index.vue'
export default {
name: 'index',
data() {
return {}
},
props: {},
watch: {},
components: {
KnowledgeInfo
},
filters: {},
methods: {
back() {
this.$router.push({
path: '/knowledge/detail',
query: {
datasetId: this.$route.query.datasetId
}
})
}
},
created() {},
mounted() {},
computed: {}
}
</script>
<style scoped lang="scss">
#index-container {
}
</style>

View File

@@ -19,6 +19,7 @@
v-if="active === 1"
@previewConfirmed="handlePreviewConfirm"
@handleReUpload="handleReUpload"
:documentId="documentId"
></step-split-config>
<step-words ref="words" v-if="active === 2"></step-words>
</transition>
@@ -54,7 +55,7 @@ export default {
return {
visible: false,
active: 0,
documentId: '1363864715567140864'
documentId: '1364315544778543104'
}
},
props: {},

View File

@@ -183,12 +183,13 @@ export default {
margin-bottom: 20px;
.knowledge-content {
min-height: 300px;
min-height: 250px;
}
}
.full-height {
height: calc(100% - 20px);
height: 100%;
padding-bottom: 20px;
}
.mt20 {

View File

@@ -34,6 +34,28 @@ module.exports = {
errors: true
},
proxy: {
'/app': {
target: 'http://localhost:3000',
changeOrigin: true,
onProxyRes: (proxyRes, req, res) => {
delete proxyRes.headers['x-frame-options']
},
pathRewrite: {
// '^/app': '/'
},
logLevel: 'debug'
},
'/_next': {
target: 'http://localhost:3000',
changeOrigin: true,
onProxyRes: (proxyRes, req, res) => {
delete proxyRes.headers['x-frame-options']
},
pathRewrite: {
// '^/_next': '/'
},
logLevel: 'debug'
},
'/api': {
target: process.env.VUE_APP_ADMIN,
changeOrigin: true,