mirror of
https://github.com/1Panel-dev/MaxKB.git
synced 2025-12-26 01:33:05 +00:00
parent
c67f4633a1
commit
633c005905
|
|
@ -218,7 +218,7 @@ class ParagraphSerializers(ApiMixin, serializers.Serializer):
|
|||
def association(self, with_valid=True, with_embedding=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
problem = QuerySet(Problem).filter(id=self.data.get("problem_id"))
|
||||
problem = QuerySet(Problem).filter(id=self.data.get("problem_id")).first()
|
||||
problem_paragraph_mapping = ProblemParagraphMapping(id=uuid.uuid1(),
|
||||
document_id=self.data.get('document_id'),
|
||||
paragraph_id=self.data.get('paragraph_id'),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"""
|
||||
import os
|
||||
import uuid
|
||||
from typing import Dict
|
||||
from typing import Dict, List
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import QuerySet
|
||||
|
|
@ -83,6 +83,7 @@ class ProblemSerializers(ApiMixin, serializers.Serializer):
|
|||
**{'dataset_id': self.data.get('dataset_id')})
|
||||
if 'content' in self.data:
|
||||
query_set = query_set.filter(**{'content__contains': self.data.get('content')})
|
||||
query_set = query_set.order_by("-create_time")
|
||||
return query_set
|
||||
|
||||
def list(self):
|
||||
|
|
@ -95,6 +96,22 @@ class ProblemSerializers(ApiMixin, serializers.Serializer):
|
|||
return native_page_search(current_page, page_size, query_set, select_string=get_file_content(
|
||||
os.path.join(PROJECT_DIR, "apps", "dataset", 'sql', 'list_problem.sql')))
|
||||
|
||||
class BatchOperate(serializers.Serializer):
|
||||
dataset_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("知识库id"))
|
||||
|
||||
def delete(self, problem_id_list: List, with_valid=True):
|
||||
if with_valid:
|
||||
self.is_valid(raise_exception=True)
|
||||
dataset_id = self.data.get('dataset_id')
|
||||
problem_paragraph_mapping_list = QuerySet(ProblemParagraphMapping).filter(
|
||||
dataset_id=dataset_id,
|
||||
problem_id__in=problem_id_list)
|
||||
source_ids = [row.id for row in problem_paragraph_mapping_list]
|
||||
problem_paragraph_mapping_list.delete()
|
||||
QuerySet(Problem).filter(id__in=problem_id_list).delete()
|
||||
ListenerManagement.delete_embedding_by_source_ids_signal.send(source_ids)
|
||||
return True
|
||||
|
||||
class Operate(serializers.Serializer):
|
||||
dataset_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("知识库id"))
|
||||
|
||||
|
|
@ -105,6 +122,8 @@ class ProblemSerializers(ApiMixin, serializers.Serializer):
|
|||
self.is_valid(raise_exception=True)
|
||||
problem_paragraph_mapping = QuerySet(ProblemParagraphMapping).filter(dataset_id=self.data.get("dataset_id"),
|
||||
problem_id=self.data.get("problem_id"))
|
||||
if problem_paragraph_mapping is None or len(problem_paragraph_mapping)==0:
|
||||
return []
|
||||
return native_search(
|
||||
QuerySet(Paragraph).filter(id__in=[row.paragraph_id for row in problem_paragraph_mapping]),
|
||||
select_string=get_file_content(
|
||||
|
|
@ -123,6 +142,7 @@ class ProblemSerializers(ApiMixin, serializers.Serializer):
|
|||
dataset_id=self.data.get('dataset_id'),
|
||||
problem_id=self.data.get('problem_id'))
|
||||
source_ids = [row.id for row in problem_paragraph_mapping_list]
|
||||
problem_paragraph_mapping_list.delete()
|
||||
QuerySet(Problem).filter(id=self.data.get('problem_id')).delete()
|
||||
ListenerManagement.delete_embedding_by_source_ids_signal.send(source_ids)
|
||||
return True
|
||||
|
|
|
|||
|
|
@ -36,6 +36,25 @@ class ProblemApi(ApiMixin):
|
|||
}
|
||||
)
|
||||
|
||||
class BatchOperate(ApiMixin):
|
||||
@staticmethod
|
||||
def get_request_params_api():
|
||||
return [openapi.Parameter(name='dataset_id',
|
||||
in_=openapi.IN_PATH,
|
||||
type=openapi.TYPE_STRING,
|
||||
required=True,
|
||||
description='知识库id'),
|
||||
]
|
||||
|
||||
@staticmethod
|
||||
def get_request_body_api():
|
||||
return openapi.Schema(
|
||||
title="问题id列表",
|
||||
description="问题id列表",
|
||||
type=openapi.TYPE_ARRAY,
|
||||
items=openapi.Schema(type=openapi.TYPE_STRING)
|
||||
)
|
||||
|
||||
class Operate(ApiMixin):
|
||||
@staticmethod
|
||||
def get_request_params_api():
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ urlpatterns = [
|
|||
'dataset/<str:dataset_id>/document/<str:document_id>/paragraph/<str:paragraph_id>/problem/<str:problem_id>/association',
|
||||
views.Paragraph.Problem.Association.as_view()),
|
||||
path('dataset/<str:dataset_id>/problem', views.Problem.as_view()),
|
||||
path('dataset/<str:dataset_id>/problem/_batch', views.Problem.OperateBatch.as_view()),
|
||||
path('dataset/<str:dataset_id>/problem/<int:current_page>/<int:page_size>', views.Problem.Page.as_view()),
|
||||
path('dataset/<str:dataset_id>/problem/<str:problem_id>', views.Problem.Operate.as_view()),
|
||||
path('dataset/<str:dataset_id>/problem/<str:problem_id>/paragraph', views.Problem.Paragraph.as_view()),
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ class Problem(APIView):
|
|||
def post(self, request: Request, dataset_id: str):
|
||||
return result.success(
|
||||
ProblemSerializers.Create(
|
||||
data={'dataset_id': dataset_id, 'problem_list': request.query_params.get('problem_list')}).save())
|
||||
data={'dataset_id': dataset_id, 'problem_list': request.data}).batch())
|
||||
|
||||
class Paragraph(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
|
@ -70,6 +70,24 @@ class Problem(APIView):
|
|||
data={**query_params_to_single_dict(request.query_params), 'dataset_id': dataset_id,
|
||||
'problem_id': problem_id}).list_paragraph())
|
||||
|
||||
class OperateBatch(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
@action(methods=['DELETE'], detail=False)
|
||||
@swagger_auto_schema(operation_summary="批量删除问题",
|
||||
operation_id="批量删除问题",
|
||||
request_body=
|
||||
ProblemApi.BatchOperate.get_request_body_api(),
|
||||
manual_parameters=ProblemApi.BatchOperate.get_request_params_api(),
|
||||
responses=result.get_default_response(),
|
||||
tags=["知识库/文档/段落/问题"])
|
||||
@has_permissions(
|
||||
lambda r, k: Permission(group=Group.DATASET, operate=Operate.MANAGE,
|
||||
dynamic_tag=k.get('dataset_id')))
|
||||
def delete(self, request: Request, dataset_id: str):
|
||||
return result.success(
|
||||
ProblemSerializers.BatchOperate(data={'dataset_id': dataset_id}).delete(request.data))
|
||||
|
||||
class Operate(APIView):
|
||||
authentication_classes = [TokenAuth]
|
||||
|
||||
|
|
|
|||
|
|
@ -129,25 +129,55 @@ const postProblem: (
|
|||
dataset_id: string,
|
||||
document_id: string,
|
||||
paragraph_id: string,
|
||||
data: any
|
||||
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, data: any) => {
|
||||
data: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, data: any, loading) => {
|
||||
return post(
|
||||
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem`,
|
||||
data
|
||||
data,
|
||||
{},
|
||||
loading
|
||||
)
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param dataset_id 数据集id
|
||||
* @param document_id 文档id
|
||||
* @param paragraph_id 段落id
|
||||
* @param problem_id 问题id
|
||||
* @param loading 加载器
|
||||
* @returns
|
||||
*/
|
||||
const associationProblem: (
|
||||
dataset_id: string,
|
||||
document_id: string,
|
||||
paragraph_id: string,
|
||||
problem_id: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, document_id, paragraph_id, problem_id, loading) => {
|
||||
return put(
|
||||
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/association`,
|
||||
{},
|
||||
{},
|
||||
loading
|
||||
)
|
||||
}
|
||||
/**
|
||||
* 解除关联问题
|
||||
* @param 参数 dataset_id, document_id, paragraph_id,problem_id
|
||||
*/
|
||||
const delProblem: (
|
||||
const disassociationProblem: (
|
||||
dataset_id: string,
|
||||
document_id: string,
|
||||
paragraph_id: string,
|
||||
problem_id: string
|
||||
) => Promise<Result<boolean>> = (dataset_id, document_id, paragraph_id, problem_id) => {
|
||||
problem_id: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<boolean>> = (dataset_id, document_id, paragraph_id, problem_id, loading) => {
|
||||
return put(
|
||||
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/un_association`
|
||||
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${paragraph_id}/problem/${problem_id}/un_association`,
|
||||
{},
|
||||
{},
|
||||
loading
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -158,5 +188,6 @@ export default {
|
|||
postParagraph,
|
||||
getProblem,
|
||||
postProblem,
|
||||
delProblem
|
||||
disassociationProblem,
|
||||
associationProblem
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,107 @@
|
|||
import { Result } from '@/request/Result'
|
||||
import { get, post, del, put } from '@/request/index'
|
||||
import type { Ref } from 'vue'
|
||||
import type { KeyValue } from '@/api/type/common'
|
||||
import type { pageRequest } from '@/api/type/common'
|
||||
const prefix = '/dataset'
|
||||
|
||||
/**
|
||||
* 文档分页列表
|
||||
* @param 参数 dataset_id,
|
||||
* page {
|
||||
"current_page": "string",
|
||||
"page_size": "string",
|
||||
}
|
||||
* query {
|
||||
"content": "string",
|
||||
}
|
||||
*/
|
||||
|
||||
const getProblems: (
|
||||
dataset_id: string,
|
||||
page: pageRequest,
|
||||
param: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, page, param, loading) => {
|
||||
return get(
|
||||
`${prefix}/${dataset_id}/problem/${page.current_page}/${page.page_size}`,
|
||||
param,
|
||||
loading
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建问题
|
||||
* @param 参数 dataset_id
|
||||
* data: array[string]
|
||||
*/
|
||||
const postProblems: (
|
||||
dataset_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, data, loading) => {
|
||||
return post(`${prefix}/${dataset_id}/problem`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除问题
|
||||
* @param 参数 dataset_id, problem_id,
|
||||
*/
|
||||
const delProblems: (
|
||||
dataset_id: string,
|
||||
problem_id: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<boolean>> = (dataset_id, problem_id, loading) => {
|
||||
return del(`${prefix}/${dataset_id}/problem/${problem_id}`, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除问题
|
||||
* @param 参数 dataset_id,
|
||||
*/
|
||||
const delMulProblem: (
|
||||
dataset_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<boolean>> = (dataset_id, data, loading) => {
|
||||
return del(`${prefix}/${dataset_id}/problem/_batch`, undefined, data, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改问题
|
||||
* @param 参数
|
||||
* dataset_id, problem_id,
|
||||
* {
|
||||
"content": "string",
|
||||
}
|
||||
*/
|
||||
const putProblems: (
|
||||
dataset_id: string,
|
||||
problem_id: string,
|
||||
data: any,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, problem_id, data: any, loading) => {
|
||||
return put(`${prefix}/${dataset_id}/problem/${problem_id}`, data, undefined, loading)
|
||||
}
|
||||
|
||||
/**
|
||||
* 问题详情
|
||||
* @param 参数
|
||||
* dataset_id, problem_id,
|
||||
*/
|
||||
const getDetailProblems: (
|
||||
dataset_id: string,
|
||||
problem_id: string,
|
||||
loading?: Ref<boolean>
|
||||
) => Promise<Result<any>> = (dataset_id, problem_id, loading) => {
|
||||
return get(`${prefix}/${dataset_id}/problem/${problem_id}/paragraph`, undefined, loading)
|
||||
}
|
||||
|
||||
export default {
|
||||
getProblems,
|
||||
postProblems,
|
||||
delProblems,
|
||||
putProblems,
|
||||
getDetailProblems,
|
||||
delMulProblem
|
||||
}
|
||||
|
|
@ -102,13 +102,4 @@ defineExpose({ open })
|
|||
height: calc(100vh - 260px);
|
||||
}
|
||||
}
|
||||
.paragraph-source-card {
|
||||
height: 210px;
|
||||
width: 100%;
|
||||
.active-button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@
|
|||
<el-input
|
||||
ref="quickInputRef"
|
||||
v-model="inputValue"
|
||||
placeholder="请输入文档名称"
|
||||
:placeholder="`请输入${quickCreateName}`"
|
||||
class="w-500 mr-12"
|
||||
autofocus
|
||||
:maxlength="quickCreateMaxlength"
|
||||
:show-word-limit="quickCreateMaxlength ? true : false"
|
||||
/>
|
||||
|
||||
<el-button type="primary" @click="submitHandle" :disabled="loading">创建</el-button>
|
||||
|
|
@ -17,7 +19,7 @@
|
|||
<div v-else @click="quickCreateHandel" class="w-full">
|
||||
<el-button type="primary" link class="quich-button">
|
||||
<el-icon><Plus /></el-icon>
|
||||
<span class="ml-4">快速创建空白文档</span>
|
||||
<span class="ml-4">{{ quickCreatePlaceholder }}</span>
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -51,6 +53,18 @@ const props = defineProps({
|
|||
quickCreate: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
quickCreateName: {
|
||||
type: String,
|
||||
default: '文档名称'
|
||||
},
|
||||
quickCreatePlaceholder: {
|
||||
type: String,
|
||||
default: '快速创建空白文档'
|
||||
},
|
||||
quickCreateMaxlength: {
|
||||
type: Number,
|
||||
default: () => 0
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['changePage', 'sizeChange', 'creatQuick'])
|
||||
|
|
@ -81,7 +95,7 @@ function submitHandle() {
|
|||
loading.value = false
|
||||
}, 200)
|
||||
} else {
|
||||
MsgError('文件名称不能为空!')
|
||||
MsgError(`${props.quickCreateName}不能为空!`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -728,5 +728,51 @@ export const iconMap: any = {
|
|||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
'app-problems': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M565.03091564 528.45078523a588.83471385 588.83471385 0 0 1 16.90811971-15.58251253c16.81532721-14.88656875 34.70439623-28.84521246 50.33330501-44.73261462 28.33485369-28.83195638 37.04409293-63.99368709 29.02416942-101.57465094-9.23948212-43.27444672-40.20566608-71.52976398-84.66653122-81.02111147-31.27770165-8.21876458-35.38708395-7.01909007-67.9373685-4.33473551-37.94550581 6.16407344-39.35727747 6.05802485-76.22241344 22.62811474-2.48551348 1.39188755-19.28758462 10.35962019-24.5966414 15.11855-11.44661809 5.60731841-19.40026124 17.25940562-19.40026123 30.86013539a34.46578693 34.46578693 0 0 0 34.46578694 34.46578694 34.1807814 34.1807814 0 0 0 20.83854503-7.17816293c0.35128591-0.22535322 0.69594378-0.41756626 1.06711379-0.74896807 28.77230406-25.79631593 62.90668921-36.7259472 102.56885634-31.38375021 15.43006769 2.07457524 28.54032281 8.45737387 38.05818242 20.42097876 12.23535436 15.3770434 10.79707056 32.51714437 6.85338917 49.71026962-3.05552458 13.30909618-11.26103308 24.31163586-21.66704951 33.43181333-17.02079632 14.932965-34.65799999 29.27603478-52.28194758 43.60584853-19.63224249 15.97356663-28.85846852 36.7259472-31.52293898 60.18919446a257.89025081 257.89025081 0 0 0-1.49793613 30.30338037h0.04639624c-0.03976821 19.12188371 16.21880398 32.68947331 30.90653165 33.12029565 20.02329661 0.59652323 35.11533446-13.47479709 35.32743162-32.39783973-0.00662803-1.0869979-0.19884108-2.07457524-0.28500555-3.12180494-0.00662803-5.1433559-0.0927925-10.29333983 0.01988411-15.43006769 0.29826162-13.49468121 3.10854885-26.22713825 13.66038209-36.34814915zM515.93042532 643.75209862c-19.01583514-0.76222413-32.4309799 15.15169019-33.41192923 31.12525684-1.23281469 20.1691134 15.69518913 34.65799999 30.89327557 35.10870642 20.02329661 0.59652323 35.11533446-13.47479709 35.32743161-32.39783973-0.13918876-19.99015643-13.38863262-33.06064333-32.80877795-33.83612353zM96.72703555 251.52481518h120.80258323c17.31242991 0 31.34398202-14.84017249 31.34398202-33.14017976s-14.03818015-33.14017975-31.34398202-33.14017975H96.72703555c-17.31242991 0-31.34398202 14.84017249-31.34398201 33.14017975s14.03155212 33.14017975 31.34398201 33.14017976zM94.63920422 412.78492985h120.80258324c17.31242991 0 31.34398202-14.84017249 31.34398201-33.14017974s-14.03818015-33.14017975-31.34398201-33.14017976H94.63920422c-17.31242991 0-31.35061005 14.84017249-31.35061003 33.14017976s14.03818015 33.14017975 31.35061003 33.14017974zM246.78576947 542.32989251c0-18.3066353-14.03818015-33.14017975-31.34398201-33.14017975H94.63920422c-17.31242991 0-31.35061005 14.83354446-31.35061003 33.14017975 0 18.30000725 14.03818015 33.14017975 31.35061003 33.14017976h120.80258324c17.30580187 0 31.34398202-14.84017249 31.34398201-33.14017976z',
|
||||
fill: 'currentColor'
|
||||
}),
|
||||
h('path', {
|
||||
d: 'M824.35945025 44.76986174H194.99429654a35.93058289 35.93058289 0 0 0 0 71.84790971h629.36515371c19.80457142 0 35.96372307 16.13263951 35.96372307 35.93058289v718.5652615a35.99023521 35.99023521 0 0 1-35.96372307 35.93721092H230.10963102a35.95709503 35.95709503 0 0 1-35.95709503-35.93721092v-190.42347285a35.93721092 35.93721092 0 0 0-35.96372307-35.92395486 35.92395486 35.92395486 0 0 0-35.95709503 35.92395486v190.42347285c0 59.43359837 48.40454655 107.79837669 107.87791313 107.7983767h594.24981923c59.47999461 0 107.8712851-48.36477833 107.87128509-107.7983767V152.55498237c0-59.42697034-48.39129049-107.78512063-107.87128509-107.78512063z',
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
},
|
||||
'app-quxiaoguanlian': {
|
||||
iconReader: () => {
|
||||
return h('i', [
|
||||
h(
|
||||
'svg',
|
||||
{
|
||||
style: { height: '100%', width: '100%' },
|
||||
viewBox: '0 0 1024 1024',
|
||||
version: '1.1',
|
||||
xmlns: 'http://www.w3.org/2000/svg'
|
||||
},
|
||||
[
|
||||
h('path', {
|
||||
d: 'M544 298.688a32 32 0 0 1 32-32h320c41.216 0 74.688 33.408 74.688 74.624V640c0 41.216-33.472 74.688-74.688 74.688h-85.312a32 32 0 1 1 0-64H896a10.688 10.688 0 0 0 10.688-10.688V341.312A10.688 10.688 0 0 0 896 330.688H576a32 32 0 0 1-32-32zM53.312 341.312c0-41.216 33.472-74.624 74.688-74.624h106.688a32 32 0 1 1 0 64H128a10.688 10.688 0 0 0-10.688 10.624V640c0 5.888 4.8 10.688 10.688 10.688h320a32 32 0 1 1 0 64H128A74.688 74.688 0 0 1 53.312 640V341.312zM282.432 100.416a32 32 0 0 1 43.84 11.392l426.624 725.312a32 32 0 0 1-55.168 32.448L271.104 144.256a32 32 0 0 1 11.328-43.84zM650.688 490.688a32 32 0 0 1 32-32H768a32 32 0 1 1 0 64h-85.312a32 32 0 0 1-32-32zM224 490.688a32 32 0 0 1 32-32h85.312a32 32 0 1 1 0 64H256a32 32 0 0 1-32-32z',
|
||||
fill: 'currentColor'
|
||||
})
|
||||
]
|
||||
)
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,27 @@
|
|||
<template>
|
||||
<div class="cursor">
|
||||
<div class="cursor w-full">
|
||||
<slot name="read">
|
||||
<div class="flex align-center" v-if="!isEdit">
|
||||
<auto-tooltip :content="data">
|
||||
{{ data }}
|
||||
</auto-tooltip>
|
||||
|
||||
<el-button @click.stop="editNameHandle" text v-if="showEditIcon">
|
||||
<el-icon><Edit /></el-icon>
|
||||
<el-button class="ml-4" @click.stop="editNameHandle" text v-if="showEditIcon">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</div>
|
||||
</slot>
|
||||
<slot>
|
||||
<div class="flex align-center" v-if="isEdit">
|
||||
<div @click.stop>
|
||||
<el-input ref="inputRef" v-model="writeValue" placeholder="请输入" autofocus></el-input>
|
||||
<div class="flex align-center" @click.stop v-if="isEdit">
|
||||
<div class="w-full">
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-model="writeValue"
|
||||
placeholder="请输入"
|
||||
autofocus
|
||||
:maxlength="maxlength"
|
||||
:show-word-limit="maxlength ? true : false"
|
||||
></el-input>
|
||||
</div>
|
||||
|
||||
<span class="ml-4">
|
||||
|
|
@ -42,6 +49,10 @@ const props = defineProps({
|
|||
showEditIcon: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
maxlength: {
|
||||
type: Number,
|
||||
default: () => 0
|
||||
}
|
||||
})
|
||||
const emit = defineEmits(['change'])
|
||||
|
|
|
|||
|
|
@ -37,6 +37,18 @@ const datasetRouter = {
|
|||
},
|
||||
component: () => import('@/views/document/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'problem',
|
||||
name: 'Problem',
|
||||
meta: {
|
||||
icon: 'app-problems',
|
||||
title: '问题',
|
||||
active: 'problem',
|
||||
parentPath: '/dataset/:id',
|
||||
parentName: 'DatasetDetail'
|
||||
},
|
||||
component: () => import('@/views/problem/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'hit-test',
|
||||
name: 'DatasetHitTest',
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import useParagraphStore from './modules/paragraph'
|
|||
import useModelStore from './modules/model'
|
||||
import useApplicationStore from './modules/application'
|
||||
import useDocumentStore from './modules/document'
|
||||
import useProblemStore from './modules/problem'
|
||||
|
||||
const useStore = () => ({
|
||||
common: useCommonStore(),
|
||||
|
|
@ -16,7 +17,8 @@ const useStore = () => ({
|
|||
paragraph: useParagraphStore(),
|
||||
model: useModelStore(),
|
||||
application: useApplicationStore(),
|
||||
document: useDocumentStore()
|
||||
document: useDocumentStore(),
|
||||
problem: useProblemStore()
|
||||
})
|
||||
|
||||
export default useStore
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import documentApi from '@/api/document'
|
|||
import { type Ref } from 'vue'
|
||||
|
||||
const useDocumentStore = defineStore({
|
||||
id: 'documents',
|
||||
id: 'document',
|
||||
state: () => ({}),
|
||||
actions: {
|
||||
async asyncGetAllDocument(id: string, loading?: Ref<boolean>) {
|
||||
|
|
@ -17,6 +17,18 @@ const useDocumentStore = defineStore({
|
|||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
async asyncPostDocument(datasetId: string, data: any, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
documentApi
|
||||
.postDocument(datasetId, data, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
import { defineStore } from 'pinia'
|
||||
import { type Ref } from 'vue'
|
||||
import problemApi from '@/api/problem'
|
||||
import paragraphApi from '@/api/paragraph'
|
||||
import type { pageRequest } from '@/api/type/common'
|
||||
|
||||
const useProblemStore = defineStore({
|
||||
id: 'problem',
|
||||
state: () => ({}),
|
||||
actions: {
|
||||
async asyncPostProblem(datasetId: string, data: any, loading?: Ref<boolean>) {
|
||||
return new Promise((resolve, reject) => {
|
||||
problemApi
|
||||
.postProblems(datasetId, data, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
async asyncGetProblem(
|
||||
datasetId: string,
|
||||
page: pageRequest,
|
||||
param: any,
|
||||
loading?: Ref<boolean>
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
problemApi
|
||||
.getProblems(datasetId, page, param, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
async asyncDisassociationProblem(
|
||||
datasetId: string,
|
||||
documentId: string,
|
||||
paragraphId: string,
|
||||
problemId: string,
|
||||
loading?: Ref<boolean>
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
paragraphApi
|
||||
.disassociationProblem(datasetId, documentId, paragraphId, problemId, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
},
|
||||
async asyncAssociationProblem(
|
||||
datasetId: string,
|
||||
documentId: string,
|
||||
paragraphId: string,
|
||||
problemId: string,
|
||||
loading?: Ref<boolean>
|
||||
) {
|
||||
return new Promise((resolve, reject) => {
|
||||
paragraphApi
|
||||
.associationProblem(datasetId, documentId, paragraphId, problemId, loading)
|
||||
.then((data) => {
|
||||
resolve(data)
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default useProblemStore
|
||||
|
|
@ -533,3 +533,36 @@ h4 {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 段落card
|
||||
.paragraph-source-card {
|
||||
height: 210px;
|
||||
width: 100%;
|
||||
.active-button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
// 分段 dialog
|
||||
.paragraph-dialog {
|
||||
padding: 0 !important;
|
||||
.el-scrollbar {
|
||||
height: auto !important;
|
||||
}
|
||||
.el-dialog__header {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
.el-dialog__body {
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
.el-dialog__footer {
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
}
|
||||
|
|
@ -58,18 +58,18 @@ import StepSecond from './step/StepSecond.vue'
|
|||
import ResultSuccess from './step/ResultSuccess.vue'
|
||||
import datasetApi from '@/api/dataset'
|
||||
import type { datasetData } from '@/api/type/dataset'
|
||||
import documentApi from '@/api/document'
|
||||
import { MsgConfirm, MsgSuccess } from '@/utils/message'
|
||||
|
||||
import useStore from '@/stores'
|
||||
const { dataset } = useStore()
|
||||
const { dataset, document } = useStore()
|
||||
const baseInfo = computed(() => dataset.baseInfo)
|
||||
const webInfo = computed(() => dataset.webInfo)
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id, type }
|
||||
params: { type },
|
||||
query: { id } // id为datasetID,有id的是上传文档
|
||||
} = route
|
||||
const isCreate = type === 'create'
|
||||
// const steps = [
|
||||
|
|
@ -112,19 +112,19 @@ function clearStore() {
|
|||
}
|
||||
function submit() {
|
||||
loading.value = true
|
||||
const documents = [] as any[]
|
||||
const data = [] as any
|
||||
StepSecondRef.value?.paragraphList.map((item: any) => {
|
||||
documents.push({
|
||||
data.push({
|
||||
name: item.name,
|
||||
paragraphs: item.content
|
||||
})
|
||||
})
|
||||
const obj = { ...baseInfo.value, documents } as datasetData
|
||||
const id = route.query.id
|
||||
const obj = { ...baseInfo.value, data } as datasetData
|
||||
if (id) {
|
||||
documentApi
|
||||
.postDocument(id as string, documents)
|
||||
.then((res) => {
|
||||
// 上传文档
|
||||
document
|
||||
.asyncPostDocument(id as string, data)
|
||||
.then(() => {
|
||||
MsgSuccess('提交成功')
|
||||
clearStore()
|
||||
router.push({ path: `/dataset/${id}/document` })
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
<p class="mb-8">同步方式</p>
|
||||
<el-radio-group v-model="method" class="card__radio">
|
||||
<el-card shadow="never" class="mb-16" :class="method === 'replace' ? 'active' : ''">
|
||||
<el-radio label="replace" size="large">
|
||||
<el-radio value="replace" size="large">
|
||||
<p class="mb-4">替换同步</p>
|
||||
<el-text type="info">重新获取 Web 站点文档,覆盖替换本地知识库中的文档</el-text>
|
||||
</el-radio>
|
||||
</el-card>
|
||||
|
||||
<el-card shadow="never" class="mb-16" :class="method === 'complete' ? 'active' : ''">
|
||||
<el-radio label="complete" size="large">
|
||||
<el-radio value="complete" size="large">
|
||||
<p class="mb-4">整体同步</p>
|
||||
<el-text type="info">先删除本地知识库所有文档,重新获取 Web 站点文档</el-text>
|
||||
</el-radio>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never" class="mb-16" :class="form.type === '0' ? 'active' : ''">
|
||||
<el-radio label="0" size="large">
|
||||
<el-radio value="0" size="large">
|
||||
<div class="flex align-center">
|
||||
<AppAvatar class="mr-8" shape="square" :size="32">
|
||||
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
|
||||
|
|
@ -31,7 +31,7 @@
|
|||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card shadow="never" class="mb-16" :class="form.type === '1' ? 'active' : ''">
|
||||
<el-radio label="1" size="large">
|
||||
<el-radio value="1" size="large">
|
||||
<div class="flex align-center">
|
||||
<AppAvatar class="mr-8 avatar-purple" shape="square" :size="32">
|
||||
<img src="@/assets/icon_web.svg" style="width: 58%" alt="" />
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@
|
|||
<div class="left-height" @click.stop>
|
||||
<el-radio-group v-model="radio" class="set-rules__radio">
|
||||
<el-card shadow="never" class="mb-16" :class="radio === '1' ? 'active' : ''">
|
||||
<el-radio label="1" size="large">
|
||||
<el-radio value="1" size="large">
|
||||
<p class="mb-4">智能分段(推荐)</p>
|
||||
<el-text type="info">不了解如何设置分段规则推荐使用智能分段</el-text>
|
||||
</el-radio>
|
||||
</el-card>
|
||||
<el-card shadow="never" class="mb-16" :class="radio === '2' ? 'active' : ''">
|
||||
<el-radio label="2" size="large">
|
||||
<el-radio value="2" size="large">
|
||||
<p class="mb-4">高级分段</p>
|
||||
<el-text type="info"
|
||||
>用户可根据文档规范自行设置分段标识符、分段长度以及清洗规则
|
||||
|
|
|
|||
|
|
@ -169,10 +169,10 @@ import useStore from '@/stores'
|
|||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id }
|
||||
params: { id } // id为datasetID
|
||||
} = route as any
|
||||
|
||||
const { dataset } = useStore()
|
||||
const { dataset, document } = useStore()
|
||||
|
||||
const SyncWebDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
|
|
@ -262,9 +262,9 @@ function rowClickHandle(row: any) {
|
|||
function creatQuickHandle(val: string) {
|
||||
loading.value = true
|
||||
const obj = [{ name: val }]
|
||||
documentApi
|
||||
.postDocument(id, obj)
|
||||
.then((res) => {
|
||||
document
|
||||
.asyncPostDocument(id, obj)
|
||||
.then(() => {
|
||||
getList()
|
||||
MsgSuccess('创建成功')
|
||||
})
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6" class="border-l">
|
||||
<el-col :span="6" class="border-l" style="width: 300px;">
|
||||
<!-- 关联问题 -->
|
||||
<ProblemComponent
|
||||
:problemId="problemId"
|
||||
|
|
@ -150,24 +150,5 @@ const handleDebounceClick = debounce(() => {
|
|||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.paragraph-dialog {
|
||||
padding: 0 !important;
|
||||
.el-scrollbar {
|
||||
height: auto !important;
|
||||
}
|
||||
.el-dialog__header {
|
||||
padding: 16px 24px;
|
||||
}
|
||||
.el-dialog__body {
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
.el-dialog__footer {
|
||||
padding: 16px 24px;
|
||||
border-top: 1px solid var(--el-border-color);
|
||||
}
|
||||
|
||||
.title {
|
||||
color: var(--app-text-color);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -11,16 +11,7 @@
|
|||
<div v-loading="loading">
|
||||
<el-scrollbar height="345px">
|
||||
<div class="p-24" style="padding-top: 16px">
|
||||
<el-input
|
||||
ref="inputRef"
|
||||
v-if="isAddProblem"
|
||||
v-model="problemValue"
|
||||
@change="addProblemHandle"
|
||||
placeholder="请输入问题,回车保存"
|
||||
class="mb-8"
|
||||
autofocus
|
||||
/>
|
||||
<!-- <el-select
|
||||
<el-select
|
||||
v-if="isAddProblem"
|
||||
v-model="problemValue"
|
||||
filterable
|
||||
|
|
@ -28,15 +19,19 @@
|
|||
default-first-option
|
||||
:reserve-keyword="false"
|
||||
placeholder="请选择问题"
|
||||
style="width: 240px"
|
||||
remote
|
||||
:remote-method="remoteMethod"
|
||||
:loading="optionLoading"
|
||||
@change="addProblemHandle"
|
||||
class="mb-16"
|
||||
>
|
||||
<el-option
|
||||
v-for="item in problemList"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
v-for="item in problemOptions"
|
||||
:key="item.id"
|
||||
:label="item.content"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select> -->
|
||||
</el-select>
|
||||
<template v-for="(item, index) in problemList" :key="index">
|
||||
<TagEllipsis
|
||||
@close="delProblemHandle(item, index)"
|
||||
|
|
@ -56,6 +51,7 @@
|
|||
import { ref, nextTick, onMounted, onUnmounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import paragraphApi from '@/api/paragraph'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const props = defineProps({
|
||||
problemId: String,
|
||||
|
|
@ -65,9 +61,10 @@ const props = defineProps({
|
|||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id, documentId }
|
||||
params: { id, documentId } // id为datasetId
|
||||
} = route as any
|
||||
|
||||
const { problem } = useStore()
|
||||
const inputRef = ref()
|
||||
const loading = ref(false)
|
||||
const isAddProblem = ref(false)
|
||||
|
|
@ -75,6 +72,9 @@ const isAddProblem = ref(false)
|
|||
const problemValue = ref('')
|
||||
const problemList = ref<any[]>([])
|
||||
|
||||
const problemOptions = ref<any[]>([])
|
||||
const optionLoading = ref(false)
|
||||
|
||||
watch(
|
||||
() => props.problemId,
|
||||
(value) => {
|
||||
|
|
@ -88,19 +88,20 @@ watch(
|
|||
)
|
||||
|
||||
function delProblemHandle(item: any, index: number) {
|
||||
loading.value = true
|
||||
if (item.id) {
|
||||
paragraphApi
|
||||
.delProblem(props.datasetId || id, documentId || props.docId, props.problemId || '', item.id)
|
||||
.then((res) => {
|
||||
problem
|
||||
.asyncDisassociationProblem(
|
||||
props.datasetId || id,
|
||||
documentId || props.docId,
|
||||
props.problemId || '',
|
||||
item.id,
|
||||
loading
|
||||
)
|
||||
.then((res: any) => {
|
||||
getProblemList()
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
problemList.value.splice(index, 1)
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,32 +125,52 @@ function addProblem() {
|
|||
})
|
||||
}
|
||||
function addProblemHandle(val: string) {
|
||||
if (val) {
|
||||
const obj = {
|
||||
content: val
|
||||
}
|
||||
loading.value = true
|
||||
if (props.problemId) {
|
||||
paragraphApi
|
||||
.postProblem(props.datasetId || id, documentId || props.docId, props.problemId, obj)
|
||||
.then((res) => {
|
||||
getProblemList()
|
||||
problemValue.value = ''
|
||||
isAddProblem.value = false
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
} else {
|
||||
problemList.value.unshift(obj)
|
||||
if (props.problemId) {
|
||||
const api = problemOptions.value.some((option) => option.id === val)
|
||||
? problem.asyncAssociationProblem(
|
||||
props.datasetId || id,
|
||||
documentId || props.docId,
|
||||
props.problemId,
|
||||
val,
|
||||
loading
|
||||
)
|
||||
: paragraphApi.postProblem(
|
||||
props.datasetId || id,
|
||||
documentId || props.docId,
|
||||
props.problemId,
|
||||
{
|
||||
content: val
|
||||
},
|
||||
loading
|
||||
)
|
||||
api.then(() => {
|
||||
getProblemList()
|
||||
problemValue.value = ''
|
||||
isAddProblem.value = false
|
||||
loading.value = false
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {})
|
||||
const remoteMethod = (query: string) => {
|
||||
getProblemOption(query)
|
||||
}
|
||||
|
||||
function getProblemOption(filterText?: string) {
|
||||
return problem
|
||||
.asyncGetProblem(
|
||||
id as string,
|
||||
{ current_page: 1, page_size: 100 },
|
||||
filterText && { content: filterText },
|
||||
optionLoading
|
||||
)
|
||||
.then((res: any) => {
|
||||
problemOptions.value = res.data.records
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getProblemOption()
|
||||
})
|
||||
onUnmounted(() => {
|
||||
problemList.value = []
|
||||
problemValue.value = ''
|
||||
|
|
@ -162,6 +183,6 @@ defineExpose({
|
|||
</script>
|
||||
<style scoped lang="scss">
|
||||
.question-tag {
|
||||
width: 217px;
|
||||
// width: 217px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
title="创建问题"
|
||||
v-model="dialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
:destroy-on-close="true"
|
||||
>
|
||||
<el-form
|
||||
label-position="top"
|
||||
ref="problemFormRef"
|
||||
:rules="rules"
|
||||
:model="form"
|
||||
require-asterisk-position="right"
|
||||
>
|
||||
<el-form-item label="问题" prop="data">
|
||||
<el-input
|
||||
v-model="form.data"
|
||||
placeholder="请输入问题,支持输入多个,一行一个。"
|
||||
:rows="10"
|
||||
type="textarea"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click.prevent="dialogVisible = false"> 取消 </el-button>
|
||||
<el-button type="primary" @click="submit(problemFormRef)" :loading="loading">
|
||||
确定
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import type { FormInstance, FormRules } from 'element-plus'
|
||||
import { MsgSuccess } from '@/utils/message'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id }
|
||||
} = route as any
|
||||
const { problem } = useStore()
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
const problemFormRef = ref()
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
const form = ref<any>({
|
||||
data: ''
|
||||
})
|
||||
|
||||
const rules = reactive({
|
||||
data: [{ required: true, message: '请输入问题', trigger: 'blur' }]
|
||||
})
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
form.value = {
|
||||
data: ''
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const open = () => {
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
const submit = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return
|
||||
await formEl.validate((valid, fields) => {
|
||||
if (valid) {
|
||||
const arr = form.value.data.split('\n')
|
||||
problem.asyncPostProblem(id, arr, loading).then((res: any) => {
|
||||
MsgSuccess('创建成功')
|
||||
emit('refresh')
|
||||
dialogVisible.value = false
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
|
|
@ -0,0 +1,197 @@
|
|||
<template>
|
||||
<el-drawer v-model="visible" size="60%" @close="closeHandel">
|
||||
<template #header>
|
||||
<h4>问题详情</h4>
|
||||
</template>
|
||||
<div>
|
||||
<el-scrollbar>
|
||||
<div class="p-8">
|
||||
<el-form label-position="top" v-loading="loading">
|
||||
<el-form-item label="问题">
|
||||
<ReadWrite
|
||||
@change="editName"
|
||||
:data="currentContent"
|
||||
:showEditIcon="true"
|
||||
:maxlength="256"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="关联分段">
|
||||
<template v-for="(item, index) in paragraphList" :key="index">
|
||||
<CardBox
|
||||
shadow="never"
|
||||
:title="item.title || '-'"
|
||||
class="paragraph-source-card cursor mb-8"
|
||||
:showIcon="false"
|
||||
>
|
||||
<div class="active-button">
|
||||
<span class="mr-4">
|
||||
<el-tooltip effect="dark" content="编辑" placement="top">
|
||||
<el-button type="primary" text @click.stop="editParagraph(item)">
|
||||
<el-icon><EditPen /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
<el-tooltip effect="dark" content="取消关联" placement="top">
|
||||
<el-button type="primary" text @click.stop="disassociation(item)">
|
||||
<AppIcon iconName="app-quxiaoguanlian"></AppIcon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
<template #description>
|
||||
<el-scrollbar height="80">
|
||||
{{ item.content }}
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
<template #footer>
|
||||
<div class="footer-content flex-between">
|
||||
<el-text>
|
||||
<el-icon>
|
||||
<Document />
|
||||
</el-icon>
|
||||
{{ item?.document_name }}
|
||||
</el-text>
|
||||
</div>
|
||||
</template>
|
||||
</CardBox>
|
||||
</template>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
<ParagraphDialog ref="ParagraphDialogRef" title="编辑分段" @refresh="refresh" />
|
||||
<RelateProblemDialog ref="RelateProblemDialogRef" @refresh="refresh" />
|
||||
</div>
|
||||
<template #footer>
|
||||
<div>
|
||||
<el-button @click="relateProblem">关联分段</el-button>
|
||||
<el-button @click="pre" :disabled="pre_disable || loading">上一条</el-button>
|
||||
<el-button @click="next" :disabled="next_disable || loading">下一条</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-drawer>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, reactive, computed, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import problemApi from '@/api/problem'
|
||||
import ParagraphDialog from '@/views/paragraph/component/ParagraphDialog.vue'
|
||||
import RelateProblemDialog from './RelateProblemDialog.vue'
|
||||
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
/**
|
||||
* 当前的id
|
||||
*/
|
||||
currentId: string
|
||||
currentContent: string
|
||||
/**
|
||||
* 下一条
|
||||
*/
|
||||
next: () => void
|
||||
/**
|
||||
* 上一条
|
||||
*/
|
||||
pre: () => void
|
||||
|
||||
pre_disable: boolean
|
||||
|
||||
next_disable: boolean
|
||||
}>(),
|
||||
{}
|
||||
)
|
||||
|
||||
const emit = defineEmits(['update:currentId', 'update:currentContent', 'refresh'])
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id }
|
||||
} = route
|
||||
|
||||
const { problem } = useStore()
|
||||
const RelateProblemDialogRef = ref()
|
||||
const ParagraphDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
const visible = ref(false)
|
||||
const paragraphList = ref<any[]>([])
|
||||
|
||||
function disassociation(item: any) {
|
||||
problem
|
||||
.asyncDisassociationProblem(
|
||||
item.dataset_id,
|
||||
item.document_id,
|
||||
item.id,
|
||||
props.currentId,
|
||||
loading
|
||||
)
|
||||
.then(() => {
|
||||
getRecord()
|
||||
})
|
||||
}
|
||||
|
||||
function relateProblem() {
|
||||
RelateProblemDialogRef.value.open(props.currentId)
|
||||
}
|
||||
|
||||
function editParagraph(row: any) {
|
||||
ParagraphDialogRef.value.open(row)
|
||||
}
|
||||
|
||||
function editName(val: string) {
|
||||
if (val) {
|
||||
const obj = {
|
||||
content: val
|
||||
}
|
||||
problemApi.putProblems(id as string, props.currentId, obj, loading).then(() => {
|
||||
emit('update:currentContent', val)
|
||||
MsgSuccess('修改成功')
|
||||
})
|
||||
} else {
|
||||
MsgError('问题不能为空!')
|
||||
}
|
||||
}
|
||||
|
||||
function closeHandel() {
|
||||
paragraphList.value = []
|
||||
}
|
||||
|
||||
function getRecord() {
|
||||
if (props.currentId && visible.value) {
|
||||
problemApi.getDetailProblems(id as string, props.currentId, loading).then((res) => {
|
||||
paragraphList.value = res.data
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
getRecord()
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.currentId,
|
||||
() => {
|
||||
paragraphList.value = []
|
||||
getRecord()
|
||||
}
|
||||
)
|
||||
|
||||
watch(visible, (bool) => {
|
||||
if (!bool) {
|
||||
emit('update:currentId', '')
|
||||
emit('update:currentContent', '')
|
||||
emit('refresh')
|
||||
}
|
||||
})
|
||||
|
||||
const open = () => {
|
||||
getRecord()
|
||||
visible.value = true
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
open
|
||||
})
|
||||
</script>
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,261 @@
|
|||
<template>
|
||||
<el-dialog
|
||||
title="关联分段"
|
||||
v-model="dialogVisible"
|
||||
width="80%"
|
||||
class="paragraph-dialog"
|
||||
destroy-on-close
|
||||
>
|
||||
<el-row v-loading="loading">
|
||||
<el-col :span="6">
|
||||
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
|
||||
<div class="bold title align-center p-24 pb-0">选择文档</div>
|
||||
<div class="p-8" style="padding-bottom: 8px">
|
||||
<common-list
|
||||
:data="documentList"
|
||||
class="mt-8"
|
||||
@click="clickDocumentHandle"
|
||||
:default-active="currentDocument"
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<span class="flex lighter align-center">
|
||||
<auto-tooltip :content="row.name">
|
||||
{{ row.name }}
|
||||
</auto-tooltip>
|
||||
<el-badge
|
||||
:value="associationCount(row.id)"
|
||||
type="primary"
|
||||
v-if="associationCount(row.id)"
|
||||
class="paragraph-badge ml-4"
|
||||
/>
|
||||
</span>
|
||||
</template>
|
||||
</common-list>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-col>
|
||||
<el-col :span="18" class="border-l">
|
||||
<el-scrollbar height="500" wrap-class="paragraph-scrollbar">
|
||||
<div class="p-24" style="padding-bottom: 8px; padding-top: 16px">
|
||||
<div class="flex-between mb-16">
|
||||
<div class="bold title align-center">
|
||||
选择分段
|
||||
<el-text> (已选分段:{{ associationCount(currentDocument) }} 个) </el-text>
|
||||
</div>
|
||||
<el-input
|
||||
v-model="search"
|
||||
placeholder="搜索"
|
||||
class="input-with-select"
|
||||
style="width: 260px"
|
||||
@change="searchHandle"
|
||||
>
|
||||
<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-empty v-if="paragraphList.length == 0" description="暂无数据" />
|
||||
|
||||
<InfiniteScroll
|
||||
v-else
|
||||
:size="paragraphList.length"
|
||||
:total="paginationConfig.total"
|
||||
:page_size="paginationConfig.page_size"
|
||||
v-model:current_page="paginationConfig.current_page"
|
||||
@load="getParagraphList"
|
||||
:loading="loading"
|
||||
>
|
||||
<template v-for="(item, index) in paragraphList" :key="index">
|
||||
<CardBox
|
||||
shadow="hover"
|
||||
:title="item.title || '-'"
|
||||
:description="item.content"
|
||||
class="paragraph-card cursor mb-16"
|
||||
:class="isAssociation(item.id) ? 'active' : ''"
|
||||
:showIcon="false"
|
||||
@click="associationClick(item)"
|
||||
>
|
||||
</CardBox>
|
||||
</template>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
</el-scrollbar>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, watch, reactive } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import problemApi from '@/api/problem'
|
||||
import paragraphApi from '@/api/paragraph'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const { problem, document } = useStore()
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id } // datasetId
|
||||
} = route as any
|
||||
|
||||
const emit = defineEmits(['refresh'])
|
||||
|
||||
const dialogVisible = ref<boolean>(false)
|
||||
|
||||
const loading = ref(false)
|
||||
const documentList = ref<any[]>([])
|
||||
const paragraphList = ref<any[]>([])
|
||||
const currentProblemId = ref<String>('')
|
||||
|
||||
// 回显
|
||||
const associationParagraph = ref<any[]>([])
|
||||
|
||||
const currentDocument = ref<String>('')
|
||||
const search = ref('')
|
||||
const searchType = ref('title')
|
||||
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 50,
|
||||
total: 0
|
||||
})
|
||||
|
||||
function associationClick(item: any) {
|
||||
if (isAssociation(item.id)) {
|
||||
problem
|
||||
.asyncDisassociationProblem(
|
||||
id,
|
||||
item.document_id,
|
||||
item.id,
|
||||
currentProblemId.value as string,
|
||||
loading
|
||||
)
|
||||
.then(() => {
|
||||
getRecord(currentProblemId.value)
|
||||
})
|
||||
} else {
|
||||
problem
|
||||
.asyncAssociationProblem(
|
||||
id,
|
||||
item.document_id,
|
||||
item.id,
|
||||
currentProblemId.value as string,
|
||||
loading
|
||||
)
|
||||
.then(() => {
|
||||
getRecord(currentProblemId.value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function searchHandle() {
|
||||
paginationConfig.current_page = 1
|
||||
paragraphList.value = []
|
||||
getParagraphList(currentDocument.value)
|
||||
}
|
||||
|
||||
function clickDocumentHandle(item: any) {
|
||||
paginationConfig.current_page = 1
|
||||
paragraphList.value = []
|
||||
currentDocument.value = item.id
|
||||
getParagraphList(item.id)
|
||||
}
|
||||
|
||||
function getDocument() {
|
||||
document.asyncGetAllDocument(id, loading).then((res: any) => {
|
||||
documentList.value = res.data
|
||||
currentDocument.value = documentList.value?.length > 0 ? documentList.value[0].id : ''
|
||||
getParagraphList(currentDocument.value)
|
||||
})
|
||||
}
|
||||
|
||||
function getParagraphList(documentId: String) {
|
||||
paragraphApi
|
||||
.getParagraph(
|
||||
id,
|
||||
(documentId || currentDocument.value) as string,
|
||||
paginationConfig,
|
||||
search.value && { [searchType.value]: search.value },
|
||||
loading
|
||||
)
|
||||
.then((res) => {
|
||||
paragraphList.value = [...paragraphList.value, ...res.data.records]
|
||||
paginationConfig.total = res.data.total
|
||||
})
|
||||
}
|
||||
|
||||
// 已关联分段
|
||||
function getRecord(problemId: String) {
|
||||
problemApi.getDetailProblems(id as string, problemId as string, loading).then((res) => {
|
||||
associationParagraph.value = res.data
|
||||
})
|
||||
}
|
||||
|
||||
function associationCount(documentId: String) {
|
||||
return associationParagraph.value.filter((item) => item.document_id === documentId).length
|
||||
}
|
||||
function isAssociation(paragraphId: String) {
|
||||
return associationParagraph.value.some((option) => option.id === paragraphId)
|
||||
}
|
||||
|
||||
watch(dialogVisible, (bool) => {
|
||||
if (!bool) {
|
||||
documentList.value = []
|
||||
paragraphList.value = []
|
||||
associationParagraph.value = []
|
||||
|
||||
currentDocument.value = ''
|
||||
search.value = ''
|
||||
searchType.value = 'title'
|
||||
emit('refresh')
|
||||
}
|
||||
})
|
||||
|
||||
const open = (problemId: string) => {
|
||||
currentProblemId.value = problemId
|
||||
getDocument()
|
||||
getRecord(problemId)
|
||||
dialogVisible.value = true
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
</script>
|
||||
<style lang="scss" scope>
|
||||
.paragraph-card {
|
||||
position: relative;
|
||||
&.active {
|
||||
border: 1px solid var(--el-color-primary);
|
||||
&:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
border: 14px solid var(--el-color-primary);
|
||||
border-bottom-color: transparent;
|
||||
border-left-color: transparent;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
width: 3px;
|
||||
height: 6px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
border: 2px solid #fff;
|
||||
border-top-color: transparent;
|
||||
border-left-color: transparent;
|
||||
transform: rotate(35deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
.paragraph-badge {
|
||||
.el-badge__content {
|
||||
height: auto;
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,340 @@
|
|||
<template>
|
||||
<LayoutContainer header="问题">
|
||||
<div class="main-calc-height">
|
||||
<div class="p-24">
|
||||
<div class="flex-between">
|
||||
<div>
|
||||
<el-button type="primary" @click="createProblem">创建问题</el-button>
|
||||
<el-button @click="deleteMulDocument" :disabled="multipleSelection.length === 0"
|
||||
>批量删除</el-button
|
||||
>
|
||||
</div>
|
||||
|
||||
<el-input
|
||||
v-model="filterText"
|
||||
placeholder="搜索内容"
|
||||
prefix-icon="Search"
|
||||
class="w-240"
|
||||
@change="getList"
|
||||
/>
|
||||
</div>
|
||||
<app-table
|
||||
ref="multipleTableRef"
|
||||
class="mt-16"
|
||||
:data="problemData"
|
||||
:pagination-config="paginationConfig"
|
||||
quick-create
|
||||
quickCreateName="问题"
|
||||
quickCreatePlaceholder="快速创建问题"
|
||||
:quickCreateMaxlength="256"
|
||||
@sizeChange="handleSizeChange"
|
||||
@changePage="getList"
|
||||
@cell-mouse-enter="cellMouseEnter"
|
||||
@cell-mouse-leave="cellMouseLeave"
|
||||
@creatQuick="creatQuickHandle"
|
||||
@row-click="rowClickHandle"
|
||||
@selection-change="handleSelectionChange"
|
||||
:row-class-name="setRowClass"
|
||||
v-loading="loading"
|
||||
:row-key="(row: any) => row.id"
|
||||
>
|
||||
<el-table-column type="selection" width="55" :reserve-selection="true" />
|
||||
<el-table-column prop="content" label="问题" min-width="280">
|
||||
<template #default="{ row }">
|
||||
<ReadWrite
|
||||
@change="editName"
|
||||
:data="row.content"
|
||||
:showEditIcon="row.id === currentMouseId"
|
||||
:maxlength="256"
|
||||
/>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="paragraph_count" label="关联分段数" align="right" min-width="100">
|
||||
<template #default="{ row }">
|
||||
<el-link type="primary" @click.stop="rowClickHandle(row)" v-if="row.paragraph_count">
|
||||
{{ row.paragraph_count }}
|
||||
</el-link>
|
||||
<span v-else>
|
||||
{{ row.paragraph_count }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="create_time" label="创建时间" width="170">
|
||||
<template #default="{ row }">
|
||||
{{ datetimeFormat(row.create_time) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="update_time" label="更新时间" width="170">
|
||||
<template #default="{ row }">
|
||||
{{ datetimeFormat(row.update_time) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="left">
|
||||
<template #default="{ row }">
|
||||
<div>
|
||||
<span class="mr-4">
|
||||
<el-tooltip effect="dark" content="关联分段" placement="top">
|
||||
<el-button type="primary" text @click.stop="relateProblem(row)">
|
||||
<el-icon><Connection /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
<span>
|
||||
<el-tooltip effect="dark" content="删除" placement="top">
|
||||
<el-button type="primary" text @click.stop="deleteProblem(row)">
|
||||
<el-icon><Delete /></el-icon>
|
||||
</el-button>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</app-table>
|
||||
</div>
|
||||
</div>
|
||||
<CreateProblemDialog ref="CreateProblemDialogRef" @refresh="refresh" />
|
||||
<DetailProblemDrawer
|
||||
:next="nextChatRecord"
|
||||
:pre="preChatRecord"
|
||||
ref="DetailProblemRef"
|
||||
v-model:currentId="currentClickId"
|
||||
v-model:currentContent="currentContent"
|
||||
:pre_disable="pre_disable"
|
||||
:next_disable="next_disable"
|
||||
@refresh="refresh"
|
||||
/>
|
||||
<RelateProblemDialog ref="RelateProblemDialogRef" @refresh="refresh" />
|
||||
</LayoutContainer>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, reactive, onBeforeUnmount, computed } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { ElTable } from 'element-plus'
|
||||
import problemApi from '@/api/problem'
|
||||
import CreateProblemDialog from './component/CreateProblemDialog.vue'
|
||||
import DetailProblemDrawer from './component/DetailProblemDrawer.vue'
|
||||
import RelateProblemDialog from './component/RelateProblemDialog.vue'
|
||||
import { datetimeFormat } from '@/utils/time'
|
||||
import { MsgSuccess, MsgConfirm, MsgError } from '@/utils/message'
|
||||
import type { Dict } from '@/api/type/common'
|
||||
import useStore from '@/stores'
|
||||
|
||||
const route = useRoute()
|
||||
const {
|
||||
params: { id }
|
||||
} = route as any
|
||||
|
||||
const { problem } = useStore()
|
||||
|
||||
const RelateProblemDialogRef = ref()
|
||||
const DetailProblemRef = ref()
|
||||
const CreateProblemDialogRef = ref()
|
||||
const loading = ref(false)
|
||||
|
||||
// 当前需要修改问题的id
|
||||
const currentMouseId = ref('')
|
||||
// 当前点击打开drawer的id
|
||||
const currentClickId = ref('')
|
||||
const currentContent = ref('')
|
||||
|
||||
const paginationConfig = reactive({
|
||||
current_page: 1,
|
||||
page_size: 10,
|
||||
total: 0
|
||||
})
|
||||
|
||||
const filterText = ref('')
|
||||
const problemData = ref<any[]>([])
|
||||
const problemIndexMap = computed<Dict<number>>(() => {
|
||||
return problemData.value
|
||||
.map((row, index) => ({
|
||||
[row.id]: index
|
||||
}))
|
||||
.reduce((pre, next) => ({ ...pre, ...next }), {})
|
||||
})
|
||||
|
||||
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
|
||||
const multipleSelection = ref<any[]>([])
|
||||
|
||||
function relateProblem(row: any) {
|
||||
RelateProblemDialogRef.value.open(row.id)
|
||||
}
|
||||
|
||||
function createProblem() {
|
||||
CreateProblemDialogRef.value.open()
|
||||
}
|
||||
|
||||
const handleSelectionChange = (val: any[]) => {
|
||||
multipleSelection.value = val
|
||||
}
|
||||
|
||||
/*
|
||||
快速创建空白文档
|
||||
*/
|
||||
function creatQuickHandle(val: string) {
|
||||
loading.value = true
|
||||
const obj = [val]
|
||||
problem
|
||||
.asyncPostProblem(id, obj)
|
||||
.then((res) => {
|
||||
getList()
|
||||
MsgSuccess('创建成功')
|
||||
})
|
||||
.catch(() => {
|
||||
loading.value = false
|
||||
})
|
||||
}
|
||||
|
||||
function deleteMulDocument() {
|
||||
const arr: string[] = []
|
||||
multipleSelection.value.map((v) => {
|
||||
if (v) {
|
||||
arr.push(v.id)
|
||||
}
|
||||
})
|
||||
problemApi.delMulProblem(id, arr, loading).then(() => {
|
||||
MsgSuccess('批量删除成功')
|
||||
getList()
|
||||
})
|
||||
}
|
||||
|
||||
function deleteProblem(row: any) {
|
||||
MsgConfirm(
|
||||
`是否删除问题:${row.content} ?`,
|
||||
`删除问题关联的 ${row.paragraph_count} 个分段会被取消关联,请谨慎操作。`,
|
||||
{
|
||||
confirmButtonText: '删除',
|
||||
confirmButtonClass: 'danger'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
problemApi.delProblems(id, row.id, loading).then(() => {
|
||||
MsgSuccess('删除成功')
|
||||
getList()
|
||||
})
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
function editName(val: string) {
|
||||
if (val) {
|
||||
const obj = {
|
||||
content: val
|
||||
}
|
||||
problemApi.putProblems(id, currentMouseId.value, obj, loading).then(() => {
|
||||
getList()
|
||||
MsgSuccess('修改成功')
|
||||
})
|
||||
} else {
|
||||
MsgError('问题不能为空!')
|
||||
}
|
||||
}
|
||||
|
||||
function cellMouseEnter(row: any) {
|
||||
currentMouseId.value = row.id
|
||||
}
|
||||
function cellMouseLeave() {
|
||||
currentMouseId.value = ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 下一页
|
||||
*/
|
||||
const nextChatRecord = () => {
|
||||
let index = problemIndexMap.value[currentClickId.value] + 1
|
||||
if (index >= problemData.value.length) {
|
||||
if (
|
||||
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
|
||||
paginationConfig.total - 1
|
||||
) {
|
||||
return
|
||||
}
|
||||
paginationConfig.current_page = paginationConfig.current_page + 1
|
||||
getList().then(() => {
|
||||
index = 0
|
||||
currentClickId.value = problemData.value[index].id
|
||||
currentContent.value = problemData.value[index].content
|
||||
})
|
||||
} else {
|
||||
currentClickId.value = problemData.value[index].id
|
||||
currentContent.value = problemData.value[index].content
|
||||
}
|
||||
}
|
||||
const pre_disable = computed(() => {
|
||||
let index = problemIndexMap.value[currentClickId.value] - 1
|
||||
return index < 0 && paginationConfig.current_page <= 1
|
||||
})
|
||||
|
||||
const next_disable = computed(() => {
|
||||
let index = problemIndexMap.value[currentClickId.value] + 1
|
||||
return (
|
||||
index >= problemData.value.length &&
|
||||
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
|
||||
paginationConfig.total - 1
|
||||
)
|
||||
})
|
||||
/**
|
||||
* 上一页
|
||||
*/
|
||||
const preChatRecord = () => {
|
||||
let index = problemIndexMap.value[currentClickId.value] - 1
|
||||
|
||||
if (index < 0) {
|
||||
if (paginationConfig.current_page <= 1) {
|
||||
return
|
||||
}
|
||||
paginationConfig.current_page = paginationConfig.current_page - 1
|
||||
getList().then((ok) => {
|
||||
index = paginationConfig.page_size - 1
|
||||
currentClickId.value = problemData.value[index].id
|
||||
currentContent.value = problemData.value[index].content
|
||||
})
|
||||
} else {
|
||||
currentClickId.value = problemData.value[index].id
|
||||
currentContent.value = problemData.value[index].content
|
||||
}
|
||||
}
|
||||
|
||||
function rowClickHandle(row: any) {
|
||||
if (row.paragraph_count) {
|
||||
currentClickId.value = row.id
|
||||
currentContent.value = row.content
|
||||
DetailProblemRef.value.open()
|
||||
}
|
||||
}
|
||||
|
||||
const setRowClass = ({ row }: any) => {
|
||||
return currentClickId.value === row?.id ? 'hightlight' : ''
|
||||
}
|
||||
|
||||
function handleSizeChange() {
|
||||
paginationConfig.current_page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
function getList() {
|
||||
return problem
|
||||
.asyncGetProblem(
|
||||
id as string,
|
||||
paginationConfig,
|
||||
filterText.value && { content: filterText.value },
|
||||
loading
|
||||
)
|
||||
.then((res: any) => {
|
||||
problemData.value = res.data.records
|
||||
paginationConfig.total = res.data.total
|
||||
})
|
||||
}
|
||||
|
||||
function refresh() {
|
||||
paginationConfig.current_page = 1
|
||||
getList()
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getList()
|
||||
})
|
||||
|
||||
onBeforeUnmount(() => {})
|
||||
</script>
|
||||
<style lang="scss" scoped></style>
|
||||
Loading…
Reference in New Issue