feat: add conversation shortcuts to statistics

This commit is contained in:
Soulter
2026-08-27 19:04:16 +08:00
parent 69030851d4
commit cec1cd53ab
8 changed files with 96 additions and 17 deletions
@@ -5,7 +5,7 @@
"providers": "Providers",
"commands": "Commands",
"persona": "Persona",
"data": "Data",
"data": "Data & Logs",
"dataTabs": {
"statistics": "Statistics",
"conversations": "Conversations",
@@ -69,7 +69,8 @@
"title": "Model Usage Ranking"
},
"sessionRanking": {
"title": "{range} Session Model Usage Top 10"
"title": "{range} Session Model Usage Top 10",
"openConversation": "View conversation"
},
"empty": {
"platformStats": "No platform message statistics available.",
@@ -5,7 +5,7 @@
"providers": "Провайдеры моделей",
"commands": "Команды",
"persona": "Персонажи",
"data": "Данные",
"data": "Данные и логи",
"dataTabs": {
"statistics": "Статистика",
"conversations": "Данные диалогов",
@@ -69,7 +69,8 @@
"title": "Рейтинг использования моделей"
},
"sessionRanking": {
"title": "{range} топ-10 сессий по использованию моделей"
"title": "{range} топ-10 сессий по использованию моделей",
"openConversation": "Открыть диалог"
},
"empty": {
"platformStats": "Статистика сообщений по платформам отсутствует.",
@@ -5,7 +5,7 @@
"providers": "模型提供商",
"commands": "指令管理",
"persona": "人格设定",
"data": "数据",
"data": "数据与日志",
"dataTabs": {
"statistics": "统计",
"conversations": "对话",
@@ -69,7 +69,8 @@
"title": "模型用量排名"
},
"sessionRanking": {
"title": "{range}会话模型用量 Top 10"
"title": "{range}会话模型用量 Top 10",
"openConversation": "查看对话"
},
"empty": {
"platformStats": "当前没有平台消息统计数据。",
@@ -7,7 +7,7 @@ import {
ref,
watch,
} from "vue";
import { RouterLink } from "vue-router";
import { RouterLink, useRoute, useRouter } from "vue-router";
import { VueMonacoEditor } from "@guolao/vue-monaco-editor";
import {
Bot,
@@ -81,15 +81,23 @@ type ConversationListEntry =
const { locale } = useI18n();
const { tm } = useModuleI18n("features/conversation");
const route = useRoute();
const router = useRouter();
const customizerStore = useCustomizerStore();
const confirmDialog = useConfirmDialog();
const initialUmoQuery = Array.isArray(route.query.umo)
? route.query.umo[0]
: route.query.umo;
const conversations = ref<Conversation[]>([]);
const availableBots = ref<BotOption[]>([]);
const keyword = ref("");
const selectedBotIds = ref<string[]>([]);
const selectedTypes = ref<string[]>([]);
const umoQuery = ref("");
const umoQuery = ref(
typeof initialUmoQuery === "string" ? initialUmoQuery : "",
);
const sortValue = ref("updated_at:desc");
const groupBySession = ref(false);
const mobileFiltersOpen = ref(false);
@@ -402,14 +410,17 @@ async function fetchConversations() {
page: page.value,
page_size: pageSize,
include_history: false,
exclude_ids: "astrbot",
exclude_platforms: "webchat",
sort_by: sortBy,
sort_order: sortOrder,
group_by_session: groupBySession.value,
};
if (keyword.value.trim()) params.keyword = keyword.value.trim();
if (umoQuery.value.trim()) params.umo = umoQuery.value.trim();
if (umoQuery.value.trim()) {
params.umo = umoQuery.value.trim();
} else {
params.exclude_ids = "astrbot";
params.exclude_platforms = "webchat";
}
if (selectedBotIds.value.length) {
params.platforms = selectedBotIds.value.join(",");
}
@@ -466,13 +477,22 @@ async function fetchConversations() {
function resetFilters() {
cancelScheduledFetch();
keyword.value = "";
umoQuery.value = "";
clearUmoQuery();
selectedBotIds.value = [];
selectedTypes.value = [];
sortValue.value = "updated_at:desc";
page.value = 1;
}
function clearUmoQuery() {
umoQuery.value = "";
if ("umo" in route.query) {
const query = { ...route.query };
delete query.umo;
void router.replace({ query });
}
}
function toggleConversation(item: Conversation) {
const key = conversationKey(item);
const next = { ...selectedByKey.value };
@@ -911,9 +931,21 @@ function changePage(nextPage: number) {
density="compact"
variant="solo-filled"
flat
clearable
hide-details
/>
>
<template #append-inner>
<button
v-if="umoQuery"
type="button"
class="filter-input-clear"
:aria-label="tm('workspace.filters.reset')"
@mousedown.prevent
@click.stop="clearUmoQuery"
>
<X :size="18" aria-hidden="true" />
</button>
</template>
</v-text-field>
</div>
<div class="filter-block filter-block--last">
@@ -1539,6 +1571,26 @@ function changePage(nextPage: number) {
opacity: 0;
}
.filter-input-clear {
align-items: center;
background: transparent;
border: 0;
border-radius: 50%;
color: rgba(var(--v-theme-on-surface), 0.54);
cursor: pointer;
display: inline-flex;
height: 28px;
justify-content: center;
padding: 0;
transition: background-color 0.16s ease, color 0.16s ease;
width: 28px;
}
.filter-input-clear:hover {
background: rgba(var(--v-theme-on-surface), 0.07);
color: rgba(var(--v-theme-on-surface), 0.82);
}
.robot-options {
display: flex;
flex-direction: column;
+27 -3
View File
@@ -227,6 +227,19 @@
: globalT('core.common.copy') }}
</span>
</v-tooltip>
<v-tooltip location="top">
<template #activator="{ props }">
<RouterLink
v-bind="props"
class="umo-conversation-link"
:to="{ name: 'Conversation', query: { umo: item.umo } }"
:aria-label="t('sessionRanking.openConversation')"
>
<MessageSquareText :size="15" aria-hidden="true" />
</RouterLink>
</template>
<span>{{ t('sessionRanking.openConversation') }}</span>
</v-tooltip>
</div>
<strong>{{ formatNumber(item.tokens) }}</strong>
</div>
@@ -240,8 +253,9 @@
<script setup lang="ts">
import type { ApexOptions } from 'apexcharts'
import { Check, Copy, MessageCircle } from '@lucide/vue'
import { Check, Copy, MessageCircle, MessageSquareText } from '@lucide/vue'
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
import { RouterLink } from 'vue-router'
import { useTheme } from 'vuetify'
import { statsApi } from '@/api/v1'
import { useI18n, useModuleI18n } from '@/i18n/composables'
@@ -1077,6 +1091,7 @@ onBeforeUnmount(() => {
.provider-list {
display: grid;
gap: 12px;
min-width: 0;
}
.provider-list--scrollable {
@@ -1089,6 +1104,12 @@ onBeforeUnmount(() => {
padding: 12px 0;
border-bottom: 1px solid var(--stats-border);
font-size: 14px;
min-width: 0;
width: 100%;
}
.provider-row > strong {
flex: 0 0 auto;
}
.provider-row:last-child {
@@ -1129,7 +1150,8 @@ onBeforeUnmount(() => {
overflow-wrap: anywhere;
}
.umo-copy-button {
.umo-copy-button,
.umo-conversation-link {
align-items: center;
background: transparent;
border: 0;
@@ -1141,11 +1163,13 @@ onBeforeUnmount(() => {
height: 26px;
justify-content: center;
padding: 0;
text-decoration: none;
transition: background-color 0.18s ease, color 0.18s ease;
width: 26px;
}
.umo-copy-button:hover {
.umo-copy-button:hover,
.umo-conversation-link:hover {
background: rgba(var(--v-theme-on-surface), 0.07);
color: var(--stats-text);
}