Files
momentry_core/portal/src/views/IdentityDetailView.vue

117 lines
4.3 KiB
Vue

<template>
<div class="space-y-6">
<!-- Header -->
<div class="flex items-center space-x-4">
<button @click="$router.back()" class="text-gray-400 hover:text-white">
返回
</button>
<div>
<h2 class="text-2xl font-bold">{{ profile.name || '未命名身份' }}</h2>
<p class="text-sm text-gray-400">全域身份 ID: {{ identityId }}</p>
</div>
</div>
<!-- Loading -->
<div v-if="loading" class="text-center py-12 text-gray-500">載入中...</div>
<!-- Content -->
<div v-else-if="detail" class="grid gap-6">
<!-- Profile Card -->
<div class="bg-gray-800 rounded-lg p-6 border border-gray-700">
<h3 class="text-lg font-semibold text-blue-400 mb-4">人物檔案</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<span class="text-gray-500 text-sm">本名</span>
<p class="text-white text-lg">{{ profile.name || '-' }}</p>
</div>
<div>
<span class="text-gray-500 text-sm">角色名</span>
<p class="text-white text-lg">{{ profile.character_name || '-' }}</p>
</div>
<div>
<span class="text-gray-500 text-sm">別名 (Aliases)</span>
<div class="flex flex-wrap gap-2 mt-1">
<span v-for="(alias, idx) in profile.aliases" :key="idx" class="bg-gray-700 text-gray-300 px-2 py-1 rounded text-sm">
{{ alias }}
</span>
<span v-if="!profile.aliases || profile.aliases.length === 0" class="text-gray-600 text-sm"></span>
</div>
</div>
<div>
<span class="text-gray-500 text-sm">Speaker ID</span>
<p class="text-white text-lg font-mono">{{ profile.speaker_id || '-' }}</p>
</div>
<div>
<span class="text-gray-500 text-sm">性別</span>
<p class="text-white">{{ profile.gender || '-' }}</p>
</div>
<div>
<span class="text-gray-500 text-sm">年齡</span>
<p class="text-white">{{ profile.age || '-' }}</p>
</div>
</div>
</div>
<!-- Videos List -->
<div class="bg-gray-800 rounded-lg p-6 border border-gray-700">
<h3 class="text-lg font-semibold text-green-400 mb-4">出現影片 ({{ videos.length }})</h3>
<div class="overflow-x-auto">
<table class="w-full text-sm text-left text-gray-400">
<thead class="text-xs text-gray-500 uppercase bg-gray-700">
<tr>
<th scope="col" class="px-6 py-3 rounded-l-lg">影片名稱</th>
<th scope="col" class="px-6 py-3">區域 ID</th>
<th scope="col" class="px-6 py-3">出現次數</th>
<th scope="col" class="px-6 py-3 rounded-r-lg">首次出現</th>
</tr>
</thead>
<tbody>
<tr v-for="video in videos" :key="video.file_uuid" class="bg-gray-800 border-b border-gray-700 hover:bg-gray-750">
<td class="px-6 py-4 font-medium text-white">{{ video.file_name }}</td>
<td class="px-6 py-4 font-mono text-blue-300">{{ video.person_id }}</td>
<td class="px-6 py-4">{{ video.appearance_count }}</td>
<td class="px-6 py-4">{{ video.first_appearance?.toFixed(2) || '-' }}s</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { httpFetch, getCurrentConfig } from '@/api/client'
const route = useRoute()
const identityId = ref('')
const loading = ref(false)
const detail = ref<any>(null)
const profile = ref<any>({})
const videos = ref<any[]>([])
const loadDetail = async () => {
identityId.value = route.params.id as string
loading.value = true
try {
const config = getCurrentConfig()
const result = await httpFetch<any>(`${config.api_base_url}/api/v1/identity/${identityId.value}`)
detail.value = result
profile.value = result.profile || {}
videos.value = result.videos || []
} catch (error) {
console.error('Failed to load identity detail:', error)
alert('載入失敗: ' + error)
} finally {
loading.value = false
}
}
onMounted(() => {
loadDetail()
})
</script>