feat: 迁移成员Tab内的模块到其他Tab

This commit is contained in:
digua
2026-04-02 22:33:10 +08:00
committed by digua
parent 4599ce44a0
commit 75183db517
5 changed files with 53 additions and 82 deletions
@@ -1,70 +0,0 @@
<script setup lang="ts">
import { ref, computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { SubTabs } from '@/components/UI'
import NicknameHistory from './member/NicknameHistory.vue'
import Relationships from './member/Relationships.vue'
import ClusterView from '@openchatlab/chart-cluster/ClusterView.vue'
const { t } = useI18n()
interface TimeFilter {
startTs?: number
endTs?: number
}
const props = defineProps<{
sessionId: string
timeFilter?: TimeFilter
}>()
// 子 Tab 配置
const subTabs = computed(() => [
{ id: 'relationships', label: t('analysis.subTabs.member.relationships'), icon: 'i-heroicons-heart' },
{ id: 'cluster', label: t('analysis.subTabs.member.cluster'), icon: 'i-heroicons-user-group' },
{ id: 'history', label: t('analysis.subTabs.member.nicknameHistory'), icon: 'i-heroicons-clock' },
])
const activeSubTab = ref('relationships')
</script>
<template>
<div class="flex h-full flex-col">
<!-- Tab 导航 -->
<SubTabs v-model="activeSubTab" :items="subTabs" persist-key="memberTab" />
<!-- Tab 内容 -->
<div class="flex-1 min-h-0 overflow-auto">
<Transition name="fade" mode="out-in">
<!-- 群关系 -->
<Relationships
v-if="activeSubTab === 'relationships'"
:session-id="props.sessionId"
:time-filter="props.timeFilter"
/>
<!-- 小团体 -->
<ClusterView
v-else-if="activeSubTab === 'cluster'"
:session-id="props.sessionId"
:time-filter="props.timeFilter"
/>
<!-- 昵称变更记录 -->
<NicknameHistory v-else-if="activeSubTab === 'history'" :session-id="props.sessionId" />
</Transition>
</div>
</div>
</template>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.15s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
+11 -1
View File
@@ -6,6 +6,8 @@ import UserSelect from '@/components/common/UserSelect.vue'
import MessageView from '@openchatlab/chart-message/MessageView.vue'
import InteractionView from '@openchatlab/chart-interaction/InteractionView.vue'
import RankingView from '@openchatlab/chart-ranking/RankingView.vue'
import Relationships from './view/Relationships.vue'
import ClusterView from '@openchatlab/chart-cluster/ClusterView.vue'
import { isFeatureSupported, type LocaleType } from '@/i18n'
const { t, locale } = useI18n()
@@ -25,10 +27,12 @@ const subTabs = computed(() => {
const tabs = [
{ id: 'message', label: t('analysis.subTabs.view.message'), icon: 'i-heroicons-chat-bubble-left-right' },
{ id: 'interaction', label: t('analysis.subTabs.view.interaction'), icon: 'i-heroicons-arrows-right-left' },
{ id: 'relationships', label: t('analysis.subTabs.member.relationships'), icon: 'i-heroicons-heart' },
{ id: 'cluster', label: t('analysis.subTabs.member.cluster'), icon: 'i-heroicons-user-group' },
]
// 榜单仅在中文下显示
if (isFeatureSupported('groupRanking', locale.value as LocaleType)) {
tabs.push({ id: 'ranking', label: t('analysis.subTabs.view.ranking'), icon: 'i-heroicons-trophy' })
tabs.splice(1, 0, { id: 'ranking', label: t('analysis.subTabs.view.ranking'), icon: 'i-heroicons-trophy' })
}
return tabs
})
@@ -63,6 +67,12 @@ const viewTimeFilter = computed(() => ({
:session-id="props.sessionId"
:time-filter="viewTimeFilter"
/>
<Relationships
v-else-if="activeSubTab === 'relationships'"
:session-id="props.sessionId"
:time-filter="viewTimeFilter"
/>
<ClusterView v-else-if="activeSubTab === 'cluster'" :session-id="props.sessionId" :time-filter="viewTimeFilter" />
<RankingView
v-else-if="activeSubTab === 'ranking'"
:session-id="props.sessionId"
@@ -0,0 +1,35 @@
<script setup lang="ts">
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import NicknameHistory from './NicknameHistory.vue'
const { t } = useI18n()
const props = defineProps<{
sessionId: string
}>()
const isOpen = ref(false)
</script>
<template>
<UButton variant="ghost" icon="i-heroicons-clock" size="sm" @click="isOpen = true">
{{ t('analysis.subTabs.member.nicknameHistory') }}
</UButton>
<UModal v-if="props.sessionId" v-model:open="isOpen" :ui="{ content: 'max-w-6xl h-[85vh]' }">
<template #content>
<div class="flex h-full flex-col overflow-hidden bg-white dark:bg-gray-900">
<div class="flex flex-none items-center justify-between border-b border-gray-200 px-5 py-3 dark:border-gray-700">
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
{{ t('analysis.subTabs.member.nicknameHistory') }}
</h2>
<UButton variant="ghost" icon="i-heroicons-x-mark" size="sm" @click="isOpen = false" />
</div>
<div class="flex-1 overflow-auto">
<NicknameHistory :session-id="props.sessionId" />
</div>
</div>
</template>
</UModal>
</template>
+7 -11
View File
@@ -12,8 +12,8 @@ import { ChatExplorer } from '@/components/AIChat'
import OverviewTab from './components/OverviewTab.vue'
import ViewTab from './components/ViewTab.vue'
import QuotesTab from './components/QuotesTab.vue'
import MemberTab from './components/MemberTab.vue'
import MemberList from '@/components/common/member/MemberList.vue'
import NicknameHistoryEntry from './components/member/NicknameHistoryEntry.vue'
import PageHeader from '@/components/layout/PageHeader.vue'
import SessionIndexModal from '@/components/analysis/SessionIndexModal.vue'
import IncrementalImportModal from '@/components/analysis/IncrementalImportModal.vue'
@@ -64,7 +64,6 @@ const allTabs = [
{ id: 'overview', labelKey: 'analysis.tabs.overview', icon: 'i-heroicons-chart-pie' },
{ id: 'view', labelKey: 'analysis.tabs.view', icon: 'i-heroicons-presentation-chart-bar' },
{ id: 'quotes', labelKey: 'analysis.tabs.groupQuotes', icon: 'i-heroicons-chat-bubble-bottom-center-text' },
{ id: 'members', labelKey: 'analysis.tabs.members', icon: 'i-heroicons-user-group' },
{ id: 'ai-chat', labelKey: 'analysis.tabs.aiChat', icon: 'i-heroicons-chat-bubble-left-ellipsis' },
{ id: 'lab', labelKey: 'analysis.tabs.lab', icon: 'i-heroicons-beaker' },
]
@@ -247,11 +246,11 @@ onMounted(() => {
<span class="whitespace-nowrap">{{ t(tab.labelKey) }}</span>
</button>
</div>
<!-- AI 对话实验室和成员页都不使用这里的时间范围筛选因此在这些一级 Tab 下隐藏 -->
<!-- AI 对话和实验室都不使用这里的时间范围筛选因此在这些一级 Tab 下隐藏 -->
<TimeSelect
v-model="timeRangeValue"
:session-id="currentSessionId ?? undefined"
:visible="activeTab !== 'ai-chat' && activeTab !== 'lab' && activeTab !== 'members'"
:visible="activeTab !== 'ai-chat' && activeTab !== 'lab'"
:initial-state="initialTimeState"
@update:full-range="fullTimeRange = $event"
@update:available-years="availableYears = $event"
@@ -298,12 +297,6 @@ onMounted(() => {
:session-id="currentSessionId!"
:time-filter="timeFilter"
/>
<MemberTab
v-else-if="activeTab === 'members'"
:key="'members-' + currentSessionId"
:session-id="currentSessionId!"
:time-filter="timeFilter"
/>
<ChatExplorer
v-else-if="activeTab === 'ai-chat'"
:key="'ai-chat-' + currentSessionId"
@@ -359,7 +352,10 @@ onMounted(() => {
{{ t('members.list.description', { count: session?.memberCount ?? 0 }) }}
</p>
</div>
<UButton variant="ghost" icon="i-heroicons-x-mark" size="sm" @click="showMemberManagementModal = false" />
<div class="flex items-center gap-2">
<NicknameHistoryEntry :session-id="currentSessionId" />
<UButton variant="ghost" icon="i-heroicons-x-mark" size="sm" @click="showMemberManagementModal = false" />
</div>
</div>
<div class="flex-1 overflow-hidden">
<MemberList :session-id="currentSessionId" :show-header="false" @data-changed="loadData" />