UnisKB/ui/src/views/log/index.vue

654 lines
19 KiB
Vue
Raw Normal View History

2023-11-15 09:42:31 +00:00
<template>
2025-01-15 11:10:29 +00:00
<LayoutContainer :header="$t('views.log.title')">
2023-12-05 03:36:11 +00:00
<div class="p-24">
<div class="mb-16">
<el-select v-model="history_day" class="mr-12 w-120" @change="changeDayHandle">
2023-12-05 03:36:11 +00:00
<el-option
v-for="item in dayOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
<el-date-picker
v-if="history_day === 'other'"
v-model="daterangeValue"
type="daterange"
:start-placeholder="$t('views.applicationOverview.monitor.startDatePlaceholder')"
:end-placeholder="$t('views.applicationOverview.monitor.endDatePlaceholder')"
format="YYYY-MM-DD"
value-format="YYYY-MM-DD"
@change="changeDayRangeHandle"
/>
2023-12-06 09:30:46 +00:00
<el-input
v-model="search"
@change="getList"
2025-01-13 03:15:51 +00:00
:placeholder="$t('common.search')"
2023-12-06 09:30:46 +00:00
prefix-icon="Search"
class="w-240"
clearable
2023-12-06 09:30:46 +00:00
/>
2024-10-16 08:43:29 +00:00
<div style="display: flex; align-items: center" class="float-right">
2025-01-15 11:10:29 +00:00
<el-button @click="dialogVisible = true">{{
$t('views.log.buttons.clearStrategy')
}}</el-button>
<el-button @click="exportLog">{{ $t('common.export') }}</el-button>
<el-button @click="openDocumentDialog" :disabled="multipleSelection.length === 0"
2025-01-15 11:10:29 +00:00
>{{ $t('views.log.addToDataset') }}
</el-button>
2024-10-16 08:43:29 +00:00
</div>
2023-12-05 03:36:11 +00:00
</div>
<app-table
2023-12-06 09:30:46 +00:00
:data="tableData"
2023-12-05 03:36:11 +00:00
:pagination-config="paginationConfig"
@sizeChange="getList"
2023-12-06 09:30:46 +00:00
@changePage="getList"
@row-click="rowClickHandle"
2023-12-05 06:27:50 +00:00
v-loading="loading"
2023-12-08 04:42:40 +00:00
:row-class-name="setRowClass"
@selection-change="handleSelectionChange"
2023-12-27 07:31:20 +00:00
class="log-table"
2024-12-26 10:35:11 +00:00
ref="multipleTableRef"
2023-12-05 03:36:11 +00:00
>
<el-table-column type="selection" width="55" />
2025-01-15 11:10:29 +00:00
<el-table-column
prop="abstract"
:label="$t('views.log.table.abstract')"
show-overflow-tooltip
/>
<el-table-column
prop="chat_record_count"
:label="$t('views.log.table.chat_record_count')"
align="right"
/>
2024-01-29 06:46:40 +00:00
<el-table-column prop="star_num" align="right">
2024-01-29 09:13:59 +00:00
<template #header>
2024-03-04 06:16:25 +00:00
<div>
2025-01-15 11:10:29 +00:00
<span>{{ $t('views.log.table.feedback.label') }}</span>
2025-01-23 04:10:03 +00:00
<el-popover :width="200" trigger="click" :visible="popoverVisible">
2024-01-29 06:46:40 +00:00
<template #reference>
<el-button
2024-03-04 06:16:25 +00:00
style="margin-top: -2px"
2024-01-29 07:44:33 +00:00
:type="filter.min_star || filter.min_trample ? 'primary' : ''"
2024-01-29 06:46:40 +00:00
link
@click="popoverVisible = !popoverVisible"
>
<el-icon>
<Filter />
</el-icon>
2024-01-29 06:46:40 +00:00
</el-button>
</template>
<div class="filter">
<div class="form-item mb-16">
<div @click.stop>
2025-01-15 11:10:29 +00:00
{{ $t('views.log.table.feedback.star') }} >=
2024-01-29 06:46:40 +00:00
<el-input-number
v-model="filter.min_star"
:min="0"
:step="1"
2024-07-01 09:14:04 +00:00
:value-on-clear="0"
2024-01-29 06:46:40 +00:00
controls-position="right"
2025-01-23 04:10:03 +00:00
style="width: 80px"
2024-01-29 06:46:40 +00:00
size="small"
2024-03-04 06:19:52 +00:00
step-strictly
2024-01-29 06:46:40 +00:00
/>
</div>
</div>
<div class="form-item mb-16">
<div @click.stop>
2025-01-15 11:10:29 +00:00
{{ $t('views.log.table.feedback.trample') }} >=
2024-01-29 06:46:40 +00:00
<el-input-number
v-model="filter.min_trample"
:min="0"
:step="1"
2024-07-01 09:14:04 +00:00
:value-on-clear="0"
2024-01-29 06:46:40 +00:00
controls-position="right"
2025-01-23 04:10:03 +00:00
style="width: 80px"
2024-01-29 06:46:40 +00:00
size="small"
2024-03-04 06:19:52 +00:00
step-strictly
2024-01-29 06:46:40 +00:00
/>
</div>
</div>
</div>
<div class="text-right">
2025-01-15 11:10:29 +00:00
<el-button size="small" @click="filterChange('clear')">{{
$t('common.clear')
}}</el-button>
<el-button type="primary" @click="filterChange" size="small">{{
$t('common.confirm')
}}</el-button>
2024-01-29 06:46:40 +00:00
</div>
</el-popover>
</div>
</template>
2023-12-05 03:36:11 +00:00
<template #default="{ row }">
2024-01-29 06:46:40 +00:00
<span class="mr-8" v-if="!row.trample_num && !row.star_num"> - </span>
<span class="mr-8" v-else>
2023-12-07 03:08:05 +00:00
<span v-if="row.star_num">
<AppIcon iconName="app-like-color"></AppIcon>
{{ row.star_num }}
</span>
2024-02-23 08:48:15 +00:00
<span v-if="row.trample_num" class="ml-8">
2023-12-07 03:08:05 +00:00
<AppIcon iconName="app-oppose-color"></AppIcon>
{{ row.trample_num }}
</span>
</span>
2023-12-05 03:36:11 +00:00
</template>
</el-table-column>
2025-01-15 11:10:29 +00:00
<el-table-column prop="mark_sum" :label="$t('views.log.table.mark')" align="right" />
<el-table-column :label="$t('views.log.table.recenTimes')" width="180">
2023-12-05 03:36:11 +00:00
<template #default="{ row }">
{{ datetimeFormat(row.update_time) }}
2023-12-05 03:36:11 +00:00
</template>
</el-table-column>
2024-03-14 07:37:25 +00:00
<!-- <el-table-column label="操作" width="70" align="left">
2023-12-05 03:36:11 +00:00
<template #default="{ row }">
2025-01-13 03:15:51 +00:00
<el-tooltip effect="dark" :content="$t('common.delete')" placement="top">
2023-12-07 03:08:05 +00:00
<el-button type="primary" text @click.stop="deleteLog(row)">
2023-12-05 03:36:11 +00:00
<el-icon><Delete /></el-icon>
</el-button>
</el-tooltip>
</template>
2024-03-14 07:37:25 +00:00
</el-table-column> -->
2023-12-05 03:36:11 +00:00
</app-table>
</div>
2023-12-08 10:10:47 +00:00
<ChatRecordDrawer
:next="nextChatRecord"
:pre="preChatRecord"
ref="ChatRecordRef"
2024-05-20 09:50:14 +00:00
v-model:chatId="currentChatId"
2024-01-22 02:43:51 +00:00
v-model:currentAbstract="currentAbstract"
2023-12-08 10:10:47 +00:00
:application="detail"
:pre_disable="pre_disable"
:next_disable="next_disable"
2024-01-25 07:08:25 +00:00
@refresh="refresh"
2023-12-08 10:10:47 +00:00
/>
2024-10-16 08:43:29 +00:00
<el-dialog
2025-01-15 11:10:29 +00:00
:title="$t('views.log.buttons.clearStrategy')"
2024-10-16 08:43:29 +00:00
v-model="dialogVisible"
width="25%"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
2025-01-13 03:15:51 +00:00
<span>{{ $t('common.delete') }}</span>
2024-10-16 08:43:29 +00:00
<el-input-number
v-model="days"
controls-position="right"
2024-12-17 08:02:56 +00:00
:min="1"
:max="100000"
:value-on-clear="0"
step-strictly
2024-10-16 08:43:29 +00:00
style="width: 110px; margin-left: 8px; margin-right: 8px"
></el-input-number>
2025-01-21 01:34:32 +00:00
<span>{{ $t('views.log.daysText') }}</span>
2024-10-16 08:43:29 +00:00
<template #footer>
<div class="dialog-footer" style="margin-top: 16px">
2025-01-21 01:34:32 +00:00
<el-button @click="dialogVisible = false">{{ $t('common.cancel') }} </el-button>
2024-10-16 08:43:29 +00:00
<el-button type="primary" @click="saveCleanTime">
2025-01-21 01:34:32 +00:00
{{ $t('common.save') }}
2024-10-16 08:43:29 +00:00
</el-button>
</div>
</template>
</el-dialog>
<el-dialog
2025-01-15 11:10:29 +00:00
:title="$t('views.log.addToDataset')"
v-model="documentDialogVisible"
width="50%"
:close-on-click-modal="false"
:close-on-press-escape="false"
>
<el-form
ref="formRef"
:model="form"
label-position="top"
require-asterisk-position="right"
:rules="rules"
@submit.prevent
>
2025-01-15 11:10:29 +00:00
<el-form-item :label="$t('views.log.selectDataset')" prop="dataset_id">
<el-select
v-model="form.dataset_id"
filterable
2025-01-15 11:10:29 +00:00
:placeholder="$t('views.log.selectDatasetPlaceholder')"
:loading="optionLoading"
@change="changeDataset"
>
<el-option
v-for="item in datasetList"
:key="item.id"
:label="item.name"
:value="item.id"
>
<span class="flex align-center">
<AppAvatar
v-if="!item.dataset_id && item.type === '1'"
class="mr-12 avatar-purple"
shape="square"
:size="24"
>
<img src="@/assets/icon_web.svg" style="width: 58%" alt="" />
</AppAvatar>
<AppAvatar
v-else-if="!item.dataset_id && item.type === '0'"
class="mr-12 avatar-blue"
shape="square"
:size="24"
>
<img src="@/assets/icon_document.svg" style="width: 58%" alt="" />
</AppAvatar>
{{ item.name }}
</span>
</el-option>
</el-select>
</el-form-item>
2025-01-15 11:10:29 +00:00
<el-form-item :label="$t('views.log.saveToDocument')" prop="document_id">
<el-select
v-model="form.document_id"
filterable
2025-01-15 11:10:29 +00:00
:placeholder="$t('views.log.documentPlaceholder')"
:loading="optionLoading"
@change="changeDocument"
>
<el-option
v-for="item in documentList"
:key="item.id"
:label="item.name"
:value="item.id"
>
{{ item.name }}
</el-option>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
2025-01-15 11:10:29 +00:00
<el-button @click.prevent="documentDialogVisible = false">
{{ $t('common.cancel') }}
</el-button>
<el-button type="primary" @click="submitForm(formRef)" :loading="documentLoading">
2025-01-15 11:10:29 +00:00
{{ $t('common.save') }}
</el-button>
</span>
</template>
</el-dialog>
2023-12-05 03:36:11 +00:00
</LayoutContainer>
2023-11-15 09:42:31 +00:00
</template>
<script setup lang="ts">
import { ref, type Ref, onMounted, reactive, computed } from 'vue'
2023-12-07 07:22:07 +00:00
import { useRoute } from 'vue-router'
2024-01-29 06:46:40 +00:00
import { cloneDeep } from 'lodash'
2023-12-07 07:22:07 +00:00
import ChatRecordDrawer from './component/ChatRecordDrawer.vue'
2024-05-20 09:50:14 +00:00
import { MsgSuccess, MsgConfirm } from '@/utils/message'
2023-12-06 09:30:46 +00:00
import logApi from '@/api/log'
import { beforeDay, datetimeFormat, nowDate } from '@/utils/time'
2023-12-07 11:28:38 +00:00
import useStore from '@/stores'
2023-12-08 10:10:47 +00:00
import type { Dict } from '@/api/type/common'
import { t } from '@/locales'
import type { FormInstance, FormRules } from 'element-plus'
2024-12-26 10:35:11 +00:00
import { ElTable } from 'element-plus'
const { application, log, document, user } = useStore()
2023-12-05 03:36:11 +00:00
const route = useRoute()
const {
params: { id }
} = route as any
const emit = defineEmits(['refresh'])
const formRef = ref()
2023-12-05 03:36:11 +00:00
const dayOptions = [
{
value: 7,
// @ts-ignore
label: t('views.applicationOverview.monitor.pastDayOptions.past7Days') // 使用 t 方法来国际化显示文本
2023-12-05 03:36:11 +00:00
},
{
value: 30,
label: t('views.applicationOverview.monitor.pastDayOptions.past30Days')
2023-12-05 03:36:11 +00:00
},
{
value: 90,
label: t('views.applicationOverview.monitor.pastDayOptions.past90Days')
2023-12-05 03:36:11 +00:00
},
{
2023-12-05 08:30:22 +00:00
value: 183,
label: t('views.applicationOverview.monitor.pastDayOptions.past183Days')
},
{
value: 'other',
label: t('views.applicationOverview.monitor.pastDayOptions.other')
2023-12-05 03:36:11 +00:00
}
]
const daterangeValue = ref('')
// 提交日期时间
const daterange = ref({
start_time: '',
end_time: ''
})
2024-12-26 10:35:11 +00:00
const multipleTableRef = ref<InstanceType<typeof ElTable>>()
const multipleSelection = ref<any[]>([])
2023-12-07 07:22:07 +00:00
2023-12-11 02:35:26 +00:00
const ChatRecordRef = ref()
const loading = ref(false)
const documentLoading = ref(false)
2023-12-11 02:35:26 +00:00
const paginationConfig = reactive({
current_page: 1,
page_size: 20,
total: 0
})
2024-10-16 08:43:29 +00:00
const dialogVisible = ref(false)
const documentDialogVisible = ref(false)
2024-10-16 08:43:29 +00:00
const days = ref<number>(180)
2023-12-11 02:35:26 +00:00
const tableData = ref<any[]>([])
const tableIndexMap = computed<Dict<number>>(() => {
return tableData.value
.map((row, index) => ({
[row.id]: index
}))
.reduce((pre, next) => ({ ...pre, ...next }), {})
})
const history_day = ref<number | string>(7)
2023-12-11 02:35:26 +00:00
const search = ref('')
const detail = ref<any>(null)
const currentChatId = ref<string>('')
2024-01-22 02:43:51 +00:00
const currentAbstract = ref<string>('')
2024-01-29 06:46:40 +00:00
const popoverVisible = ref(false)
const defaultFilter = {
min_star: 0,
min_trample: 0,
comparer: 'and'
}
const filter = ref<any>({
min_star: 0,
min_trample: 0,
comparer: 'and'
})
const form = ref<any>({
dataset_id: '',
document_id: ''
})
const rules = reactive<FormRules>({
2025-01-15 11:10:29 +00:00
dataset_id: [
{ required: true, message: t('views.log.selectDatasetPlaceholder'), trigger: 'change' }
],
document_id: [
{
required: true,
message: t('views.log.documentPlaceholder'),
trigger: 'change'
}
]
})
const optionLoading = ref(false)
const documentList = ref<any[]>([])
2024-01-29 06:46:40 +00:00
function filterChange(val: string) {
if (val === 'clear') {
filter.value = cloneDeep(defaultFilter)
}
getList()
popoverVisible.value = false
}
2023-12-11 02:35:26 +00:00
2023-12-08 10:10:47 +00:00
/**
* 下一页
*/
const nextChatRecord = () => {
let index = tableIndexMap.value[currentChatId.value] + 1
if (index >= tableData.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
currentChatId.value = tableData.value[index].id
2024-01-22 02:43:51 +00:00
currentAbstract.value = tableData.value[index].abstract
2023-12-08 10:10:47 +00:00
})
} else {
currentChatId.value = tableData.value[index].id
2024-01-22 02:43:51 +00:00
currentAbstract.value = tableData.value[index].abstract
2023-12-08 10:10:47 +00:00
}
}
const pre_disable = computed(() => {
let index = tableIndexMap.value[currentChatId.value] - 1
return index < 0 && paginationConfig.current_page <= 1
})
const next_disable = computed(() => {
let index = tableIndexMap.value[currentChatId.value] + 1
return (
index >= tableData.value.length &&
index + (paginationConfig.current_page - 1) * paginationConfig.page_size >=
paginationConfig.total - 1
)
})
/**
* 上一页
*/
const preChatRecord = () => {
let index = tableIndexMap.value[currentChatId.value] - 1
if (index < 0) {
if (paginationConfig.current_page <= 1) {
return
}
paginationConfig.current_page = paginationConfig.current_page - 1
2024-05-20 09:50:14 +00:00
getList().then(() => {
2023-12-08 10:10:47 +00:00
index = paginationConfig.page_size - 1
currentChatId.value = tableData.value[index].id
2024-01-22 02:43:51 +00:00
currentAbstract.value = tableData.value[index].abstract
2023-12-08 10:10:47 +00:00
})
} else {
currentChatId.value = tableData.value[index].id
2024-01-22 02:43:51 +00:00
currentAbstract.value = tableData.value[index].abstract
2023-12-08 10:10:47 +00:00
}
}
function rowClickHandle(row: any, column?: any) {
if (column && column.type === 'selection') {
return
}
2023-12-08 04:42:40 +00:00
currentChatId.value = row.id
2024-01-22 02:43:51 +00:00
currentAbstract.value = row.abstract
2023-12-08 10:10:47 +00:00
ChatRecordRef.value.open()
2023-12-06 09:30:46 +00:00
}
2023-12-05 06:27:50 +00:00
2023-12-08 04:42:40 +00:00
const setRowClass = ({ row }: any) => {
2024-04-15 10:46:03 +00:00
return currentChatId.value === row?.id ? 'highlight' : ''
2023-12-08 04:42:40 +00:00
}
const handleSelectionChange = (val: any[]) => {
multipleSelection.value = val
}
2025-01-15 11:10:29 +00:00
// function deleteLog(row: any) {
// MsgConfirm(`是否删除对话:${row.abstract} ?`, `删除后无法恢复,请谨慎操作。`, {
// confirmButtonText: t('common.delete'),
// confirmButtonClass: 'danger'
// })
// .then(() => {
// loading.value = true
// logApi.delChatLog(id as string, row.id, loading).then(() => {
// MsgSuccess(t('common.deleteSuccess'))
// getList()
// })
// })
// .catch(() => {})
// }
2023-12-07 03:08:05 +00:00
2023-12-05 03:36:11 +00:00
function getList() {
2023-12-07 03:08:05 +00:00
let obj: any = {
start_time: daterange.value.start_time,
end_time: daterange.value.end_time,
2024-01-29 06:46:40 +00:00
...filter.value
2023-12-06 09:30:46 +00:00
}
if (search.value) {
2024-01-23 08:49:53 +00:00
obj = { ...obj, abstract: search.value }
2023-12-06 09:30:46 +00:00
}
return log.asyncGetChatLog(id as string, paginationConfig, obj, loading).then((res: any) => {
2023-12-06 09:30:46 +00:00
tableData.value = res.data.records
2023-12-08 04:42:40 +00:00
if (currentChatId.value) {
currentChatId.value = tableData.value[0]?.id
}
2023-12-06 09:30:46 +00:00
paginationConfig.total = res.data.total
2023-12-05 03:36:11 +00:00
})
}
function getDetail(isLoading = false) {
application
.asyncGetApplicationDetail(id as string, isLoading ? loading : undefined)
.then((res: any) => {
detail.value = res.data
days.value = res.data.clean_time
})
2023-12-07 11:28:38 +00:00
}
const exportLog = () => {
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
if (detail.value) {
let obj: any = {
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, { select_ids: arr }, loading)
}
}
2024-01-25 07:08:25 +00:00
function refresh() {
getList()
}
function changeDayRangeHandle(val: string) {
daterange.value.start_time = val[0]
daterange.value.end_time = val[1]
2023-12-05 03:36:11 +00:00
getList()
}
function changeDayHandle(val: number | string) {
if (val !== 'other') {
daterange.value.start_time = beforeDay(val)
daterange.value.end_time = nowDate
getList()
}
}
2024-10-16 08:43:29 +00:00
function saveCleanTime() {
const obj = {
clean_time: days.value
}
2024-10-16 08:43:29 +00:00
application
.asyncPutApplication(id as string, obj, loading)
2024-10-16 08:43:29 +00:00
.then(() => {
2025-01-13 03:15:51 +00:00
MsgSuccess(t('common.saveSuccess'))
2024-10-16 08:43:29 +00:00
dialogVisible.value = false
getDetail(true)
2024-10-16 08:43:29 +00:00
})
.catch(() => {
dialogVisible.value = false
})
}
function changeDataset(dataset_id: string) {
localStorage.setItem(id + 'chat_dataset_id', dataset_id)
form.value.document_id = ''
getDocument(dataset_id)
}
function changeDocument(document_id: string) {
localStorage.setItem(id + 'chat_document_id', document_id)
}
const datasetList = ref<any[]>([])
function getDataset() {
application.asyncGetApplicationDataset(id, documentLoading).then((res: any) => {
datasetList.value = res.data
if (localStorage.getItem(id + 'chat_dataset_id')) {
form.value.dataset_id = localStorage.getItem(id + 'chat_dataset_id') as string
if (!datasetList.value.find((v) => v.id === form.value.dataset_id)) {
form.value.dataset_id = ''
form.value.document_id = ''
} else {
getDocument(form.value.dataset_id)
}
}
})
}
const submitForm = async (formEl: FormInstance | undefined) => {
if (!formEl) return
const arr: string[] = []
multipleSelection.value.map((v) => {
if (v) {
arr.push(v.id)
}
})
await formEl.validate((valid) => {
if (valid) {
const obj = {
document_id: form.value.document_id,
dataset_id: form.value.dataset_id,
chat_ids: arr
}
logApi.postChatRecordLog(id, form.value.dataset_id, obj, documentLoading).then((res: any) => {
2024-12-26 10:35:11 +00:00
multipleTableRef.value?.clearSelection()
documentDialogVisible.value = false
})
}
})
}
function getDocument(dataset_id: string) {
document.asyncGetAllDocument(dataset_id, documentLoading).then((res: any) => {
documentList.value = res.data
if (localStorage.getItem(id + 'chat_document_id')) {
form.value.document_id = localStorage.getItem(id + 'chat_document_id') as string
}
if (!documentList.value.find((v) => v.id === form.value.document_id)) {
form.value.document_id = ''
}
})
}
function openDocumentDialog() {
getDataset()
formRef.value?.clearValidate()
documentDialogVisible.value = true
}
onMounted(() => {
changeDayHandle(history_day.value)
2023-12-07 11:28:38 +00:00
getDetail()
2023-12-05 03:36:11 +00:00
})
2023-11-15 09:42:31 +00:00
</script>
2023-12-27 07:31:20 +00:00
<style lang="scss" scoped>
2024-08-20 03:25:23 +00:00
.log-table {
:deep(tr) {
cursor: pointer;
}
2023-12-27 07:31:20 +00:00
}
</style>