From 3b995d34eb46f84776a3507adf20fb5f0aed4d58 Mon Sep 17 00:00:00 2001 From: wxg0103 <727495428@qq.com> Date: Tue, 15 Oct 2024 18:47:07 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AF=B9=E8=AF=9D=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../serializers/chat_serializers.py | 28 ++++-- apps/application/views/chat_views.py | 4 +- ui/src/api/log.ts | 7 +- ui/src/request/index.ts | 39 ++++++++ ui/src/views/log/index.vue | 89 +++++++++++++++---- 5 files changed, 136 insertions(+), 31 deletions(-) diff --git a/apps/application/serializers/chat_serializers.py b/apps/application/serializers/chat_serializers.py index 2b345ecff..c5877b540 100644 --- a/apps/application/serializers/chat_serializers.py +++ b/apps/application/serializers/chat_serializers.py @@ -97,7 +97,8 @@ class ChatSerializers(serializers.Serializer): class Query(serializers.Serializer): abstract = serializers.CharField(required=False, error_messages=ErrMessage.char("摘要")) - history_day = serializers.IntegerField(required=True, error_messages=ErrMessage.integer("历史天数")) + start_time = serializers.DateField(format='%Y-%m-%d', error_messages=ErrMessage.date("开始时间")) + end_time = serializers.DateField(format='%Y-%m-%d', error_messages=ErrMessage.date("结束时间")) user_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("用户id")) application_id = serializers.UUIDField(required=True, error_messages=ErrMessage.uuid("应用id")) min_star = serializers.IntegerField(required=False, min_value=0, @@ -110,23 +111,34 @@ class ChatSerializers(serializers.Serializer): ]) def get_end_time(self): - history_day = self.data.get('history_day') - return datetime.datetime.now() - datetime.timedelta(days=history_day) + return datetime.datetime.combine( + datetime.datetime.strptime(self.data.get('end_time'), '%Y-%m-%d'), + datetime.datetime.max.time()) - def get_query_set(self): + def get_start_time(self): + return self.data.get('start_time') + + def get_query_set(self, select_ids=None): end_time = self.get_end_time() + start_time = self.get_start_time() query_set = QuerySet(model=get_dynamics_model( {'application_chat.application_id': models.CharField(), 'application_chat.abstract': models.CharField(), "star_num": models.IntegerField(), 'trample_num': models.IntegerField(), 'comparer': models.CharField(), - 'application_chat.create_time': models.DateTimeField()})) + 'application_chat.create_time': models.DateTimeField(), + 'application_chat.id': models.UUIDField(), })) base_query_dict = {'application_chat.application_id': self.data.get("application_id"), - 'application_chat.create_time__gte': end_time} + 'application_chat.create_time__gte': start_time, + 'application_chat.create_time__lte': end_time, + } if 'abstract' in self.data and self.data.get('abstract') is not None: base_query_dict['application_chat.abstract__icontains'] = self.data.get('abstract') + + if select_ids is not None and len(select_ids) > 0: + base_query_dict['application_chat.id__in'] = select_ids base_condition = Q(**base_query_dict) min_star_query = None min_trample_query = None @@ -176,11 +188,11 @@ class ChatSerializers(serializers.Serializer): row.get('message_tokens') + row.get('answer_tokens'), row.get('run_time'), str(row.get('create_time'))] - def export(self, with_valid=True): + def export(self, data, with_valid=True): if with_valid: self.is_valid(raise_exception=True) - data_list = native_search(self.get_query_set(), + data_list = native_search(self.get_query_set(data.get('select_ids')), select_string=get_file_content( os.path.join(PROJECT_DIR, "apps", "application", 'sql', 'export_application_chat.sql')), diff --git a/apps/application/views/chat_views.py b/apps/application/views/chat_views.py index c9b10a009..922bbfc3c 100644 --- a/apps/application/views/chat_views.py +++ b/apps/application/views/chat_views.py @@ -54,10 +54,10 @@ class ChatView(APIView): [lambda r, keywords: Permission(group=Group.APPLICATION, operate=Operate.USE, dynamic_tag=keywords.get('application_id'))]) ) - def get(self, request: Request, application_id: str): + def post(self, request: Request, application_id: str): return ChatSerializers.Query( data={**query_params_to_single_dict(request.query_params), 'application_id': application_id, - 'user_id': request.user.id}).export() + 'user_id': request.user.id}).export(request.data) class Open(APIView): authentication_classes = [TokenAuth] diff --git a/ui/src/api/log.ts b/ui/src/api/log.ts index de4716a3f..6dbca4689 100644 --- a/ui/src/api/log.ts +++ b/ui/src/api/log.ts @@ -1,5 +1,5 @@ import { Result } from '@/request/Result' -import { get, del, put, exportExcel } from '@/request/index' +import { get, del, put, exportExcel, exportExcelPost } from '@/request/index' import type { pageRequest } from '@/api/type/common' import { type Ref } from 'vue' @@ -34,9 +34,10 @@ const exportChatLog: ( application_id: string, application_name: string, param: any, + data: any, loading?: Ref -) => void = (application_id, application_name, param, loading) => { - exportExcel(application_name, `${prefix}/${application_id}/chat/export`, param, loading) +) => void = (application_id, application_name, param, data, loading) => { + exportExcelPost(application_name, `${prefix}/${application_id}/chat/export`, param, data, loading) } /** diff --git a/ui/src/request/index.ts b/ui/src/request/index.ts index fdde51396..94760aeb4 100644 --- a/ui/src/request/index.ts +++ b/ui/src/request/index.ts @@ -240,6 +240,45 @@ export const exportExcel: ( .catch((e) => {}) } +export const exportExcelPost: ( + fileName: string, + url: string, + params: any, + data: any, + loading?: NProgress | Ref +) => Promise = ( + fileName: string, + url: string, + params: any, + data: any, + loading?: NProgress | Ref +) => { + return promise( + request({ + url: url, + method: 'post', + params, // 查询字符串参数 + data, // 请求体数据 + responseType: 'blob' + }), + loading + ) + .then((res: any) => { + if (res) { + const blob = new Blob([res], { + type: 'application/vnd.ms-excel' + }) + const link = document.createElement('a') + link.href = window.URL.createObjectURL(blob) + link.download = fileName + link.click() + // 释放内存 + window.URL.revokeObjectURL(link.href) + } + return true + }) + .catch((e) => {}) +} export const download: ( url: string, diff --git a/ui/src/views/log/index.vue b/ui/src/views/log/index.vue index 3eebe3a47..5748be6a3 100644 --- a/ui/src/views/log/index.vue +++ b/ui/src/views/log/index.vue @@ -2,7 +2,7 @@
- + + 导出 @@ -29,8 +40,10 @@ @row-click="rowClickHandle" v-loading="loading" :row-class-name="setRowClass" + @selection-change="handleSelectionChange" class="log-table" > + @@ -45,7 +58,9 @@ link @click="popoverVisible = !popoverVisible" > - + + +
@@ -139,9 +154,11 @@ import { cloneDeep } from 'lodash' import ChatRecordDrawer from './component/ChatRecordDrawer.vue' import { MsgSuccess, MsgConfirm } from '@/utils/message' import logApi from '@/api/log' -import { datetimeFormat } from '@/utils/time' +import { beforeDay, datetimeFormat, nowDate } from '@/utils/time' import useStore from '@/stores' import type { Dict } from '@/api/type/common' +import { t } from '@/locales' + const { application, log } = useStore() const route = useRoute() const { @@ -151,21 +168,33 @@ const { const dayOptions = [ { value: 7, - label: '过去7天' + // @ts-ignore + label: t('views.applicationOverview.monitor.pastDayOptions.past7Days') // 使用 t 方法来国际化显示文本 }, { value: 30, - label: '过去30天' + label: t('views.applicationOverview.monitor.pastDayOptions.past30Days') }, { value: 90, - label: '过去90天' + label: t('views.applicationOverview.monitor.pastDayOptions.past90Days') }, { value: 183, - label: '过去半年' + label: t('views.applicationOverview.monitor.pastDayOptions.past183Days') + }, + { + value: 'other', + label: t('views.applicationOverview.monitor.pastDayOptions.other') } ] +const daterangeValue = ref('') +// 提交日期时间 +const daterange = ref({ + start_time: '', + end_time: '' +}) +const multipleSelection = ref([]) const ChatRecordRef = ref() const loading = ref(false) @@ -182,7 +211,8 @@ const tableIndexMap = computed>(() => { })) .reduce((pre, next) => ({ ...pre, ...next }), {}) }) -const history_day = ref(7) +const history_day = ref(7) + const search = ref('') const detail = ref(null) @@ -279,6 +309,10 @@ const setRowClass = ({ row }: any) => { return currentChatId.value === row?.id ? 'highlight' : '' } +const handleSelectionChange = (val: any[]) => { + multipleSelection.value = val +} + function deleteLog(row: any) { MsgConfirm(`是否删除对话:${row.abstract} ?`, `删除后无法恢复,请谨慎操作。`, { confirmButtonText: '删除', @@ -299,15 +333,11 @@ function handleSizeChange() { getList() } -function changeHandle(val: number) { - history_day.value = val - paginationConfig.current_page = 1 - getList() -} - function getList() { + paginationConfig.current_page = 1 let obj: any = { - history_day: history_day.value, + start_time: daterange.value.start_time, + end_time: daterange.value.end_time, ...filter.value } if (search.value) { @@ -329,23 +359,46 @@ function getDetail() { } const exportLog = () => { + const arr: string[] = [] + multipleSelection.value.map((v) => { + if (v) { + arr.push(v.id) + } + }) if (detail.value) { let obj: any = { - history_day: history_day.value, + start_time: daterange.value.start_time, + end_time: daterange.value.end_time, ...filter.value } if (search.value) { obj = { ...obj, abstract: search.value } } - logApi.exportChatLog(detail.value.id, detail.value.name, obj, loading) + + logApi.exportChatLog(detail.value.id, detail.value.name, obj, { select_ids: arr }, loading) } } + function refresh() { getList() } -onMounted(() => { +function changeDayRangeHandle(val: string) { + daterange.value.start_time = val[0] + daterange.value.end_time = val[1] getList() +} + +function changeDayHandle(val: number | string) { + if (val !== 'other') { + daterange.value.start_time = beforeDay(val) + daterange.value.end_time = nowDate + getList() + } +} + +onMounted(() => { + changeDayHandle(history_day.value) getDetail() })