mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
分段模块
This commit is contained in:
parent
e452a942be
commit
48257eacff
|
|
@ -196,6 +196,30 @@ const delParagraph: (
|
|||
return del(`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建段落
|
||||
* @param 参数
|
||||
* dataset_id, document_id
|
||||
* {
|
||||
"content": "string",
|
||||
"title": "string",
|
||||
"is_active": true,
|
||||
"problem_list": [
|
||||
{
|
||||
"id": "string",
|
||||
"content": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
const postParagraph: (
|
||||
dataset_id: string,
|
||||
document_id: string,
|
||||
data: any
|
||||
) => Promise<Result<any>> = (dataset_id, document_id, data: any) => {
|
||||
return post(`${prefix}/${dataset_id}/document/${document_id}/paragraph`, data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改段落
|
||||
* @param 参数
|
||||
|
|
@ -236,5 +260,6 @@ export default {
|
|||
getDocumentDetail,
|
||||
getParagraph,
|
||||
delParagraph,
|
||||
putParagraph
|
||||
putParagraph,
|
||||
postParagraph
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
v-model="inputValue"
|
||||
placeholder="请输入文档名称"
|
||||
class="w-240 mr-12"
|
||||
autofocus
|
||||
/>
|
||||
|
||||
<el-button type="primary" @click="submitHandle" :disabled="loading">创建</el-button>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import CardAdd from './card-add/index.vue'
|
|||
import BackButton from './back-button/index.vue'
|
||||
import AppTable from './app-table/index.vue'
|
||||
import ReadWrite from './read-write/index.vue'
|
||||
import TagEllipsis from './tag-ellipsis/index.vue'
|
||||
|
||||
export default {
|
||||
install(app: App) {
|
||||
|
|
@ -24,5 +25,6 @@ export default {
|
|||
app.component(BackButton.name, BackButton)
|
||||
app.component(AppTable.name, AppTable)
|
||||
app.component(ReadWrite.name, ReadWrite)
|
||||
app.component(TagEllipsis.name, TagEllipsis)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,10 @@
|
|||
</slot>
|
||||
<slot>
|
||||
<div class="flex align-center" v-if="isEdit">
|
||||
<el-input ref="inputRef" v-model="writeValue" placeholder="请输入"></el-input>
|
||||
<div @click.stop>
|
||||
<el-input ref="inputRef" v-model="writeValue" placeholder="请输入" autofocus></el-input>
|
||||
</div>
|
||||
|
||||
<span class="ml-4">
|
||||
<el-button type="primary" text @click.stop="submit" :disabled="loading">
|
||||
<el-icon><Select /></el-icon>
|
||||
|
|
@ -26,7 +29,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { ref, watch, onMounted, nextTick } from 'vue'
|
||||
defineOptions({ name: 'ReadWrite' })
|
||||
const props = defineProps({
|
||||
data: {
|
||||
|
|
@ -39,6 +42,7 @@ const props = defineProps({
|
|||
}
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
const inputRef = ref()
|
||||
const isEdit = ref(false)
|
||||
const writeValue = ref('')
|
||||
const loading = ref(false)
|
||||
|
|
@ -61,5 +65,11 @@ function editNameHandle(row: any) {
|
|||
writeValue.value = props.data
|
||||
isEdit.value = true
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
inputRef.value?.focus()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<el-tag class="tag-ellipsis flex-between mb-8" effect="plain" v-bind="$attrs">
|
||||
<el-tooltip
|
||||
:disabled="!isShowTooltip"
|
||||
effect="dark"
|
||||
:content="tooltipContent"
|
||||
placement="bottom"
|
||||
>
|
||||
<div ref="tagLabel">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</el-tag>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, useSlots } from 'vue'
|
||||
defineOptions({ name: 'TagEllipsis' })
|
||||
const slots = useSlots()
|
||||
const tooltipContent = slots.default()?.[0].children || ''
|
||||
const tagLabel = ref()
|
||||
const isShowTooltip = computed(() => {
|
||||
const containerWeight = tagLabel.value?.scrollWidth
|
||||
const contentWeight = tagLabel.value?.clientWidth
|
||||
if (containerWeight > contentWeight) {
|
||||
// 实际宽度 > 可视宽度
|
||||
return true
|
||||
} else {
|
||||
// 否则为不溢出
|
||||
return false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
// tag超出省略号
|
||||
.tag-ellipsis {
|
||||
border: 1px solid var(--el-border-color);
|
||||
color: var(--app-text-color);
|
||||
border-radius: 4px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
padding: 0 9px;
|
||||
box-sizing: border-box;
|
||||
|
||||
:deep(.el-tag__content) {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
:deep(.el-tooltip__trigger) {
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -59,7 +59,7 @@
|
|||
</el-input>
|
||||
<el-button
|
||||
size="large"
|
||||
class="send-email-button ml-10"
|
||||
class="send-email-button ml-16"
|
||||
@click="sendEmail"
|
||||
:loading="loading"
|
||||
>获取验证码</el-button
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const datasetRouter = {
|
|||
children: [
|
||||
{
|
||||
path: 'document',
|
||||
name: 'DatasetDocument',
|
||||
name: 'Document',
|
||||
meta: {
|
||||
icon: 'Document',
|
||||
title: '文档',
|
||||
|
|
@ -34,7 +34,7 @@ const datasetRouter = {
|
|||
parentPath: '/dataset/:datasetId',
|
||||
parentName: 'DatasetDetail'
|
||||
},
|
||||
component: () => import('@/views/dataset/DatasetDocument.vue')
|
||||
component: () => import('@/views/document/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'setting',
|
||||
|
|
@ -46,15 +46,15 @@ const datasetRouter = {
|
|||
parentPath: '/dataset/:datasetId',
|
||||
parentName: 'DatasetDetail'
|
||||
},
|
||||
component: () => import('@/views/dataset/DatasetSetting.vue')
|
||||
component: () => import('@/views/document/DatasetSetting.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/dataset/:datasetId/:documentId', // 分段详情
|
||||
name: 'DocumentDetail',
|
||||
name: 'Paragraph',
|
||||
meta: { activeMenu: '/dataset' },
|
||||
component: () => import('@/views/dataset/DocumentDetail.vue'),
|
||||
component: () => import('@/views/paragraph/index.vue'),
|
||||
hidden: true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ const store = createPinia()
|
|||
export { store }
|
||||
import useUserStore from './modules/user'
|
||||
import useDatasetStore from './modules/dataset'
|
||||
import useParagraphStore from './modules/paragraph'
|
||||
|
||||
const useStore = () => ({
|
||||
user: useUserStore(),
|
||||
dataset: useDatasetStore()
|
||||
dataset: useDatasetStore(),
|
||||
paragraph: useParagraphStore(),
|
||||
})
|
||||
|
||||
export default useStore
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import datasetApi from '@/api/dataset'
|
||||
|
||||
const useParagraphStore = defineStore({
|
||||
id: 'paragraph',
|
||||
state: () => ({}),
|
||||
actions: {
|
||||
async asyncPutParagraph(datasetId: string, documentId: string, paragraphId: string, data: any) {
|
||||
return new Promise((resolve, reject) => {
|
||||
datasetApi
|
||||
.putParagraph(datasetId, documentId, paragraphId, data)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default useParagraphStore
|
||||
|
|
@ -292,3 +292,5 @@ h4 {
|
|||
.primary {
|
||||
color: var(--el-color-primary);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
--el-color-primary-light-9: rgba(51, 112, 255, 0.1);
|
||||
--el-menu-item-height: 45px;
|
||||
--el-box-shadow-light: 0px 2px 4px 0px rgba(31, 35, 41, 0.12);
|
||||
--el-border-color: #DEE0E3;
|
||||
--el-border-color: #dee0e3;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
|
|
@ -74,17 +74,21 @@
|
|||
}
|
||||
|
||||
@media only screen and (min-width: 1400px) {
|
||||
.el-col-lg-6 {
|
||||
display: block;
|
||||
max-width: 20.8333333333%;
|
||||
flex: 0 0 20.8333333333%;
|
||||
.app-list-row {
|
||||
.el-col-lg-6 {
|
||||
display: block;
|
||||
max-width: 20.8333333333%;
|
||||
flex: 0 0 20.8333333333%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media only screen and (min-width: 1920px) {
|
||||
.el-col-xl-4 {
|
||||
display: block;
|
||||
max-width: 16.6666666667%;
|
||||
flex: 0 0 16.6666666667%;
|
||||
.app-list-row {
|
||||
.el-col-xl-4 {
|
||||
display: block;
|
||||
max-width: 16.6666666667%;
|
||||
flex: 0 0 16.6666666667%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ function clearStore() {
|
|||
function submit() {
|
||||
loading.value = true
|
||||
const documents = [] as any[]
|
||||
StepSecondRef.value.segmentList.map((item: any) => {
|
||||
StepSecondRef.value.paragraphList.map((item: any) => {
|
||||
documents.push({
|
||||
name: item.name,
|
||||
paragraphs: item.content
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
</el-form>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed, watch } from 'vue'
|
||||
import { ref, reactive, onMounted, onUnmounted, computed, watch } from 'vue'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const props = defineProps({
|
||||
|
|
@ -73,7 +73,12 @@ onMounted(() => {
|
|||
form.value = baseInfo.value
|
||||
}
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
form.value = {
|
||||
name: '',
|
||||
desc: ''
|
||||
}
|
||||
})
|
||||
defineExpose({
|
||||
validate,
|
||||
form
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<template>
|
||||
<el-dialog title="编辑分段" v-model="dialogVisible" width="600">
|
||||
<ParagraphForm ref="paragraphFormRef" :data="detail" />
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submitHandle"> 保存 </el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import ParagraphForm from '@/views/paragraph/component/ParagraphForm.vue'
|
||||
|
||||
const emit = defineEmits(['updateContent'])
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const detail = ref({})
|
||||
|
||||
const paragraphFormRef = ref()
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
detail.value = {}
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
detail.value = cloneDeep(data)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submitHandle = async () => {
|
||||
if (await paragraphFormRef.value?.validate()) {
|
||||
emit('updateContent', paragraphFormRef.value?.form)
|
||||
dialogVisible.value = false
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope></style>
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
<template>
|
||||
<el-dialog title="编辑分段" v-model="dialogVisible" width="600">
|
||||
<el-form
|
||||
ref="segmentFormRef"
|
||||
:model="segmentForm"
|
||||
label-position="top"
|
||||
:rules="rules"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="分段标题">
|
||||
<el-input v-model="segmentForm.title" placeholder="请输入分段标题"> </el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分段内容" prop="content">
|
||||
<el-input
|
||||
v-model="segmentForm.content"
|
||||
placeholder="请输入分段内容"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:autosize="{ minRows: 3, maxRow: 8 }"
|
||||
type="textarea"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submitHandle(segmentFormRef)"> 保存 </el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
const emit = defineEmits(['updateContent'])
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const segmentForm = ref({
|
||||
title: '',
|
||||
content: ''
|
||||
})
|
||||
|
||||
const segmentFormRef = ref<FormInstance>()
|
||||
|
||||
const rules = ref<FormRules>({
|
||||
content: [{ required: true, message: '请输入分段内容', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
segmentForm.value = {
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
segmentForm.value = cloneDeep(data)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submitHandle = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
emit('updateContent', segmentForm.value)
|
||||
dialogVisible.value = false
|
||||
} else {
|
||||
console.log('error submit!')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope></style>
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
<template>
|
||||
<el-dialog :title="title" v-model="dialogVisible" width="800" class="paragraph-dialog">
|
||||
<el-row>
|
||||
<el-col :span="16" class="p-24">
|
||||
<div class="flex-between mb-16">
|
||||
<div class="bold title align-center">分段内容</div>
|
||||
<el-button text>
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<el-form
|
||||
ref="segmentFormRef"
|
||||
:model="segmentForm"
|
||||
label-position="top"
|
||||
:rules="rules"
|
||||
@submit.prevent
|
||||
>
|
||||
<el-form-item label="分段标题">
|
||||
<el-input v-model="segmentForm.title" placeholder="请输入分段标题"> </el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分段内容" prop="content">
|
||||
<el-input
|
||||
v-model="segmentForm.content"
|
||||
placeholder="请输入分段内容"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
:rows="8"
|
||||
type="textarea"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<div class="text-right">
|
||||
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submitHandle(segmentFormRef)"> 保存 </el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8" class="border-l p-24">
|
||||
<p class="bold title mb-16">
|
||||
关联问题 <el-divider direction="vertical" />
|
||||
<el-button text>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
</p>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { cloneDeep } from 'lodash'
|
||||
|
||||
const props = defineProps({
|
||||
title: String
|
||||
})
|
||||
|
||||
const emit = defineEmits(['updateContent'])
|
||||
|
||||
const segmentFormRef = ref<FormInstance>()
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const segmentForm = ref({
|
||||
title: '',
|
||||
content: ''
|
||||
})
|
||||
|
||||
const rules = ref<FormRules>({
|
||||
content: [{ required: true, message: '请输入分段内容', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const isEdit = ref(false)
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
segmentForm.value = {
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
isEdit.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const open = (data: any) => {
|
||||
if (data) {
|
||||
segmentForm.value.title = data.title
|
||||
segmentForm.value.content = data.content
|
||||
isEdit.value = true
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submitHandle = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
emit('updateContent', segmentForm.value)
|
||||
dialogVisible.value = false
|
||||
} else {
|
||||
console.log('error submit!')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.paragraph-dialog {
|
||||
.el-dialog__header {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.el-dialog__body {
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
padding: 0 !important;
|
||||
}
|
||||
.title {
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<el-tabs v-model="activeName" class="segment-tabs" @tab-click="handleClick">
|
||||
<el-tabs v-model="activeName" class="paragraph-tabs" @tab-click="handleClick">
|
||||
<template v-for="(item, index) in newData" :key="index">
|
||||
<el-tab-pane :label="item.name" :name="index">
|
||||
<template #label>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
</div>
|
||||
</template>
|
||||
<el-scrollbar>
|
||||
<div class="segment-list">
|
||||
<div class="paragraph-list">
|
||||
<el-card
|
||||
v-for="(child, cIndex) in item.content"
|
||||
:key="cIndex"
|
||||
|
|
@ -41,12 +41,12 @@
|
|||
</el-tab-pane>
|
||||
</template>
|
||||
</el-tabs>
|
||||
<EditSegmentDialog ref="EditSegmentDialogRef" @updateContent="updateContent" />
|
||||
<EditParagraphDialog ref="EditParagraphDialogRef" @updateContent="updateContent" />
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, watch } from 'vue'
|
||||
import type { TabsPaneContext } from 'element-plus'
|
||||
import EditSegmentDialog from './EditSegmentDialog.vue'
|
||||
import EditParagraphDialog from './EditParagraphDialog.vue'
|
||||
import { filesize, getImgUrl } from '@/utils/utils'
|
||||
import { MsgConfirm } from '@/utils/message'
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ const props = defineProps({
|
|||
|
||||
const emit = defineEmits(['update:data'])
|
||||
|
||||
const EditSegmentDialogRef = ref()
|
||||
const EditParagraphDialogRef = ref()
|
||||
|
||||
const activeName = ref(0)
|
||||
const currentPIndex = ref(null) as any
|
||||
|
|
@ -81,7 +81,7 @@ watch(
|
|||
function editHandle(item: any, index: number, cIndex: number) {
|
||||
currentPIndex.value = index
|
||||
currentCIndex.value = cIndex
|
||||
EditSegmentDialogRef.value.open(item)
|
||||
EditParagraphDialogRef.value.open(item)
|
||||
}
|
||||
|
||||
function deleteHandle(item: any, index: number, cIndex: number) {
|
||||
|
|
@ -108,7 +108,7 @@ const handleClick = (tab: TabsPaneContext, event: Event) => {
|
|||
onMounted(() => {})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.segment-tabs {
|
||||
.paragraph-tabs {
|
||||
:deep(.el-tabs__item) {
|
||||
background: var(--app-text-color-light-1);
|
||||
margin: 4px;
|
||||
|
|
@ -134,7 +134,7 @@ onMounted(() => {})
|
|||
display: none;
|
||||
}
|
||||
}
|
||||
.segment-list {
|
||||
.paragraph-list {
|
||||
height: calc(var(--create-dataset-height) - 125px);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
</el-row>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import { ref, reactive, onUnmounted, onMounted, computed } from 'vue'
|
||||
import type { UploadProps } from 'element-plus'
|
||||
import { filesize, getImgUrl } from '@/utils/utils'
|
||||
import { MsgError } from '@/utils/message'
|
||||
|
|
@ -92,6 +92,11 @@ onMounted(() => {
|
|||
form.value.fileList = documentsFiles.value
|
||||
}
|
||||
})
|
||||
onUnmounted(() => {
|
||||
form.value = {
|
||||
fileList: []
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
validate,
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
:gutter="15"
|
||||
v-infinite-scroll="loadDataset"
|
||||
:infinite-scroll-disabled="disabledScroll"
|
||||
class="app-list-row"
|
||||
>
|
||||
<el-col :xs="24" :sm="12" :md="8" :lg="6" :xl="4" class="mt-8">
|
||||
<CardAdd title="创建数据集" @click="router.push({ path: '/dataset/create' })" />
|
||||
|
|
|
|||
|
|
@ -21,16 +21,13 @@
|
|||
<div class="form-item mb-16">
|
||||
<div class="title flex align-center mb-8">
|
||||
<span style="margin-right: 4px">分段标识</span>
|
||||
<el-popover
|
||||
placement="right"
|
||||
:width="400"
|
||||
trigger="hover"
|
||||
<el-tooltip
|
||||
effect="dark"
|
||||
content="按照所选符号先后顺序做递归分割,分割结果超出分段长度将截取至分段长度。"
|
||||
placement="right"
|
||||
>
|
||||
<template #reference>
|
||||
<el-icon style="font-size: 16px"><Warning /></el-icon>
|
||||
</template>
|
||||
</el-popover>
|
||||
<el-icon style="font-size: 16px"><Warning /></el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
|
||||
<el-select v-model="form.patterns" multiple placeholder="请选择">
|
||||
|
|
@ -76,7 +73,7 @@
|
|||
<el-col :span="12" class="p-24 border-l">
|
||||
<div v-loading="loading">
|
||||
<h4 class="title-decoration-1 mb-8">分段预览</h4>
|
||||
<SegmentPreview v-model:data="segmentList" />
|
||||
<ParagraphPreview v-model:data="paragraphList" />
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
|
@ -84,7 +81,7 @@
|
|||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, reactive } from 'vue'
|
||||
import SegmentPreview from '@/views/dataset/component/SegmentPreview.vue'
|
||||
import ParagraphPreview from '@/views/dataset/component/ParagraphPreview.vue'
|
||||
import DatasetApi from '@/api/dataset'
|
||||
import useStore from '@/stores'
|
||||
const { dataset } = useStore()
|
||||
|
|
@ -98,7 +95,7 @@ const marks = reactive({
|
|||
|
||||
const radio = ref('1')
|
||||
const loading = ref(false)
|
||||
const segmentList = ref<any[]>([])
|
||||
const paragraphList = ref<any[]>([])
|
||||
|
||||
const form = reactive<any>({
|
||||
patterns: [] as any,
|
||||
|
|
@ -123,7 +120,7 @@ function splitDocument() {
|
|||
}
|
||||
DatasetApi.postSplitDocument(fd)
|
||||
.then((res: any) => {
|
||||
segmentList.value = res.data
|
||||
paragraphList.value = res.data
|
||||
loading.value = false
|
||||
})
|
||||
.catch(() => {
|
||||
|
|
@ -136,7 +133,7 @@ onMounted(() => {
|
|||
})
|
||||
|
||||
defineExpose({
|
||||
segmentList
|
||||
paragraphList
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
</el-input>
|
||||
<el-button
|
||||
size="large"
|
||||
class="send-email-button ml-10"
|
||||
class="send-email-button ml-16"
|
||||
@click="sendEmail"
|
||||
:loading="loading"
|
||||
>获取验证码</el-button
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
</el-input>
|
||||
<el-button
|
||||
size="large"
|
||||
class="send-email-button ml-10"
|
||||
class="send-email-button ml-16"
|
||||
@click="sendEmail"
|
||||
:loading="sendEmailLoading"
|
||||
>获取验证码</el-button
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
:title="title"
|
||||
v-model="dialogVisible"
|
||||
width="800"
|
||||
class="paragraph-dialog"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-row>
|
||||
<el-col :span="16" class="p-24">
|
||||
<div class="flex-between mb-16">
|
||||
<div class="bold title align-center">分段内容</div>
|
||||
<el-button text v-if="pId">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<ParagraphForm ref="paragraphFormRef" :data="detail" />
|
||||
<div class="text-right">
|
||||
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||
<el-button type="primary" :disabled="loading" @click="submitHandle"> 保存 </el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="8" class="border-l p-24">
|
||||
<p class="bold title mb-16">
|
||||
关联问题 <el-divider direction="vertical" />
|
||||
<el-button text>
|
||||
<el-icon><Plus /></el-icon>
|
||||
</el-button>
|
||||
</p>
|
||||
<el-input
|
||||
v-model="questionValue"
|
||||
@change="addQuestion"
|
||||
placeholder="请输入问题,回车保存"
|
||||
class="mb-8"
|
||||
/>
|
||||
<template v-for="(item, index) in questionList" :key="index">
|
||||
<TagEllipsis class="question-tag" type="info" effect="plain" closable>
|
||||
{{ item.content }}
|
||||
</TagEllipsis>
|
||||
</template>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import ParagraphForm from '@/views/paragraph/component/ParagraphForm.vue'
|
||||
import datasetApi from '@/api/dataset'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const props = defineProps({
|
||||
title: String
|
||||
})
|
||||
|
||||
const { paragraph } = useStore()
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { datasetId, documentId }
|
||||
} = route as any
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const paragraphFormRef = ref<FormInstance>()
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const loading = ref(false)
|
||||
const pId = ref('')
|
||||
const detail = ref<any>({})
|
||||
const isEdit = ref(false)
|
||||
|
||||
const questionValue = ref('')
|
||||
const questionList = ref<any[]>([])
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
pId.value = ''
|
||||
detail.value = {}
|
||||
isEdit.value = false
|
||||
}
|
||||
})
|
||||
|
||||
function addQuestion() {}
|
||||
|
||||
const open = (data: any) => {
|
||||
if (data) {
|
||||
detail.value.title = data.title
|
||||
detail.value.content = data.content
|
||||
pId.value = data.id
|
||||
isEdit.value = true
|
||||
}
|
||||
dialogVisible.value = true
|
||||
}
|
||||
const submitHandle = async () => {
|
||||
if (await paragraphFormRef.value?.validate()) {
|
||||
loading.value = true
|
||||
if (id) {
|
||||
paragraph
|
||||
.asyncPutParagraph(datasetId, documentId, pId, paragraphFormRef.value?.form)
|
||||
.then((res) => {
|
||||
emit('refresh')
|
||||
loading.value = false
|
||||
dialogVisible.value = false
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
datasetApi
|
||||
.postParagraph(datasetId, documentId, paragraphFormRef.value?.form)
|
||||
.then((res) => {
|
||||
emit('refresh')
|
||||
loading.value = false
|
||||
dialogVisible.value = false
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.paragraph-dialog {
|
||||
.el-dialog__header {
|
||||
padding-bottom: 16px;
|
||||
}
|
||||
.el-dialog__body {
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
padding: 0 !important;
|
||||
}
|
||||
.title {
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
.question-tag {
|
||||
width: 217px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
<template>
|
||||
<el-form ref="paragraphFormRef" :model="form" label-position="top" :rules="rules" @submit.prevent>
|
||||
<el-form-item label="分段标题">
|
||||
<el-input v-model="form.title" placeholder="请输入分段标题"> </el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="分段内容" prop="content">
|
||||
<el-input
|
||||
v-model="form.content"
|
||||
placeholder="请输入分段内容"
|
||||
maxlength="1024"
|
||||
show-word-limit
|
||||
:rows="8"
|
||||
type="textarea"
|
||||
>
|
||||
</el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, onUnmounted, watch } from 'vue'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
data: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
}
|
||||
})
|
||||
|
||||
const form = ref<any>({
|
||||
title: '',
|
||||
content: ''
|
||||
})
|
||||
|
||||
const rules = reactive<FormRules>({
|
||||
content: [{ required: true, message: '请输入分段内容', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const paragraphFormRef = ref<FormInstance>()
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(value) => {
|
||||
if (value && JSON.stringify(value) !== '{}') {
|
||||
form.value.title = value.title
|
||||
form.value.content = value.content
|
||||
}
|
||||
},
|
||||
{
|
||||
// 初始化立即执行
|
||||
immediate: true
|
||||
}
|
||||
)
|
||||
|
||||
// 表单校验
|
||||
function validate() {
|
||||
if (!paragraphFormRef.value) return
|
||||
return paragraphFormRef.value.validate((valid: any) => {
|
||||
return valid
|
||||
})
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
form.value = {
|
||||
title: '',
|
||||
content: ''
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
validate,
|
||||
form
|
||||
})
|
||||
</script>
|
||||
<style scoped lang="scss"></style>
|
||||
|
|
@ -64,18 +64,18 @@
|
|||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<ParagraphDialog ref="ParagraphDialogRef" :title="title" />
|
||||
<ParagraphDialog ref="ParagraphDialogRef" :title="title" @refresh="refresh" />
|
||||
</LayoutContainer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import datasetApi from '@/api/dataset'
|
||||
import ParagraphDialog from './component/ParagraphDialog.vue'
|
||||
import { numberFormat } from '@/utils/utils'
|
||||
import { MsgSuccess, MsgConfirm } from '@/utils/message'
|
||||
|
||||
const router = useRouter()
|
||||
import useStore from '@/stores'
|
||||
const { paragraph } = useStore()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { datasetId, documentId }
|
||||
|
|
@ -94,8 +94,8 @@ function changeState(bool: Boolean, row: any) {
|
|||
is_active: bool
|
||||
}
|
||||
loading.value = true
|
||||
datasetApi
|
||||
.putParagraph(datasetId, documentId, row.id, obj)
|
||||
paragraph
|
||||
.asyncPutParagraph(datasetId, documentId, row.id, obj)
|
||||
.then((res) => {
|
||||
loading.value = false
|
||||
})
|
||||
|
|
@ -128,7 +128,7 @@ function addParagraph() {
|
|||
title.value = '添加分段'
|
||||
ParagraphDialogRef.value.open()
|
||||
}
|
||||
function editParagraph(row: any) {
|
||||
function editParagraph(row: any) {
|
||||
title.value = '分段详情'
|
||||
ParagraphDialogRef.value.open(row)
|
||||
}
|
||||
|
|
@ -159,6 +159,10 @@ function getParagraphDetail() {
|
|||
})
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
getParagraphDetail()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getDetail()
|
||||
getParagraphDetail()
|
||||
Loading…
Reference in New Issue