mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-05-26 16:40:17 +08:00
feat: 成员Tab中支持设置Owner视角
This commit is contained in:
Vendored
+1
@@ -28,6 +28,7 @@ declare module 'vue' {
|
||||
UModal: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Modal.vue')['default']
|
||||
UPopover: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Popover.vue')['default']
|
||||
UProgress: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Progress.vue')['default']
|
||||
USelect: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Select.vue')['default']
|
||||
USwitch: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Switch.vue')['default']
|
||||
UTabs: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Tabs.vue')['default']
|
||||
UTextarea: typeof import('./../node_modules/.pnpm/@nuxt+ui@4.2.1_@babel+parser@7.28.5_axios@1.13.2_embla-carousel@8.6.0_typescript@5.9.3__1572391ae10a8169a5c9784ec5cec455/node_modules/@nuxt/ui/dist/runtime/components/Textarea.vue')['default']
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from 'vue'
|
||||
import type { MemberWithStats } from '@/types/analysis'
|
||||
import { useSessionStore } from '@/stores/session'
|
||||
|
||||
const sessionStore = useSessionStore()
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
sessionId: string
|
||||
members: MemberWithStats[]
|
||||
isLoading?: boolean
|
||||
chatType?: 'group' | 'private'
|
||||
}>()
|
||||
|
||||
// Owner 配置相关
|
||||
const isSavingOwner = ref(false)
|
||||
|
||||
// 获取成员显示名称
|
||||
function getDisplayName(member: MemberWithStats): string {
|
||||
return member.groupNickname || member.accountName || member.platformId
|
||||
}
|
||||
|
||||
// 当前 owner 的成员信息
|
||||
const currentOwner = computed(() => {
|
||||
const ownerId = sessionStore.currentSession?.ownerId
|
||||
if (!ownerId) return null
|
||||
return props.members.find((m) => m.platformId === ownerId) || null
|
||||
})
|
||||
|
||||
// 特殊值,用于表示"未设置"
|
||||
const UNSET_VALUE = '__UNSET__'
|
||||
|
||||
// 成员选项(用于下拉选择)
|
||||
const memberOptions = computed(() => {
|
||||
return [
|
||||
{ label: '未设置', value: UNSET_VALUE },
|
||||
...props.members.map((m) => ({
|
||||
label: `${getDisplayName(m)} (${m.platformId})`,
|
||||
value: m.platformId,
|
||||
})),
|
||||
]
|
||||
})
|
||||
|
||||
// 当前选中的 owner 值(用于 USelect)
|
||||
const selectedOwnerValue = computed(() => {
|
||||
return sessionStore.currentSession?.ownerId || UNSET_VALUE
|
||||
})
|
||||
|
||||
// 提示文字
|
||||
const hintText = computed(() => {
|
||||
if (currentOwner.value) {
|
||||
return `当前:${getDisplayName(currentOwner.value)}`
|
||||
}
|
||||
return props.chatType === 'group' ? '选择你在群聊中的身份,便于数据分析' : '选择你在对话中的身份,便于数据分析'
|
||||
})
|
||||
|
||||
// 更新 owner
|
||||
async function updateOwner(value: string) {
|
||||
const platformId = value === UNSET_VALUE ? null : value
|
||||
isSavingOwner.value = true
|
||||
try {
|
||||
await sessionStore.updateSessionOwnerId(props.sessionId, platformId)
|
||||
} catch (error) {
|
||||
console.error('更新所有者失败:', error)
|
||||
} finally {
|
||||
isSavingOwner.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-150 rounded-lg border border-gray-200 bg-white p-3 shadow-sm dark:border-gray-700 dark:bg-gray-900">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<div
|
||||
class="flex h-8 w-8 items-center justify-center rounded-full bg-linear-to-br"
|
||||
:class="chatType === 'group' ? 'from-pink-400 to-pink-600' : 'from-purple-400 to-purple-600'"
|
||||
>
|
||||
<UIcon name="i-heroicons-user" class="h-4 w-4 text-white" />
|
||||
</div>
|
||||
<div>
|
||||
<h3 class="text-sm font-medium text-gray-900 dark:text-white">设置「Owner」</h3>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">{{ hintText }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<USelect
|
||||
:model-value="selectedOwnerValue"
|
||||
:items="memberOptions"
|
||||
placeholder="选择成员"
|
||||
class="w-48"
|
||||
:disabled="isSavingOwner || isLoading"
|
||||
@update:model-value="updateOwner"
|
||||
/>
|
||||
<UIcon
|
||||
v-if="isSavingOwner"
|
||||
name="i-heroicons-arrow-path"
|
||||
class="h-4 w-4 animate-spin"
|
||||
:class="chatType === 'group' ? 'text-pink-500' : 'text-purple-500'"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import type { MemberWithStats } from '@/types/analysis'
|
||||
import OwnerSelector from '@/components/analysis/member/OwnerSelector.vue'
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
@@ -17,6 +18,10 @@ const members = ref<MemberWithStats[]>([])
|
||||
const isLoading = ref(false)
|
||||
const searchQuery = ref('')
|
||||
|
||||
// 删除确认状态
|
||||
const deletingMember = ref<MemberWithStats | null>(null)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
// 分页配置
|
||||
const pageSize = 20
|
||||
const currentPage = ref(1)
|
||||
@@ -24,10 +29,6 @@ const currentPage = ref(1)
|
||||
// 排序配置
|
||||
const sortOrder = ref<'desc' | 'asc'>('desc') // desc = 发言多在前
|
||||
|
||||
// 删除确认状态
|
||||
const deletingMember = ref<MemberWithStats | null>(null)
|
||||
const isDeleting = ref(false)
|
||||
|
||||
// 正在保存别名的成员ID(用于显示加载状态)
|
||||
const savingAliasesId = ref<number | null>(null)
|
||||
|
||||
@@ -188,6 +189,9 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Owner配置 -->
|
||||
<OwnerSelector class="mb-6" :session-id="sessionId" :members="members" :is-loading="isLoading" chat-type="group" />
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<div class="mb-4">
|
||||
<UInput
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, watch, onMounted } from 'vue'
|
||||
import type { MemberWithStats } from '@/types/analysis'
|
||||
import OwnerSelector from '@/components/analysis/member/OwnerSelector.vue'
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
@@ -104,6 +105,15 @@ onMounted(() => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Owner配置 -->
|
||||
<OwnerSelector
|
||||
class="mb-6"
|
||||
:session-id="sessionId"
|
||||
:members="members"
|
||||
:is-loading="isLoading"
|
||||
chat-type="private"
|
||||
/>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<div v-if="isLoading" class="flex h-60 items-center justify-center">
|
||||
<UIcon name="i-heroicons-arrow-path" class="h-8 w-8 animate-spin text-pink-500" />
|
||||
|
||||
+3
-1
@@ -118,6 +118,7 @@ export interface DbMeta {
|
||||
imported_at: number // 导入时间戳(秒)
|
||||
group_id: string | null // 群ID(群聊类型有值,私聊为空)
|
||||
group_avatar: string | null // 群头像(base64 Data URL)
|
||||
owner_id: string | null // 所有者/导出者的 platformId
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,6 +180,7 @@ export interface ParseResult {
|
||||
type: ChatType
|
||||
groupId?: string // 群ID(群聊类型有值)
|
||||
groupAvatar?: string // 群头像(base64 Data URL)
|
||||
ownerId?: string // 所有者/导出者的 platformId
|
||||
}
|
||||
members: ParsedMember[]
|
||||
messages: ParsedMessage[]
|
||||
@@ -200,6 +202,7 @@ export interface AnalysisSession {
|
||||
dbPath: string // 数据库文件完整路径
|
||||
groupId: string | null // 群ID(群聊类型有值,私聊为空)
|
||||
groupAvatar: string | null // 群头像(base64 Data URL)
|
||||
ownerId: string | null // 所有者/导出者的 platformId
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,4 +226,3 @@ export interface ImportResult {
|
||||
sessionId?: string // 成功时返回会话ID
|
||||
error?: string // 失败时返回错误信息
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -36,6 +36,7 @@ export interface ChatLabMeta {
|
||||
sources?: MergeSource[] // 合并来源(可选)
|
||||
groupId?: string // 群ID(可选,仅群聊)
|
||||
groupAvatar?: string // 群头像(base64 Data URL,可选)
|
||||
ownerId?: string // 所有者/导出者的 platformId(可选)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -181,4 +182,3 @@ export interface ChatRecordMessage {
|
||||
timestamp: number
|
||||
type: number
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user