feat: 分页

This commit is contained in:
wangdan-fit2cloud 2023-12-06 17:30:46 +08:00
parent 9ed8aa91bb
commit ee9ee02c22
17 changed files with 200 additions and 105 deletions

View File

@ -221,19 +221,7 @@ const putChatVote: (
) )
} }
/**
*
* @param
* application_id, history_day
}
*/
const getChatLog: (
applicaiton_id: String,
history_day: number,
loading?: Ref<boolean>
) => Promise<Result<any>> = (applicaiton_id, history_day, loading) => {
return get(`${prefix}/${applicaiton_id}/chat`, { history_day }, loading)
}
export default { export default {
getAllAppilcation, getAllAppilcation,
getApplication, getApplication,
@ -250,5 +238,4 @@ export default {
postAppAuthentication, postAppAuthentication,
getProfile, getProfile,
putChatVote, putChatVote,
getChatLog
} }

View File

@ -2,6 +2,7 @@ import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index' import { get, post, del, put } from '@/request/index'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import type { KeyValue } from '@/api/type/common' import type { KeyValue } from '@/api/type/common'
import type { pageRequest } from '@/api/type/common'
const prefix = '/dataset' const prefix = '/dataset'
/** /**
@ -17,22 +18,35 @@ const postSplitDocument: (data: any) => Promise<Result<any>> = (data) => {
* @param loading * @param loading
* @returns * @returns
*/ */
const listSplitPattern: (loading?: Ref<boolean>) => Promise<Result<Array<KeyValue<string, string>>>> = ( const listSplitPattern: (
loading loading?: Ref<boolean>
) => { ) => Promise<Result<Array<KeyValue<string, string>>>> = (loading) => {
return get(`${prefix}/document/split_pattern`, {}, loading) return get(`${prefix}/document/split_pattern`, {}, loading)
} }
/** /**
* *
* @param dataset_id, name * @param dataset_id,
* page {
"current_page": "string",
"page_size": "string",
}
* param {
"name": "string",
}
*/ */
const getDocument: (dataset_id: string, name?: string) => Promise<Result<any>> = ( const getDocument: (
dataset_id, dataset_id: string,
name page: pageRequest,
) => { param: any,
return get(`${prefix}/${dataset_id}/document`, name && { name }) loading?: Ref<boolean>
) => Promise<Result<any>> = (dataset_id, page, param, loading) => {
return get(
`${prefix}/${dataset_id}/document/${page.current_page}/${page.page_size}`,
param,
loading
)
} }
/** /**
@ -100,8 +114,6 @@ const getDocumentDetail: (dataset_id: string, document_id: string) => Promise<Re
return get(`${prefix}/${dataset_id}/document/${document_id}`) return get(`${prefix}/${dataset_id}/document/${document_id}`)
} }
export default { export default {
postSplitDocument, postSplitDocument,
getDocument, getDocument,

35
ui/src/api/log.ts Normal file
View File

@ -0,0 +1,35 @@
import { Result } from '@/request/Result'
import { get, post, postStream, del, put } from '@/request/index'
import type { pageRequest } from '@/api/type/common'
import { type Ref } from 'vue'
const prefix = '/application'
/**
*
* @param
* application_id, history_day
* page {
"current_page": "string",
"page_size": "string",
}
* param {
"history_day": "string",
"search": "string",
}
*/
const getChatLog: (
applicaiton_id: String,
page: pageRequest,
param: any,
loading?: Ref<boolean>
) => Promise<Result<any>> = (applicaiton_id, page, param, loading) => {
return get(
`${prefix}/${applicaiton_id}/chat/${page.current_page}/${page.page_size}`,
param,
loading
)
}
export default {
getChatLog
}

View File

@ -1,16 +1,33 @@
import { Result } from '@/request/Result' import { Result } from '@/request/Result'
import { get, post, del, put } from '@/request/index' import { get, post, del, put } from '@/request/index'
import type { pageRequest } from '@/api/type/common'
import type { Ref } from 'vue'
const prefix = '/dataset' const prefix = '/dataset'
/** /**
* *
* @param dataset_id * @param dataset_id document_id
* page {
"current_page": "string",
"page_size": "string",
}
* param {
"title": "string",
"content": "string",
}
*/ */
const getParagraph: (dataset_id: string, document_id: string) => Promise<Result<any>> = ( const getParagraph: (
dataset_id, dataset_id: string,
document_id document_id: string,
) => { page: pageRequest,
return get(`${prefix}/${dataset_id}/document/${document_id}/paragraph`) param: any,
loading?: Ref<boolean>
) => Promise<Result<any>> = (dataset_id, document_id, page, param, loading) => {
return get(
`${prefix}/${dataset_id}/document/${document_id}/paragraph/${page.current_page}/${page.page_size}`,
param,
loading
)
} }
/** /**
@ -128,5 +145,5 @@ export default {
postParagraph, postParagraph,
getProblem, getProblem,
postProblem, postProblem,
delProblem, delProblem
} }

View File

@ -9,7 +9,6 @@ interface Dict<V> {
interface pageRequest { interface pageRequest {
current_page: number current_page: number
page_size: number page_size: number
name: string
} }
export type { KeyValue, Dict, pageRequest } export type { KeyValue, Dict, pageRequest }

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="ai-dialog"> <div class="ai-chat">
<el-scrollbar ref="scrollDiv"> <el-scrollbar ref="scrollDiv">
<div ref="dialogScrollbar" class="ai-dialog__content p-24"> <div ref="dialogScrollbar" class="ai-chat__content p-24">
<div class="item-content mb-16"> <div class="item-content mb-16">
<div class="avatar"> <div class="avatar">
<AppAvatar class="avatar-gradient"> <AppAvatar class="avatar-gradient">
@ -94,7 +94,7 @@
</template> </template>
</div> </div>
</el-scrollbar> </el-scrollbar>
<div class="ai-dialog__operate p-24"> <div class="ai-chat__operate p-24">
<div class="operate-textarea flex"> <div class="operate-textarea flex">
<el-input <el-input
ref="quickInputRef" ref="quickInputRef"
@ -125,7 +125,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, nextTick, onUpdated, computed } from 'vue' import { ref, nextTick, onUpdated, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import OperationButton from './OperationButton.vue' import OperationButton from './OperationButton.vue'
import applicationApi from '@/api/application' import applicationApi from '@/api/application'
import { ChatManagement, type chatType } from '@/api/type/application' import { ChatManagement, type chatType } from '@/api/type/application'
@ -288,7 +288,7 @@ onUpdated(() => {
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ai-dialog { .ai-chat {
--padding-left: 40px; --padding-left: 40px;
height: 100%; height: 100%;
display: flex; display: flex;

View File

@ -26,8 +26,8 @@
<div class="app-table__pagination mt-16" v-if="$slots.pagination || paginationConfig"> <div class="app-table__pagination mt-16" v-if="$slots.pagination || paginationConfig">
<slot name="pagination"> <slot name="pagination">
<el-pagination <el-pagination
v-model:current-page="paginationConfig.currentPage" v-model:current-page="paginationConfig.current_page"
v-model:page-size="paginationConfig.pageSize" v-model:page-size="paginationConfig.page_size"
:page-sizes="pageSizes" :page-sizes="pageSizes"
:total="paginationConfig.total" :total="paginationConfig.total"
layout="total, prev, pager, next, sizes" layout="total, prev, pager, next, sizes"

View File

@ -50,16 +50,16 @@ const applicationRouter = {
component: () => import('@/views/application/CreateAndSetting.vue') component: () => import('@/views/application/CreateAndSetting.vue')
}, },
{ {
path: 'dialog', path: 'log',
name: 'DialogLog', name: 'Log',
meta: { meta: {
icon: 'Setting', icon: 'Setting',
title: '对话日志', title: '对话日志',
active: 'dialog', active: 'log',
parentPath: '/application/:id', parentPath: '/application/:id',
parentName: 'ApplicationDetail' parentName: 'ApplicationDetail'
}, },
component: () => import('@/views/application/DialogLog.vue') component: () => import('@/views/log/index.vue')
} }
] ]
}, },

View File

@ -41,6 +41,6 @@
/** dataset */ /** dataset */
--create-dataset-height: calc(var(--app-main-height) - 70px); --create-dataset-height: calc(var(--app-main-height) - 70px);
/** ai-dialog */ /** ai-chat */
--dialog-bg-gradient-color: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1; --dialog-bg-gradient-color: linear-gradient(188deg, rgba(235, 241, 255, 0.20) 39.6%, rgba(231, 249, 255, 0.20) 94.3%), #EFF0F1;
} }

View File

@ -157,7 +157,7 @@
<div class="dialog-bg"> <div class="dialog-bg">
<h4 class="p-24">{{ applicationForm?.name || '应用名称' }}</h4> <h4 class="p-24">{{ applicationForm?.name || '应用名称' }}</h4>
<div class="scrollbar-height"> <div class="scrollbar-height">
<AiDialog :data="applicationForm"></AiDialog> <AiChat :data="applicationForm"></AiChat>
</div> </div>
</div> </div>
</el-col> </el-col>
@ -181,7 +181,7 @@
import { reactive, ref, watch, onMounted } from 'vue' import { reactive, ref, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import { groupBy } from 'lodash' import { groupBy } from 'lodash'
import AiDialog from '@/components/ai-dialog/index.vue' import AiChat from '@/components/ai-chat/index.vue'
import AddDatasetDialog from './components/AddDatasetDialog.vue' import AddDatasetDialog from './components/AddDatasetDialog.vue'
import CreateModelDialog from '@/views/template/component/CreateModelDialog.vue' import CreateModelDialog from '@/views/template/component/CreateModelDialog.vue'
import SelectProviderDialog from '@/views/template/component/SelectProviderDialog.vue' import SelectProviderDialog from '@/views/template/component/SelectProviderDialog.vue'

View File

@ -6,7 +6,7 @@
</div> </div>
</div> </div>
<div class="chat__main chat-width"> <div class="chat__main chat-width">
<AiDialog v-model:data="applicationDetail" :appId="applicationDetail?.id"></AiDialog> <AiChat v-model:data="applicationDetail" :appId="applicationDetail?.id"></AiChat>
</div> </div>
<div class="chat__footer"></div> <div class="chat__footer"></div>
</div> </div>
@ -14,7 +14,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, watch, onMounted } from 'vue' import { reactive, ref, watch, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import AiDialog from '@/components/ai-dialog/index.vue' import AiChat from '@/components/ai-chat/index.vue'
import applicationApi from '@/api/application' import applicationApi from '@/api/application'
import useStore from '@/stores' import useStore from '@/stores'
const route = useRoute() const route = useRoute()

View File

@ -21,7 +21,7 @@
class="card-never mb-16" class="card-never mb-16"
> >
<div class="flex-between"> <div class="flex-between">
<span>{{ child.title }}</span> <span>{{ child.title || '-' }}</span>
<div> <div>
<!-- 编辑分段按钮 --> <!-- 编辑分段按钮 -->
<el-button link @click="editHandle(child, index, cIndex)"> <el-button link @click="editHandle(child, index, cIndex)">
@ -88,7 +88,7 @@ function editHandle(item: any, index: number, cIndex: number) {
} }
function deleteHandle(item: any, index: number, cIndex: number) { function deleteHandle(item: any, index: number, cIndex: number) {
MsgConfirm(`是否删除分段:${item.title} ?`, `删除后将不会存入数据集,对本地文档无影响。`, { MsgConfirm(`是否删除分段:${item.title || '-'} ?`, `删除后将不会存入数据集,对本地文档无影响。`, {
confirmButtonText: '删除', confirmButtonText: '删除',
confirmButtonClass: 'danger' confirmButtonClass: 'danger'
}) })

View File

@ -18,10 +18,11 @@
</div> </div>
<app-table <app-table
class="mt-16" class="mt-16"
:data="dataList" :data="documentData"
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
quick-create quick-create
@sizeChange="handleSizeChange" @sizeChange="handleSizeChange"
@changePage="getList"
@cell-mouse-enter="cellMouseEnter" @cell-mouse-enter="cellMouseEnter"
@cell-mouse-leave="cellMouseLeave" @cell-mouse-leave="cellMouseLeave"
@creatQuick="creatQuickHandle" @creatQuick="creatQuickHandle"
@ -119,18 +120,11 @@ const documentData = ref<any[]>([])
const currentMouseId = ref(null) const currentMouseId = ref(null)
const paginationConfig = reactive({ const paginationConfig = reactive({
currentPage: 1, current_page: 1,
pageSize: 10, page_size: 10,
total: 0 total: 0
}) })
const dataList = computed(() =>
documentData.value.slice(
(paginationConfig.currentPage - 1) * paginationConfig.pageSize,
paginationConfig.currentPage * paginationConfig.pageSize
)
)
function rowClickHandle(row: any) { function rowClickHandle(row: any) {
router.push({ path: `/dataset/${id}/${row.id}` }) router.push({ path: `/dataset/${id}/${row.id}` })
} }
@ -217,20 +211,21 @@ function cellMouseLeave() {
} }
function handleSizeChange() { function handleSizeChange() {
paginationConfig.currentPage = 1 paginationConfig.current_page = 1
getList()
} }
function getList() { function getList() {
loading.value = true
documentApi documentApi
.getDocument(id as string, filterText.value) .getDocument(
id as string,
paginationConfig,
filterText.value && { name: filterText.value },
loading
)
.then((res) => { .then((res) => {
documentData.value = res.data documentData.value = res.data.records
paginationConfig.total = res.data.length paginationConfig.total = res.data.total
loading.value = false
})
.catch(() => {
loading.value = false
}) })
} }

View File

@ -10,16 +10,24 @@
:value="item.value" :value="item.value"
/> />
</el-select> </el-select>
<el-input v-model="search" placeholder="搜索" prefix-icon="Search" style="width: 240px" /> <el-input
v-model="search"
@change="getList"
placeholder="搜索"
prefix-icon="Search"
class="w-240"
/>
</div> </div>
<app-table <app-table
:data="dataList" :data="tableData"
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
@sizeChange="handleSizeChange" @sizeChange="handleSizeChange"
@changePage="getList"
@row-click="rowClickHandle"
v-loading="loading" v-loading="loading"
> >
<el-table-column prop="abstract" label="摘要" /> <el-table-column prop="abstract" label="摘要" show-overflow-tooltip />
<el-table-column prop="chat_record_count" label="对话提问数" align="right" /> <el-table-column prop="chat_record_count" label="对话提问数" align="right" />
<el-table-column prop="star_num" label="用户反馈" align="right"> <el-table-column prop="star_num" label="用户反馈" align="right">
<template #default="{ row }"> <template #default="{ row }">
@ -54,7 +62,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, reactive, computed } from 'vue' import { ref, onMounted, reactive, computed } from 'vue'
import { useRouter, useRoute } from 'vue-router' import { useRouter, useRoute } from 'vue-router'
import applicationApi from '@/api/application' import logApi from '@/api/log'
import { datetimeFormat } from '@/utils/time' import { datetimeFormat } from '@/utils/time'
const route = useRoute() const route = useRoute()
const { const {
@ -81,34 +89,40 @@ const dayOptions = [
] ]
const loading = ref(false) const loading = ref(false)
const paginationConfig = reactive({ const paginationConfig = reactive({
currentPage: 1, current_page: 1,
pageSize: 10, page_size: 20,
total: 0 total: 0
}) })
const tableData = ref([]) const tableData = ref([])
const history_day = ref(7) const history_day = ref(7)
const search = ref('') const search = ref('')
const dataList = computed(() => function rowClickHandle(row: any) {
tableData.value.slice( // router.push({ path: `/dataset/${id}/${row.id}` })
(paginationConfig.currentPage - 1) * paginationConfig.pageSize, }
paginationConfig.currentPage * paginationConfig.pageSize
)
)
function handleSizeChange() { function handleSizeChange() {
paginationConfig.currentPage = 1 paginationConfig.current_page = 1
getList()
} }
function changeHandle(val: number) { function changeHandle(val: number) {
history_day.value = val history_day.value = val
paginationConfig.current_page = 1
getList() getList()
} }
function getList() { function getList() {
applicationApi.getChatLog(id as string, history_day.value, loading).then((res) => { let obj = {
tableData.value = res.data history_day: history_day.value
paginationConfig.total = res.data.length }
if (search.value) {
obj = { ...object, search: search.value }
}
logApi.getChatLog(id as string, paginationConfig, obj, loading).then((res) => {
tableData.value = res.data.records
paginationConfig.total = res.data.total
}) })
} }

View File

@ -9,7 +9,7 @@
> >
<el-form-item label="分段标题"> <el-form-item label="分段标题">
<el-input v-if="isEdit" v-model="form.title" placeholder="请输入分段标题"> </el-input> <el-input v-if="isEdit" v-model="form.title" placeholder="请输入分段标题"> </el-input>
<span v-else>{{ form.title }}</span> <span v-else>{{ form.title || '-' }}</span>
</el-form-item> </el-form-item>
<el-form-item label="分段内容" prop="content"> <el-form-item label="分段内容" prop="content">
<el-input <el-input

View File

@ -5,14 +5,15 @@
<el-button @click="addParagraph" type="primary" :disabled="loading"> 添加分段 </el-button> <el-button @click="addParagraph" type="primary" :disabled="loading"> 添加分段 </el-button>
</div> </div>
</template> </template>
<div class="document-detail__main p-16" v-loading="loading"> <div class="document-detail__main p-16">
<div class="flex-between p-8"> <div class="flex-between p-8">
<span>{{ paragraphDetail.length }} 段落</span> <span>{{ pageConfig.total }} 段落</span>
<el-input <el-input
v-model="search" v-model="search"
placeholder="搜索" placeholder="搜索"
class="input-with-select" class="input-with-select"
style="width: 260px" style="width: 260px"
@change="searchHandle"
> >
<template #prepend> <template #prepend>
<el-select v-model="searchType" placeholder="Select" style="width: 80px"> <el-select v-model="searchType" placeholder="Select" style="width: 80px">
@ -23,8 +24,9 @@
</el-input> </el-input>
</div> </div>
<el-scrollbar> <el-scrollbar>
<div class="document-detail-height"> <div class="document-detail-height" v-loading="pageConfig.current_page === 1 && loading">
<el-row> <el-empty v-if="paragraphDetail.length == 0" description="暂无数据" />
<el-row v-else v-infinite-scroll="loadDataset" :infinite-scroll-disabled="disabledLoad">
<el-col <el-col
:xs="24" :xs="24"
:sm="12" :sm="12"
@ -37,7 +39,7 @@
> >
<CardBox <CardBox
shadow="hover" shadow="hover"
:title="item.title" :title="item.title || '-'"
:description="item.content" :description="item.content"
class="document-card cursor" class="document-card cursor"
:class="item.is_active ? '' : 'disabled'" :class="item.is_active ? '' : 'disabled'"
@ -65,6 +67,14 @@
</CardBox> </CardBox>
</el-col> </el-col>
</el-row> </el-row>
<div style="padding: 16px 10px">
<el-divider v-if="paragraphDetail.length > 0 && loading">
<el-text type="info"> 加载中...</el-text>
</el-divider>
<el-divider v-if="noMore">
<el-text type="info"> 到底啦</el-text>
</el-divider>
</div>
</div> </div>
</el-scrollbar> </el-scrollbar>
</div> </div>
@ -72,7 +82,7 @@
</LayoutContainer> </LayoutContainer>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from 'vue' import { reactive, ref, onMounted, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import documentApi from '@/api/document' import documentApi from '@/api/document'
import paragraphApi from '@/api/paragraph' import paragraphApi from '@/api/paragraph'
@ -94,6 +104,30 @@ const title = ref('')
const search = ref('') const search = ref('')
const searchType = ref('title') const searchType = ref('title')
const pageConfig = reactive({
current_page: 1,
page_size: 20,
total: 0
})
const noMore = computed(
() => paragraphDetail.value.length > 0 && paragraphDetail.value.length === pageConfig.total
)
const disabledLoad = computed(
() => paragraphDetail.value.length > 0 && (loading.value || noMore.value)
)
function loadDataset() {
pageConfig.current_page += 1
getParagraphList()
}
function searchHandle() {
pageConfig.current_page = 1
paragraphDetail.value = []
getParagraphList()
}
function changeState(bool: Boolean, row: any) { function changeState(bool: Boolean, row: any) {
const obj = { const obj = {
is_active: bool is_active: bool
@ -110,7 +144,7 @@ function changeState(bool: Boolean, row: any) {
} }
function deleteParagraph(row: any) { function deleteParagraph(row: any) {
MsgConfirm(`是否删除段落:${row.title} ?`, `删除后无法恢复,请谨慎操作。`, { MsgConfirm(`是否删除段落:${row.title || '-'} ?`, `删除后无法恢复,请谨慎操作。`, {
confirmButtonText: '删除', confirmButtonText: '删除',
confirmButtonClass: 'danger' confirmButtonClass: 'danger'
}) })
@ -120,7 +154,7 @@ function deleteParagraph(row: any) {
.delParagraph(id, documentId, row.id) .delParagraph(id, documentId, row.id)
.then(() => { .then(() => {
MsgSuccess('删除成功') MsgSuccess('删除成功')
getParagraphDetail() getParagraphList()
}) })
.catch(() => { .catch(() => {
loading.value = false loading.value = false
@ -151,26 +185,28 @@ function getDetail() {
}) })
} }
function getParagraphDetail() { function getParagraphList() {
loading.value = true
paragraphApi paragraphApi
.getParagraph(id, documentId) .getParagraph(
id,
documentId,
pageConfig,
search.value && { [searchType.value]: search.value },
loading
)
.then((res) => { .then((res) => {
paragraphDetail.value = res.data paragraphDetail.value = [...paragraphDetail.value, ...res.data.records]
loading.value = false pageConfig.total = res.data.total
})
.catch(() => {
loading.value = false
}) })
} }
function refresh() { function refresh() {
getParagraphDetail() getParagraphList()
} }
onMounted(() => { onMounted(() => {
getDetail() getDetail()
getParagraphDetail() getParagraphList()
}) })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>