interpreter-admin/pages/dashboard.vue
Mars Developer 51f8d95bf9 first commit
2025-06-26 11:24:11 +08:00

290 lines
9.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="space-y-6">
<!-- 统计卡片 -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4.354a4 4 0 110 5.292M15 21H3v-1a6 6 0 0112 0v1zm0 0h6v-1a6 6 0 00-9-5.197m13.5-9a2.5 2.5 0 11-5 0 2.5 2.5 0 015 0z"></path>
</svg>
</div>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">总用户数</dt>
<dd class="text-lg font-medium text-gray-900">{{ stats.totalUsers }}</dd>
</dl>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-green-500 rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
</svg>
</div>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">今日订单</dt>
<dd class="text-lg font-medium text-gray-900">{{ stats.todayOrders }}</dd>
</dl>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-yellow-500 rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8c-1.657 0-3 .895-3 2s1.343 2 3 2 3 .895 3 2-1.343 2-3 2m0-8c1.11 0 2.08.402 2.599 1M12 8V7m0 1v8m0 0v1m0-1c-1.11 0-2.08-.402-2.599-1"></path>
</svg>
</div>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">今日收入</dt>
<dd class="text-lg font-medium text-gray-900">¥{{ stats.todayRevenue.toLocaleString() }}</dd>
</dl>
</div>
</div>
</div>
<div class="bg-white rounded-lg shadow p-6">
<div class="flex items-center">
<div class="flex-shrink-0">
<div class="w-8 h-8 bg-purple-500 rounded-full flex items-center justify-center">
<svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
</svg>
</div>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 truncate">活跃译员</dt>
<dd class="text-lg font-medium text-gray-900">{{ stats.activeTranslators }}</dd>
</dl>
</div>
</div>
</div>
</div>
<!-- 最近活动 -->
<div class="bg-white shadow rounded-lg">
<div class="px-6 py-4 border-b border-gray-200">
<h3 class="text-lg font-medium text-gray-900">最近活动</h3>
</div>
<div class="px-6 py-4">
<div class="flow-root">
<ul class="-my-5 divide-y divide-gray-200">
<li v-for="activity in recentActivities" :key="activity.id" class="py-4">
<div class="flex items-center space-x-4">
<div class="flex-shrink-0">
<div :class="activity.iconColor" class="w-8 h-8 rounded-full flex items-center justify-center">
<span class="text-sm font-medium text-white">{{ activity.icon }}</span>
</div>
</div>
<div class="flex-1 min-w-0">
<p class="text-sm font-medium text-gray-900 truncate">{{ activity.title }}</p>
<p class="text-sm text-gray-500">{{ activity.description }}</p>
</div>
<div class="flex-shrink-0 text-sm text-gray-500">{{ activity.time }}</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup>
// 确保使用默认布局包含Sidebar和管理员认证
definePageMeta({
middleware: 'admin-auth', // 使用管理员认证中间件
layout: 'default' // 明确指定使用默认布局
})
// 页面标题
useHead({
title: '仪表板 - 翻译管理系统'
})
// 临时注释掉Supabase导入
// const { getStats, getCalls } = useSupabaseData()
// 当前用户信息
const currentUser = ref({
name: '系统管理员',
role: '管理员'
})
// 统计数据
const stats = ref({
totalUsers: 0,
todayOrders: 0,
todayRevenue: 0,
activeTranslators: 0
})
// 加载状态
const loading = ref(true)
const error = ref(null)
// 最近活动
const recentActivities = ref([])
// 获取用户信息
onMounted(() => {
loadDashboardData()
// 客户端专用操作
if (process.client) {
const adminUser = localStorage.getItem('adminUser')
if (adminUser) {
try {
const user = JSON.parse(adminUser)
console.log('当前用户:', user)
} catch (error) {
console.error('解析用户信息失败:', error)
}
}
}
})
// 加载仪表板数据
const loadDashboardData = async () => {
try {
loading.value = true
error.value = null
console.log('开始加载仪表板数据...')
// 临时注释掉Supabase调用使用模拟数据
// const statsData = await getStats()
// console.log('统计数据加载成功:', statsData)
// 使用模拟数据
const statsData = {
totalUsers: 156,
totalCalls: 23,
totalRevenue: 12580,
activeInterpreters: 8
}
stats.value = {
totalUsers: statsData.totalUsers || 0,
todayOrders: statsData.totalCalls || 0,
todayRevenue: statsData.totalRevenue || 0,
activeTranslators: statsData.activeInterpreters || 0
}
// 临时注释掉Supabase调用使用模拟数据
// const recentCalls = await getCalls()
// console.log('通话记录加载成功:', recentCalls)
// 使用模拟活动数据
recentActivities.value = [
{
id: 1,
title: '新订单创建',
description: '张先生 - 李译员',
time: '2分钟前',
icon: 'O',
iconColor: 'bg-yellow-400'
},
{
id: 2,
title: '翻译完成',
description: '王女士 - 陈译员',
time: '15分钟前',
icon: '✓',
iconColor: 'bg-green-400'
},
{
id: 3,
title: '翻译进行中',
description: '李总 - 刘译员',
time: '30分钟前',
icon: 'T',
iconColor: 'bg-blue-400'
}
]
console.log('仪表板数据加载成功:', { stats: stats.value, activities: recentActivities.value })
} catch (err) {
console.error('加载仪表板数据失败:', err)
error.value = '加载数据失败,请刷新页面重试'
// 显示默认数据
stats.value = {
totalUsers: 0,
todayOrders: 0,
todayRevenue: 0,
activeTranslators: 0
}
recentActivities.value = []
} finally {
loading.value = false
}
}
// 根据状态获取活动标题
const getActivityTitle = (status) => {
const statusMap = {
'pending': '新订单创建',
'in_progress': '翻译进行中',
'completed': '翻译完成',
'cancelled': '订单取消'
}
return statusMap[status] || '订单更新'
}
// 根据状态获取活动图标
const getActivityIcon = (status) => {
const iconMap = {
'pending': 'O',
'in_progress': 'T',
'completed': '✓',
'cancelled': 'X'
}
return iconMap[status] || 'U'
}
// 根据状态获取活动颜色
const getActivityColor = (status) => {
const colorMap = {
'pending': 'bg-yellow-400',
'in_progress': 'bg-blue-400',
'completed': 'bg-green-400',
'cancelled': 'bg-red-400'
}
return colorMap[status] || 'bg-gray-400'
}
// 格式化时间
const formatTime = (timestamp) => {
if (!timestamp) return '未知时间'
const now = new Date()
const time = new Date(timestamp)
const diff = now - time
const minutes = Math.floor(diff / (1000 * 60))
const hours = Math.floor(diff / (1000 * 60 * 60))
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
if (minutes < 1) return '刚刚'
if (minutes < 60) return `${minutes}分钟前`
if (hours < 24) return `${hours}小时前`
return `${days}天前`
}
</script>