parent
373d8b771b
commit
1285218eea
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export function page(params: any) {
|
||||||
|
return request.get({
|
||||||
|
url: '/chat/aigc/conversation/page',
|
||||||
|
params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function del(id: string) {
|
||||||
|
return request.delete({
|
||||||
|
url: `/chat/aigc/conversation/${id}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getMessages(conversationId: string) {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/conversation/messages/${conversationId}`,
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
|
||||||
|
|
||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 消息列表接口参数
|
||||||
|
*/
|
||||||
|
export interface MessageParams {
|
||||||
|
text?: string;
|
||||||
|
username?: string;
|
||||||
|
role?: string;
|
||||||
|
pageNum?: number;
|
||||||
|
pageSize?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取消息列表
|
||||||
|
*/
|
||||||
|
export function list(params: MessageParams) {
|
||||||
|
return request.get({
|
||||||
|
url: '/chat/aigc/message/list',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页获取消息列表
|
||||||
|
*/
|
||||||
|
export function page(params: MessageParams) {
|
||||||
|
return request.get({
|
||||||
|
url: '/chat/aigc/message/page',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加消息
|
||||||
|
*/
|
||||||
|
export function add(data: any) {
|
||||||
|
return request.post({
|
||||||
|
url: '/chat/aigc/message',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新消息
|
||||||
|
*/
|
||||||
|
export function update(data: any) {
|
||||||
|
return request.put({
|
||||||
|
url: '/chat/aigc/message',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除消息
|
||||||
|
*/
|
||||||
|
export function del(id: string) {
|
||||||
|
return request.delete({
|
||||||
|
url: `/chat/aigc/message/${id}`
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
|
||||||
|
|
||||||
|
import request from '@/config/axios'
|
||||||
|
|
||||||
|
export function getReqChartBy30() {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/statistic/requestBy30`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getReqChart() {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/statistic/request`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenChartBy30() {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/statistic/tokenBy30`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenChart() {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/statistic/token`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getHomeData() {
|
||||||
|
return request.get({
|
||||||
|
url: `/chat/aigc/statistic/home`,
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,18 +1,4 @@
|
||||||
<!--
|
|
||||||
- Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
|
|
||||||
-
|
|
||||||
- Licensed under the GNU Affero General Public License, Version 3 (the "License");
|
|
||||||
- you may not use this file except in compliance with the License.
|
|
||||||
- You may obtain a copy of the License at
|
|
||||||
-
|
|
||||||
- https://www.gnu.org/licenses/agpl-3.0.html
|
|
||||||
-
|
|
||||||
- Unless required by applicable law or agreed to in writing, software
|
|
||||||
- distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
- See the License for the specific language governing permissions and
|
|
||||||
- limitations under the License.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
|
||||||
|
|
||||||
|
import { TableColumnCtx } from 'element-plus';
|
||||||
|
import { ElTag } from 'element-plus';
|
||||||
|
import { h } from 'vue';
|
||||||
|
import type { FormSchema } from '@/types/form';
|
||||||
|
export const columns: Partial<TableColumnCtx<any>>[] = [
|
||||||
|
{
|
||||||
|
label: '用户名',
|
||||||
|
prop: 'username',
|
||||||
|
align: 'center',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '请求ip',
|
||||||
|
prop: 'ip',
|
||||||
|
align: 'center',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对话角色',
|
||||||
|
prop: 'role',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return h(
|
||||||
|
ElTag,
|
||||||
|
{
|
||||||
|
type: row.role === 'user' ? 'success' : 'danger',
|
||||||
|
size: 'small',
|
||||||
|
},
|
||||||
|
{ default: () => row.role }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '模型名称',
|
||||||
|
prop: 'model',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Token消耗',
|
||||||
|
prop: 'tokens',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '提示词Token消耗',
|
||||||
|
prop: 'promptTokens',
|
||||||
|
align: 'center',
|
||||||
|
width: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '消息内容',
|
||||||
|
prop: 'message',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return String(row.message).replace(/```|\n/g, '');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '会话时间',
|
||||||
|
prop: 'createTime',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const searchSchemas: FormSchema[] = [
|
||||||
|
{
|
||||||
|
field: 'text',
|
||||||
|
component: 'Input',
|
||||||
|
label: '内容',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入内容查询',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'username',
|
||||||
|
component: 'Input',
|
||||||
|
label: '用户名',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户名查询',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'role',
|
||||||
|
component: 'Select',
|
||||||
|
label: '对话角色',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择对话角色查询',
|
||||||
|
style: {
|
||||||
|
width: '140px',
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'user',
|
||||||
|
value: 'user',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'assistant',
|
||||||
|
value: 'assistant',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
|
@ -0,0 +1,165 @@
|
||||||
|
import { ref, computed } from 'vue'
|
||||||
|
import type { FormSchema } from '@/types/form'
|
||||||
|
import type { TableColumn } from '@/types/table'
|
||||||
|
import { useTable } from '@/hooks/web/useTable'
|
||||||
|
import { ElTag, dayjs } from 'element-plus'
|
||||||
|
import { h } from 'vue'
|
||||||
|
import * as MessageApi from '@/api/new-ai/message'
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const searchParams = ref({})
|
||||||
|
|
||||||
|
const schema = ref<FormSchema[]>([
|
||||||
|
{
|
||||||
|
field: 'text',
|
||||||
|
component: 'Input',
|
||||||
|
label: '内容',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入内容查询'
|
||||||
|
},
|
||||||
|
colProps: {
|
||||||
|
span: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'username',
|
||||||
|
component: 'Input',
|
||||||
|
label: '用户名',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户名查询'
|
||||||
|
},
|
||||||
|
colProps: {
|
||||||
|
span: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'role',
|
||||||
|
component: 'Select',
|
||||||
|
label: '对话角色',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请选择对话角色查询',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: 'user',
|
||||||
|
value: 'user'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'assistant',
|
||||||
|
value: 'assistant'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
colProps: {
|
||||||
|
span: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const columns = ref<TableColumn[]>([
|
||||||
|
{
|
||||||
|
label: '用户名',
|
||||||
|
field: 'username',
|
||||||
|
align: 'center',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '请求ip',
|
||||||
|
field: 'ip',
|
||||||
|
align: 'center',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对话角色',
|
||||||
|
field: 'role',
|
||||||
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
|
formatter(row) {
|
||||||
|
return h(
|
||||||
|
ElTag,
|
||||||
|
{
|
||||||
|
type: row.role === 'user' ? 'success' : 'danger',
|
||||||
|
size: 'small'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
default: () => row.role
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '模型名称',
|
||||||
|
field: 'model',
|
||||||
|
align: 'center',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Token消耗',
|
||||||
|
field: 'tokens',
|
||||||
|
align: 'center',
|
||||||
|
width: 100
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '提示词Token消耗',
|
||||||
|
field: 'promptTokens',
|
||||||
|
align: 'center',
|
||||||
|
width: 120
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '消息内容',
|
||||||
|
field: 'message',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return String(row.message).replace(/```|\n/g, '')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '会话时间',
|
||||||
|
field: 'createTime',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
])
|
||||||
|
|
||||||
|
const { register, tableObject, methods } = useTable({
|
||||||
|
getListApi: MessageApi.page,
|
||||||
|
defaultParams: searchParams.value,
|
||||||
|
delListApi: MessageApi.del
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (values: any) => {
|
||||||
|
methods.setSearchParams(values)
|
||||||
|
// methods.getList()
|
||||||
|
}
|
||||||
|
|
||||||
|
const pagination = computed(() => {
|
||||||
|
return {
|
||||||
|
total: tableObject.total,
|
||||||
|
pageSize: tableObject.pageSize,
|
||||||
|
currentPage: tableObject.currentPage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleDel = async (id: string | number) => {
|
||||||
|
try {
|
||||||
|
await methods.delList(id, false)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to delete message:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onMounted(() => {
|
||||||
|
methods.getList()
|
||||||
|
})
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
columns,
|
||||||
|
register,
|
||||||
|
handleSearch,
|
||||||
|
methods,
|
||||||
|
tableObject,
|
||||||
|
pagination,
|
||||||
|
handleDel
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import type { FormSchema } from '@/types/form'
|
||||||
|
|
||||||
|
export const searchSchemas: FormSchema[] = [
|
||||||
|
{
|
||||||
|
field: 'text',
|
||||||
|
component: 'Input',
|
||||||
|
label: '内容',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入内容'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,68 @@
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { nextTick, ref } from 'vue';
|
||||||
|
import { getMessages } from '@/api/new-ai/conversation';
|
||||||
|
import Message from '@/views/ai/chat/new-chat/message/Message.vue';
|
||||||
|
|
||||||
|
const messageRef = ref();
|
||||||
|
const contentRef = ref();
|
||||||
|
const loading = ref(true);
|
||||||
|
const dialogVisible = ref(false);
|
||||||
|
const info = ref<any>({});
|
||||||
|
const messages = ref<any>([]);
|
||||||
|
|
||||||
|
async function show(row: any) {
|
||||||
|
dialogVisible.value = true;
|
||||||
|
await nextTick();
|
||||||
|
|
||||||
|
info.value = row;
|
||||||
|
messages.value = await getMessages(row.id);
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleDelete(row) {
|
||||||
|
console.log('del', row);
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ show });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-drawer
|
||||||
|
v-model="dialogVisible"
|
||||||
|
:title="info.title"
|
||||||
|
size="1000px"
|
||||||
|
direction="rtl"
|
||||||
|
>
|
||||||
|
<template #default>
|
||||||
|
<div ref="contentRef" class="drawer-content">
|
||||||
|
<el-scrollbar ref="messageRef" height="calc(100vh - 180px)">
|
||||||
|
<Message
|
||||||
|
v-for="(item, index) of messages"
|
||||||
|
:key="index"
|
||||||
|
:date-time="item.createTime"
|
||||||
|
:error="false"
|
||||||
|
:inversion="item.role !== 'assistant'"
|
||||||
|
:loading="loading"
|
||||||
|
:text="item.message"
|
||||||
|
@delete="handleDelete(item)"
|
||||||
|
/>
|
||||||
|
</el-scrollbar>
|
||||||
|
</div>
|
||||||
|
<el-empty v-if="messages.length === 0" description="此会话还没有聊天信息" class="mt-5" />
|
||||||
|
</template>
|
||||||
|
<template #footer>
|
||||||
|
<div style="flex: auto">
|
||||||
|
<el-button @click="dialogVisible = false">关闭</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.drawer-content {
|
||||||
|
height: 100%;
|
||||||
|
padding: 0 20px;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,107 @@
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
import type { FormSchema } from '@/types/form'
|
||||||
|
import type { TableColumn } from '@/types/table'
|
||||||
|
import { useTable } from '@/hooks/web/useTable'
|
||||||
|
import { ElTag, dayjs } from 'element-plus'
|
||||||
|
import { h } from 'vue'
|
||||||
|
import * as ConversationApi from '@/api/new-ai/conversation'
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const searchParams = ref({})
|
||||||
|
const infoRef = ref()
|
||||||
|
|
||||||
|
const schema = ref<FormSchema[]>([
|
||||||
|
{
|
||||||
|
field: 'text',
|
||||||
|
component: 'Input',
|
||||||
|
label: '内容',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入内容'
|
||||||
|
},
|
||||||
|
colProps: {
|
||||||
|
span: 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const columns = ref<TableColumn[]>([
|
||||||
|
{
|
||||||
|
label: '用户名',
|
||||||
|
field: 'username',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '窗口标题',
|
||||||
|
field: 'title',
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '对话次数',
|
||||||
|
field: 'chatTotal',
|
||||||
|
align: 'center',
|
||||||
|
width: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Token消耗量',
|
||||||
|
field: 'tokenUsed',
|
||||||
|
align: 'center',
|
||||||
|
width: 180
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '最后一次对话时间',
|
||||||
|
field: 'endTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 180,
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return dayjs(row.endTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '创建时间',
|
||||||
|
field: 'createTime',
|
||||||
|
width: 180,
|
||||||
|
align: 'center',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return dayjs(row.createTime).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
const { register, tableObject, methods } = useTable({
|
||||||
|
getListApi: ConversationApi.page,
|
||||||
|
defaultParams: searchParams.value,
|
||||||
|
delListApi: ConversationApi.del
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (values: any) => {
|
||||||
|
methods.setSearchParams(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pagination = computed(() => {
|
||||||
|
return {
|
||||||
|
total: tableObject.total,
|
||||||
|
pageSize: tableObject.pageSize,
|
||||||
|
currentPage: tableObject.currentPage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleShowInfo = (row: any) => {
|
||||||
|
infoRef.value?.show(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
methods.getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
columns,
|
||||||
|
register,
|
||||||
|
handleSearch,
|
||||||
|
methods,
|
||||||
|
tableObject,
|
||||||
|
pagination,
|
||||||
|
handleShowInfo,
|
||||||
|
infoRef
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Delete, View } from '@element-plus/icons-vue'
|
||||||
|
import { Table } from '@/components/Table'
|
||||||
|
import useConversation from './composables'
|
||||||
|
import InfoList from './components/InfoList.vue'
|
||||||
|
import { searchSchemas } from './columns'
|
||||||
|
|
||||||
|
const {
|
||||||
|
columns,
|
||||||
|
register,
|
||||||
|
handleSearch,
|
||||||
|
methods,
|
||||||
|
tableObject,
|
||||||
|
pagination,
|
||||||
|
handleShowInfo,
|
||||||
|
infoRef
|
||||||
|
} = useConversation()
|
||||||
|
|
||||||
|
const actionColumn = {
|
||||||
|
label: '操作',
|
||||||
|
field: 'action',
|
||||||
|
width: 80,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mt-2">
|
||||||
|
<Search :schema="searchSchemas" inline @search="handleSearch" />
|
||||||
|
|
||||||
|
<Table :columns="[...columns, actionColumn]" :data="tableObject.tableList" :pagination="pagination" @register="register">
|
||||||
|
<template #action="{ row }">
|
||||||
|
<el-button :icon="View" text type="primary" @click="handleShowInfo(row)" />
|
||||||
|
<el-button :icon="Delete" text type="danger" @click="methods.delList(row.id, false)" />
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
|
||||||
|
<InfoList ref="infoRef" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import { Delete } from '@element-plus/icons-vue'
|
||||||
|
import { ElMessageBox, ElMessage } from 'element-plus'
|
||||||
|
import { Table } from '@/components/Table'
|
||||||
|
import useMessage from './composables'
|
||||||
|
import ConversationList from './conversation/index.vue'
|
||||||
|
import { searchSchemas } from './columns'
|
||||||
|
import { format } from 'path'
|
||||||
|
const activeName = ref('1')
|
||||||
|
const {
|
||||||
|
schema,
|
||||||
|
columns,
|
||||||
|
register,
|
||||||
|
handleSearch,
|
||||||
|
methods,
|
||||||
|
tableObject,
|
||||||
|
pagination,
|
||||||
|
handleDel
|
||||||
|
} = useMessage()
|
||||||
|
|
||||||
|
const actionColumn = {
|
||||||
|
label: '操作',
|
||||||
|
field: 'action',
|
||||||
|
width: 70,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<el-card>
|
||||||
|
<el-tabs v-model="activeName">
|
||||||
|
<el-tab-pane label="会话消息列表" name="1">
|
||||||
|
<div class="mt-2">
|
||||||
|
<Search :schema="searchSchemas" @search="handleSearch"/>
|
||||||
|
<Table
|
||||||
|
:columns="[...columns, actionColumn]"
|
||||||
|
:data="tableObject.tableList"
|
||||||
|
:pagination="pagination"
|
||||||
|
@register="register"
|
||||||
|
>
|
||||||
|
<template #action="{row}">
|
||||||
|
<el-button :icon="Delete" text type="danger" @click="methods.delList(row.id, false)" />
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane label="会话窗口列表" name="2">
|
||||||
|
<ConversationList />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-card>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,79 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import { Echart } from '@/components/Echart';
|
||||||
|
import { getReqChartBy30 } from '@/api/new-ai/statictic';
|
||||||
|
|
||||||
|
const options = ref({});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const data = await getReqChartBy30();
|
||||||
|
const xData: any = [];
|
||||||
|
const yData: any = [];
|
||||||
|
data.forEach((i: any) => {
|
||||||
|
xData.push(i.date);
|
||||||
|
yData.push(i.tokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
options.value = {
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
lineStyle: {
|
||||||
|
width: 1,
|
||||||
|
color: '#019680',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
boundaryGap: false,
|
||||||
|
data: xData,
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
width: 1,
|
||||||
|
type: 'solid',
|
||||||
|
color: 'rgba(226,226,226,0.5)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
splitNumber: 4,
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
splitArea: {
|
||||||
|
show: true,
|
||||||
|
areaStyle: {
|
||||||
|
color: ['rgba(255,255,255,0.2)', 'rgba(226,226,226,0.2)'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
grid: { left: '1%', right: '1%', top: '2%', bottom: 0, containLabel: true },
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
smooth: true,
|
||||||
|
data: yData,
|
||||||
|
type: 'line',
|
||||||
|
areaStyle: {},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#5ab1ef',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h3 class="my-2 mb-6 text-lg">近30天请求汇总</h3>
|
||||||
|
<Echart :options="options" height="240px" />
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<!--
|
||||||
|
- Copyright (c) 2024 LangChat. TyCoding All Rights Reserved.
|
||||||
|
-
|
||||||
|
- Licensed under the GNU Affero General Public License, Version 3 (the "License");
|
||||||
|
- you may not use this file except in compliance with the License.
|
||||||
|
- You may obtain a copy of the License at
|
||||||
|
-
|
||||||
|
- https://www.gnu.org/licenses/agpl-3.0.html
|
||||||
|
-
|
||||||
|
- Unless required by applicable law or agreed to in writing, software
|
||||||
|
- distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
- See the License for the specific language governing permissions and
|
||||||
|
- limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { Delete } from '@element-plus/icons-vue'
|
||||||
|
|
||||||
|
import { searchSchemas } from './columns'
|
||||||
|
import useOrder from '../composables'
|
||||||
|
import { columns } from './columns'
|
||||||
|
const { register, handleSearch, methods, tableObject, pagination } = useOrder()
|
||||||
|
|
||||||
|
const actionColumn = {
|
||||||
|
label: '操作',
|
||||||
|
field: 'action',
|
||||||
|
width: 70,
|
||||||
|
fixed: 'right',
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="h-full">
|
||||||
|
<el-card>
|
||||||
|
<Search :schema="searchSchemas" inline @search="handleSearch" />
|
||||||
|
|
||||||
|
<Table
|
||||||
|
:columns="[...columns, actionColumn]"
|
||||||
|
:data="tableObject.tableList"
|
||||||
|
:pagination="pagination"
|
||||||
|
@register="register"
|
||||||
|
>
|
||||||
|
<template #action="{ row }">
|
||||||
|
<el-button :icon="Delete" text type="danger" @click="methods.delList(row.id, false)" />
|
||||||
|
</template>
|
||||||
|
</Table>
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" scoped></style>
|
|
@ -0,0 +1,56 @@
|
||||||
|
import type { FormSchema } from '@/types/form';
|
||||||
|
|
||||||
|
export const columns = [
|
||||||
|
{
|
||||||
|
label: '用户名',
|
||||||
|
field: 'username',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '模型名称',
|
||||||
|
field: 'model',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Tokens',
|
||||||
|
field: 'tokens',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Prompt Tokens',
|
||||||
|
field: 'promptTokens',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Prompt Tokens',
|
||||||
|
field: 'promptTokens',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'IP地址',
|
||||||
|
field: 'ip',
|
||||||
|
align: 'center',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '调用时间',
|
||||||
|
field: 'createTime',
|
||||||
|
align: 'center',
|
||||||
|
width: 180,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export const searchSchemas: FormSchema[] = [
|
||||||
|
{
|
||||||
|
field: 'name',
|
||||||
|
component: 'Input',
|
||||||
|
label: '用户名',
|
||||||
|
componentProps: {
|
||||||
|
placeholder: '请输入用户名查询'
|
||||||
|
},
|
||||||
|
colProps: {
|
||||||
|
span: 6
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
]
|
|
@ -0,0 +1,39 @@
|
||||||
|
import { ref, computed, onMounted } from 'vue'
|
||||||
|
|
||||||
|
import type { TableColumn } from '@/types/table'
|
||||||
|
import { useTable } from '@/hooks/web/useTable'
|
||||||
|
import { dayjs } from 'element-plus'
|
||||||
|
import {page, del} from '@/api/new-ai/message'
|
||||||
|
|
||||||
|
export default function () {
|
||||||
|
const searchParams = ref({})
|
||||||
|
const { register, tableObject, methods } = useTable({
|
||||||
|
getListApi:page,
|
||||||
|
defaultParams: searchParams.value,
|
||||||
|
delListApi:del
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSearch = (values: any) => {
|
||||||
|
methods.setSearchParams(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
const pagination = computed(() => {
|
||||||
|
return {
|
||||||
|
total: tableObject.total,
|
||||||
|
pageSize: tableObject.pageSize,
|
||||||
|
currentPage: tableObject.currentPage
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
methods.getList()
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
register,
|
||||||
|
handleSearch,
|
||||||
|
methods,
|
||||||
|
tableObject,
|
||||||
|
pagination
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Chart from './components/Chart.vue';
|
||||||
|
import List from './components/List.vue';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="overflow-y-auto h-full">
|
||||||
|
<el-card>
|
||||||
|
<Chart />
|
||||||
|
<List />
|
||||||
|
</el-card>
|
||||||
|
</div>
|
||||||
|
</template>
|
|
@ -114,4 +114,4 @@ defineExpose({ show })
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="less" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|
Loading…
Reference in New Issue