File size: 5,102 Bytes
11a8eb2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
<template>
<div class="debug-view p-6">
<div class="mb-4">
<t-button theme="primary" @click="loadDebugData" :loading="loading">
<template #icon>
<t-icon name="refresh" />
</template>
刷新数据
</t-button>
</div>
<t-loading :loading="loading" text="正在加载调试数据...">
<div v-if="error" class="mb-4">
<t-alert theme="error" :message="error" />
</div>
<div v-if="!loading && debugList.length === 0" class="text-center py-12">
<t-icon name="inbox" size="48px" class="text-gray-400 mb-4" />
<p class="text-gray-500">暂无调试数据</p>
</div>
<div v-else class="space-y-4">
<t-card
v-for="item in debugList"
:key="item.debugId"
:class="{ 'border-red-200': item.hasError }"
class="cursor-pointer hover:shadow-md transition-shadow"
@click="toggleDebugContent(item.debugId)"
>
<template #header>
<div class="flex justify-between items-center">
<div class="flex items-center space-x-3">
<strong class="text-lg">{{ item.email }}</strong>
<t-tag
:theme="item.hasError ? 'danger' : 'success'"
variant="light"
>
{{ item.hasError ? '失败' : '成功' }}
</t-tag>
<span class="text-gray-500 text-sm">
{{ formatTime(item.timestamp) }}
</span>
</div>
<t-icon
:name="expandedItems.has(item.debugId) ? 'chevron-up' : 'chevron-down'"
class="text-gray-400"
/>
</div>
</template>
<div v-if="expandedItems.has(item.debugId)" class="space-y-4">
<div v-if="item.hasError" class="mb-4">
<t-alert theme="error" :message="`错误信息: ${item.errorMessage}`" />
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
<div>
<span class="font-medium text-gray-700">调试ID:</span>
<span class="ml-2 text-gray-600 font-mono">{{ item.debugId }}</span>
</div>
<div>
<span class="font-medium text-gray-700">邮箱:</span>
<span class="ml-2 text-gray-600">{{ item.email }}</span>
</div>
<div>
<span class="font-medium text-gray-700">时间:</span>
<span class="ml-2 text-gray-600">{{ formatTime(item.timestamp) }}</span>
</div>
<div>
<span class="font-medium text-gray-700">页面标题:</span>
<span class="ml-2 text-gray-600">{{ item.title }}</span>
</div>
<div class="md:col-span-2">
<span class="font-medium text-gray-700">页面URL:</span>
<span class="ml-2 text-gray-600 break-all">{{ item.url }}</span>
</div>
</div>
<div>
<h4 class="font-medium text-gray-700 mb-2">页面截图:</h4>
<div class="border rounded-lg overflow-hidden bg-gray-50">
<img
:src="item.screenshotUrl"
:alt="`${item.email} 的页面截图`"
class="w-full h-auto max-h-96 object-contain"
loading="lazy"
@error="handleImageError"
/>
</div>
</div>
</div>
</t-card>
</div>
</t-loading>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
interface DebugItem {
debugId: string
email: string
timestamp: string
url: string
title: string
hasError: boolean
errorMessage?: string
screenshotUrl: string
}
const loading = ref(false)
const error = ref('')
const debugList = ref<DebugItem[]>([])
const expandedItems = ref(new Set<string>())
const loadDebugData = async () => {
loading.value = true
error.value = ''
try {
const response = await fetch('/api/debug/list')
const result = await response.json()
if (result.success) {
debugList.value = result.data
} else {
error.value = `加载失败: ${result.error}`
}
} catch (err) {
error.value = `网络错误: ${err instanceof Error ? err.message : String(err)}`
} finally {
loading.value = false
}
}
const toggleDebugContent = (debugId: string) => {
if (expandedItems.value.has(debugId)) {
expandedItems.value.delete(debugId)
} else {
expandedItems.value.add(debugId)
}
}
const formatTime = (timestamp: string) => {
return new Date(timestamp).toLocaleString('zh-CN')
}
const handleImageError = (event: Event) => {
const img = event.target as HTMLImageElement
img.style.display = 'none'
const parent = img.parentElement
if (parent) {
parent.innerHTML = '<div class="text-center py-8 text-gray-500">截图加载失败</div>'
}
}
onMounted(() => {
loadDebugData()
})
</script> |