更新回复列表

This commit is contained in:
2026-03-18 09:09:51 +08:00
parent a414d2b003
commit fad174824a
2 changed files with 87 additions and 14 deletions

View File

@@ -1,5 +1,6 @@
<template>
<aside :style="{ width: sidebarWidth + 'px', minWidth: '96px', maxWidth: '400px' }" class="h-full bg-gradient-to-b from-white to-gray-50 border-r border-gray-200 flex flex-col shadow-sm flex-shrink-0">
<aside :style="{ width: sidebarWidth + 'px', minWidth: '96px', maxWidth: '400px' }"
class="h-full bg-gradient-to-b from-white to-gray-50 border-r border-gray-200 flex flex-col shadow-sm flex-shrink-0">
<!-- 返回和停止按钮 -->
<div class="m-3 mb-0 flex gap-2">
<button @click="onGoBack"
@@ -56,7 +57,7 @@
<span class="w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" />
<span class="text-emerald-600">{{ getRunningAccounts(getGroup(tabIndex)?.name ||
tab.label)
}} 个运行中</span>
}} 个运行中</span>
</template>
<template v-else>
<span class="text-gray-500">{{ getTotalAccounts(tabIndex) }} 个账号</span>
@@ -71,7 +72,8 @@
<!-- 详细统计 -->
<div class="flex-1 min-h-0 border-t border-gray-200 flex flex-col">
<div class="px-3 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wider bg-gray-50 flex justify-between items-center">
<div
class="px-3 py-2 text-xs font-semibold text-gray-500 uppercase tracking-wider bg-gray-50 flex justify-between items-center">
<span>详细统计</span>
<span class="text-[10px] font-normal text-gray-400">招呼/邀请/回复</span>
</div>
@@ -81,14 +83,17 @@
暂无统计数据
</div>
<template v-else>
<div v-for="(groupStats, groupName) in statsByGroup" :key="groupName" class="border-b border-gray-100 last:border-0">
<div v-for="(groupStats, groupName) in statsByGroup" :key="groupName"
class="border-b border-gray-100 last:border-0">
<div class="px-3 py-1.5 bg-gray-100/50 text-xs font-medium text-gray-600">
{{ groupName }}
</div>
<div v-for="stat in groupStats" :key="stat.viewId" class="px-3 py-1.5 flex items-center justify-between hover:bg-white transition-colors text-xs">
<div v-for="stat in groupStats" :key="stat.viewId"
class="px-3 py-1.5 flex items-center justify-between hover:bg-white transition-colors text-xs">
<div class="flex items-center gap-1">
<span class="text-gray-500">视图 {{ stat.viewId }}</span>
<span v-if="stat.unread > 0" class="w-1.5 h-1.5 rounded-full bg-red-500" :title="`${stat.unread} 条未读消息`"></span>
<span v-if="stat.unread > 0" class="w-1.5 h-1.5 rounded-full bg-red-500"
:title="`${stat.unread} 条未读消息`"></span>
</div>
<div class="flex items-center gap-3 font-mono text-gray-700">
<span class="text-blue-600 w-6 text-right">{{ stat.greeting }}</span>
@@ -135,19 +140,23 @@
<div class="flex items-center justify-between text-xs">
<span class="text-gray-500">已回复</span>
<div class="flex items-center gap-1">
<button @click="showReplyList" class="text-blue-500 hover:text-blue-600 hover:underline cursor-pointer" title="查看回复列表">
<button @click="showReplyList"
class="text-blue-500 hover:text-blue-600 hover:underline cursor-pointer" title="查看回复列表">
历史回复
</button>
<span class="text-emerald-600 font-medium">{{ greetingStats.replyCount || 0 }} </span>
</div>
</div>
<!-- 回复列表弹出框 -->
<div v-if="replyListVisible" class="absolute left-0 right-0 bottom-full mb-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 max-h-48 overflow-hidden" :style="{ maxWidth: sidebarWidth + 'px' }">
<div v-if="replyListVisible"
class="absolute left-0 right-0 bottom-full mb-1 bg-white border border-gray-200 rounded-lg shadow-lg z-50 max-h-48 overflow-hidden"
:style="{ maxWidth: sidebarWidth + 'px' }">
<div class="flex items-center justify-between px-3 py-2 border-b border-gray-100 bg-gray-50">
<span class="text-xs font-semibold text-gray-600">历史回复列表</span>
<button @click="replyListVisible = false" class="text-gray-400 hover:text-gray-600">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
@@ -156,8 +165,24 @@
暂无回复记录
</div>
<div v-else>
<div v-for="(name, index) in repliedSessions" :key="index" class="px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-50 border-b border-gray-50 last:border-0 truncate" :title="name">
{{ name }}
<div v-for="(session, index) in repliedSessions" :key="index"
class="px-3 py-1.5 text-xs text-gray-700 hover:bg-gray-50 border-b border-gray-50 last:border-0 flex items-center justify-between">
<div class="truncate" :title="session.name">
{{ session.name }}
</div>
<div class="flex items-center gap-2">
<!-- <span class="text-gray-400 text-[10px]">
ID: {{ session.id }}
</span> -->
<button @click="copyAnchorId(session.id)"
class="text-blue-500 hover:text-blue-600 p-1 rounded hover:bg-blue-50 transition-colors"
title="复制 ID">
<svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
</svg>
</button>
</div>
</div>
</div>
</div>
@@ -169,7 +194,7 @@
<script setup>
import { ref, computed, watch, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
const props = defineProps({
tabs: { type: Array, required: true },
currentTab: { type: String, required: true },
@@ -188,7 +213,7 @@ const emit = defineEmits(['tabSwitch', 'goBack', 'stopAll'])
// 回复列表相关
const replyListVisible = ref(false)
/** @type {import('vue').Ref<string[]>} */
/** @type {import('vue').Ref<Array<{name: string; id: string}>>} */
const repliedSessions = ref([])
// 显示回复列表
@@ -206,6 +231,54 @@ const showReplyList = async () => {
}
}
// 复制主播 ID
const copyAnchorId = (id) => {
if (navigator.clipboard && window.isSecureContext) {
// 现代浏览器使用 Clipboard API
navigator.clipboard.writeText(id).then(() => {
showCopySuccess()
}).catch(err => {
console.error('复制失败:', err)
// 回退到传统方法
fallbackCopyTextToClipboard(id)
})
} else {
// 传统方法
fallbackCopyTextToClipboard(id)
}
}
// 回退复制方法(兼容旧浏览器)
const fallbackCopyTextToClipboard = (text) => {
const textArea = document.createElement('textarea')
textArea.value = text
textArea.style.position = 'fixed'
textArea.style.left = '-999999px'
textArea.style.top = '-999999px'
document.body.appendChild(textArea)
textArea.focus()
textArea.select()
try {
const successful = document.execCommand('copy')
if (successful) {
showCopySuccess()
} else {
console.error('复制命令执行失败')
}
} catch (err) {
console.error('回退复制失败:', err)
} finally {
document.body.removeChild(textArea)
}
}
// 复制成功提示
const showCopySuccess = () => {
// 回退到 alert
ElMessage.success('复制成功!')
}
// Event handlers
const onTabSwitch = (id) => emit('tabSwitch', id)
const onGoBack = () => emit('goBack')

View File

@@ -126,7 +126,7 @@ export interface ElectronAPI {
// 打招呼统计
getGreetingStats: () => Promise<GreetingStats>
getRepliedSessions: () => Promise<string[]>
getRepliedSessions: () => Promise<Array<{ name: string; id: string }>>
// 获取打招呼内容
fetchPrologue: () => Promise<{ success: boolean; data?: string[]; error?: string }>