mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-28 14:52:58 +00:00
feat: 段落模块
This commit is contained in:
parent
76dd9d2192
commit
e452a942be
|
|
@ -184,6 +184,43 @@ const getParagraph: (dataset_id: string, document_id: string) => Promise<Result<
|
|||
return get(`${prefix}/${dataset_id}/document/${document_id}/paragraph`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除段落
|
||||
* @param 参数 dataset_id, document_id, document_id
|
||||
*/
|
||||
const delParagraph: (
|
||||
dataset_id: string,
|
||||
document_id: string,
|
||||
paragraph_id: string
|
||||
) => Promise<Result<boolean>> = (dataset_id, document_id, paragraph_id) => {
|
||||
return del(`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改段落
|
||||
* @param 参数
|
||||
* dataset_id, document_id, paragraph_id
|
||||
* {
|
||||
"content": "string",
|
||||
"title": "string",
|
||||
"is_active": true,
|
||||
"problem_list": [
|
||||
{
|
||||
"id": "string",
|
||||
"content": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
const putParagraph: (
|
||||
dataset_id: string,
|
||||
document_id: string,
|
||||
paragraph_id: string,
|
||||
data: any
|
||||
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, data: any) => {
|
||||
return put(`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}`, data)
|
||||
}
|
||||
|
||||
export default {
|
||||
getDateset,
|
||||
getAllDateset,
|
||||
|
|
@ -197,5 +234,7 @@ export default {
|
|||
putDocument,
|
||||
delDocument,
|
||||
getDocumentDetail,
|
||||
getParagraph
|
||||
getParagraph,
|
||||
delParagraph,
|
||||
putParagraph
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,9 +67,13 @@ function cardLeave() {
|
|||
.card-footer {
|
||||
position: absolute;
|
||||
bottom: 8px;
|
||||
left: 0;
|
||||
min-height: 30px;
|
||||
color: var(--app-text-color-secondary);
|
||||
font-weight: 400;
|
||||
padding: 0 16px;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ body {
|
|||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
|
||||
#app {
|
||||
|
|
@ -135,7 +135,7 @@ h4 {
|
|||
margin-right: calc(var(--app-base-px) + 4px);
|
||||
}
|
||||
.mr-16 {
|
||||
margin-right: calc(var(--app-base-px) * 3);
|
||||
margin-right: calc(var(--app-base-px) * 2);
|
||||
}
|
||||
|
||||
.p-8 {
|
||||
|
|
@ -212,6 +212,7 @@ h4 {
|
|||
// 内容部分 自适应高度
|
||||
.main-calc-height {
|
||||
height: var(--app-main-height);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// 标题前带竖线样式
|
||||
|
|
|
|||
|
|
@ -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: rgba(31, 35, 41, 0.15);
|
||||
--el-border-color: #DEE0E3;
|
||||
}
|
||||
|
||||
.el-button {
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
font-size: 16px;
|
||||
max-height: 24px;
|
||||
&:not(.is-disabled):hover {
|
||||
background: var(--app-text-color-primary-light-1);
|
||||
background: var(--app-text-color-light-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
.el-message-box__content {
|
||||
padding: 24px 0;
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
font-weight: 400;
|
||||
}
|
||||
.el-message-box__btns {
|
||||
|
|
@ -62,6 +62,7 @@
|
|||
button.danger {
|
||||
background: var(--el-color-danger);
|
||||
border: var(--el-color-danger);
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
.el-message-box__headerbtn {
|
||||
|
|
@ -92,7 +93,7 @@
|
|||
--el-card-padding: calc(var(--app-base-px) * 2);
|
||||
}
|
||||
.el-dropdown {
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
|
||||
.el-tag {
|
||||
|
|
@ -100,7 +101,7 @@
|
|||
}
|
||||
.el-table {
|
||||
--el-table-header-bg-color: var(--app-layout-bg-color);
|
||||
--el-table-text-color: var(--app-text-color-primary);
|
||||
--el-table-text-color: var(--app-text-color);
|
||||
font-weight: 400;
|
||||
thead {
|
||||
color: var(--app-text-color-secondary);
|
||||
|
|
@ -165,3 +166,14 @@
|
|||
.el-slider__input {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.input-with-select {
|
||||
.el-input__wrapper {
|
||||
// border: 1px solid var(--el-border-color);
|
||||
// box-shadow: none!important;
|
||||
}
|
||||
|
||||
.el-input-group__prepend {
|
||||
background-color: var(--el-fill-color-blank);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
:root {
|
||||
--app-base-px: 8px;
|
||||
--app-layout-bg-color: #f5f6f7;
|
||||
--app-text-color-primary: #1f2329;
|
||||
--app-text-color-primary-light-1: rgba(31, 35, 41, 0.1);
|
||||
--app-text-color: #1f2329;
|
||||
--app-text-color-light-1: rgba(31, 35, 41, 0.1);
|
||||
--app-text-color-secondary: #646a73;
|
||||
--app-text-color-disable: #bbbfc4;
|
||||
--app-view-padding: 24px;
|
||||
--app-view-bg-color: #ffffff;
|
||||
--app-border-color-dark: #bbbfc4;
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ const router = useRouter()
|
|||
}
|
||||
|
||||
.message-container {
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
|
||||
.title {
|
||||
font-size: 50px;
|
||||
|
|
|
|||
|
|
@ -167,7 +167,6 @@ function submit() {
|
|||
width: 100%;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
&__footer {
|
||||
padding: 16px 24px;
|
||||
|
|
|
|||
|
|
@ -1,61 +1,79 @@
|
|||
<template>
|
||||
<LayoutContainer :header="documentDetail?.name" back-to="-1" class="dataset-detail">
|
||||
<LayoutContainer :header="documentDetail?.name" back-to="-1" class="document-detail">
|
||||
<template #header>
|
||||
<!-- <el-steps :active="active" finish-status="success" align-center class="create-dataset__steps">
|
||||
<el-step v-for="(item, index) in steps" :key="index">
|
||||
<template #icon>
|
||||
<div class="app-step flex align-center">
|
||||
<div class="el-step__icon is-text">
|
||||
<div class="el-step__icon-inner">
|
||||
<el-icon v-if="active == index + 1" style="margin-top: 1px"><Select /></el-icon>
|
||||
<span v-else> {{ index + 1 }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="ml-4">{{ item.name }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-step>
|
||||
</el-steps> -->
|
||||
<div class="document-detail__header">
|
||||
<el-button @click="addParagraph" type="primary" :disabled="loading"> 添加分段 </el-button>
|
||||
</div>
|
||||
</template>
|
||||
<div class="dataset-detail__main main-calc-height p-24">
|
||||
<el-row :gutter="15">
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
:xl="4"
|
||||
v-for="(item, index) in paragraphDetail"
|
||||
:key="index"
|
||||
class="mt-8"
|
||||
<div class="document-detail__main p-16">
|
||||
<div class="flex-between p-8">
|
||||
<span>{{ paragraphDetail.length }} 段落</span>
|
||||
<el-input
|
||||
v-model="search"
|
||||
placeholder="搜索"
|
||||
class="input-with-select"
|
||||
style="width: 260px"
|
||||
>
|
||||
<CardBox
|
||||
shadow="hover"
|
||||
:title="item.title"
|
||||
:description="item.content"
|
||||
class="cursor"
|
||||
:showIcon="false"
|
||||
>
|
||||
<!-- <template #footer>
|
||||
<div class="footer-content">
|
||||
<span class="bold">{{ item?.document_count || 0 }}</span>
|
||||
文档<el-divider direction="vertical" />
|
||||
<span class="bold">{{ numberFormat(item?.char_length) || 0 }}</span>
|
||||
字符<el-divider direction="vertical" />
|
||||
<span class="bold">{{ item?.char_length || 0 }}</span>
|
||||
关联应用
|
||||
</div>
|
||||
</template> -->
|
||||
</CardBox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<template #prepend>
|
||||
<el-select v-model="searchType" placeholder="Select" style="width: 80px">
|
||||
<el-option label="标题" value="title" />
|
||||
<el-option label="内容" value="content" />
|
||||
</el-select>
|
||||
</template>
|
||||
</el-input>
|
||||
</div>
|
||||
<el-scrollbar>
|
||||
<div class="document-detail-height" v-loading="loading">
|
||||
<el-row>
|
||||
<el-col
|
||||
:xs="24"
|
||||
:sm="12"
|
||||
:md="8"
|
||||
:lg="6"
|
||||
:xl="4"
|
||||
v-for="(item, index) in paragraphDetail"
|
||||
:key="index"
|
||||
class="p-8"
|
||||
>
|
||||
<CardBox
|
||||
shadow="hover"
|
||||
:title="item.title"
|
||||
:description="item.content"
|
||||
class="document-card cursor"
|
||||
:class="item.is_active ? '' : 'disabled'"
|
||||
:showIcon="false"
|
||||
@click="editParagraph(item)"
|
||||
>
|
||||
<div class="active-button">
|
||||
<el-switch v-model="item.is_active" @change="changeState($event, item)" />
|
||||
</div>
|
||||
|
||||
<template #footer>
|
||||
<div class="footer-content flex-between">
|
||||
<span> {{ numberFormat(item?.content.length) || 0 }} 个 字符 </span>
|
||||
<el-tooltip effect="dark" content="删除" placement="top">
|
||||
<el-button text @click.stop="deleteParagraph(item)" class="delete-button">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
</template>
|
||||
</CardBox>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</div>
|
||||
<ParagraphDialog ref="ParagraphDialogRef" :title="title" />
|
||||
</LayoutContainer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter, 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()
|
||||
const route = useRoute()
|
||||
|
|
@ -63,9 +81,57 @@ const {
|
|||
params: { datasetId, documentId }
|
||||
} = route as any
|
||||
|
||||
const ParagraphDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
const documentDetail = ref<any>({})
|
||||
const paragraphDetail = ref<any[]>([])
|
||||
const title = ref('')
|
||||
const search = ref('')
|
||||
const searchType = ref('title')
|
||||
|
||||
function changeState(bool: Boolean, row: any) {
|
||||
const obj = {
|
||||
is_active: bool
|
||||
}
|
||||
loading.value = true
|
||||
datasetApi
|
||||
.putParagraph(datasetId, documentId, row.id, obj)
|
||||
.then((res) => {
|
||||
loading.value = false
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function deleteParagraph(row: any) {
|
||||
MsgConfirm(`是否删除段落:${row.title} ?`, `删除后无法恢复,请谨慎操作。`, {
|
||||
confirmButtonText: '删除',
|
||||
confirmButtonClass: 'danger'
|
||||
})
|
||||
.then(() => {
|
||||
loading.value = true
|
||||
datasetApi
|
||||
.delParagraph(datasetId, documentId, row.id)
|
||||
.then(() => {
|
||||
MsgSuccess('删除成功')
|
||||
getParagraphDetail()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
function addParagraph() {
|
||||
title.value = '添加分段'
|
||||
ParagraphDialogRef.value.open()
|
||||
}
|
||||
function editParagraph(row: any) {
|
||||
title.value = '分段详情'
|
||||
ParagraphDialogRef.value.open(row)
|
||||
}
|
||||
|
||||
function getDetail() {
|
||||
loading.value = true
|
||||
|
|
@ -99,9 +165,42 @@ onMounted(() => {
|
|||
})
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.dataset-detail {
|
||||
&__main{
|
||||
box-sizing: border-box;
|
||||
.document-detail {
|
||||
&__header {
|
||||
position: absolute;
|
||||
right: calc(var(--app-base-px) * 3);
|
||||
}
|
||||
|
||||
.document-detail-height {
|
||||
height: calc(var(--app-main-height) - 75px);
|
||||
}
|
||||
.document-card {
|
||||
height: 210px;
|
||||
background: var(--app-layout-bg-color);
|
||||
border: 1px solid var(--app-layout-bg-color);
|
||||
&:hover {
|
||||
background: #ffffff;
|
||||
border: 1px solid var(--el-border-color);
|
||||
}
|
||||
&.disabled {
|
||||
background: var(--app-layout-bg-color);
|
||||
border: 1px solid var(--app-layout-bg-color);
|
||||
:deep(.description) {
|
||||
color: var(--app-border-color-dark);
|
||||
}
|
||||
:deep(.title) {
|
||||
color: var(--app-border-color-dark);
|
||||
}
|
||||
}
|
||||
:deep(.description) {
|
||||
-webkit-line-clamp: 5 !important;
|
||||
height: 110px;
|
||||
}
|
||||
.active-button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,121 @@
|
|||
<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>
|
||||
|
|
@ -110,7 +110,7 @@ onMounted(() => {})
|
|||
<style scoped lang="scss">
|
||||
.segment-tabs {
|
||||
:deep(.el-tabs__item) {
|
||||
background: var(--app-text-color-primary-light-1);
|
||||
background: var(--app-text-color-light-1);
|
||||
margin: 4px;
|
||||
border-radius: 4px;
|
||||
padding: 5px 10px 5px 8px !important;
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ onMounted(() => {
|
|||
}
|
||||
.footer-content {
|
||||
.bold {
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ defineExpose({
|
|||
height: 100%;
|
||||
padding: calc(var(--app-base-px) * 2);
|
||||
line-height: 22px;
|
||||
color: var(--app-text-color-primary);
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
:deep(.el-radio__label) {
|
||||
padding-left: 32px;
|
||||
|
|
|
|||
Loading…
Reference in New Issue