169 lines
6.3 KiB
Vue
169 lines
6.3 KiB
Vue
<template>
|
|
<div class="analytics-dashboard">
|
|
<!-- Header with Mode Toggle -->
|
|
<div class="flex flex-col md:flex-row md:items-center justify-between mb-8 p-6 bg-gradient-to-r from-gray-50 to-white rounded-2xl shadow-sm border border-gray-200">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-gray-900">Vehicle Analytics & TCO Dashboard</h1>
|
|
<p class="text-gray-600 mt-2">
|
|
{{ isPrivateGarage ? 'Personal driving insights and fun achievements' : 'Corporate fleet performance and cost optimization' }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="mt-4 md:mt-0">
|
|
<div class="flex items-center space-x-4">
|
|
<div class="flex items-center">
|
|
<span class="mr-3 text-sm font-medium text-gray-700">View Mode:</span>
|
|
<div class="relative inline-block w-64">
|
|
<div class="bg-gray-100 rounded-xl p-1 flex">
|
|
<button
|
|
@click="setMode('private_garage')"
|
|
:class="[
|
|
'flex-1 py-3 px-4 rounded-lg text-sm font-medium transition-all duration-200',
|
|
isPrivateGarage
|
|
? 'bg-white shadow text-gray-900'
|
|
: 'text-gray-600 hover:text-gray-900'
|
|
]"
|
|
>
|
|
<div class="flex items-center justify-center">
|
|
<span class="mr-2">🎮</span>
|
|
<span>Fun Stats</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
@click="setMode('corporate_fleet')"
|
|
:class="[
|
|
'flex-1 py-3 px-4 rounded-lg text-sm font-medium transition-all duration-200',
|
|
isCorporateFleet
|
|
? 'bg-white shadow text-gray-900'
|
|
: 'text-gray-600 hover:text-gray-900'
|
|
]"
|
|
>
|
|
<div class="flex items-center justify-center">
|
|
<span class="mr-2">📊</span>
|
|
<span>Business BI</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
@click="toggleMode"
|
|
class="px-4 py-3 bg-gradient-to-r from-blue-500 to-indigo-600 text-white rounded-xl font-medium hover:from-blue-600 hover:to-indigo-700 transition-all duration-200 shadow-md hover:shadow-lg flex items-center"
|
|
>
|
|
<span class="mr-2">🔄</span>
|
|
Switch to {{ isPrivateGarage ? 'Business' : 'Fun' }} View
|
|
</button>
|
|
</div>
|
|
|
|
<div class="mt-4 text-sm text-gray-500 flex items-center">
|
|
<div class="w-3 h-3 rounded-full bg-green-500 mr-2"></div>
|
|
<span>Live data updated {{ lastUpdated }}</span>
|
|
<button @click="refreshData" class="ml-4 text-blue-600 hover:text-blue-800 flex items-center">
|
|
<span class="mr-1">↻</span>
|
|
Refresh
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Mode Indicator -->
|
|
<div class="mb-6">
|
|
<div v-if="isPrivateGarage" class="inline-flex items-center px-4 py-2 rounded-full bg-gradient-to-r from-blue-100 to-indigo-100 text-blue-800">
|
|
<span class="mr-2">🎯</span>
|
|
<span class="font-medium">Private Garage Mode</span>
|
|
<span class="ml-2 text-sm">Personal insights and achievements</span>
|
|
</div>
|
|
<div v-else class="inline-flex items-center px-4 py-2 rounded-full bg-gradient-to-r from-green-100 to-emerald-100 text-green-800">
|
|
<span class="mr-2">🏢</span>
|
|
<span class="font-medium">Corporate Fleet Mode</span>
|
|
<span class="ml-2 text-sm">Business intelligence and TCO analysis</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Dynamic Component -->
|
|
<div class="mt-6">
|
|
<component :is="currentComponent" />
|
|
</div>
|
|
|
|
<!-- Footer Notes -->
|
|
<div class="mt-12 pt-6 border-t border-gray-200">
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
<div class="bg-gray-50 p-4 rounded-xl">
|
|
<h4 class="font-semibold text-gray-800 mb-2">📈 Data Sources</h4>
|
|
<p class="text-sm text-gray-600">Vehicle telemetry, fuel receipts, maintenance records, and insurance data aggregated in real-time.</p>
|
|
</div>
|
|
<div class="bg-gray-50 p-4 rounded-xl">
|
|
<h4 class="font-semibold text-gray-800 mb-2">🎯 Key Metrics</h4>
|
|
<p class="text-sm text-gray-600">TCO (Total Cost of Ownership), Cost per km, Fuel efficiency, Utilization rate, and Environmental impact.</p>
|
|
</div>
|
|
<div class="bg-gray-50 p-4 rounded-xl">
|
|
<h4 class="font-semibold text-gray-800 mb-2">🔄 Auto-Sync</h4>
|
|
<p class="text-sm text-gray-600">Data updates every 24 hours. Manual refresh available. Historical data retained for 36 months.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, ref, shallowRef } from 'vue'
|
|
import { useAppModeStore } from '@/stores/appModeStore'
|
|
import FunStats from './FunStats.vue'
|
|
import BusinessBI from './BusinessBI.vue'
|
|
|
|
const appModeStore = useAppModeStore()
|
|
const { mode, isPrivateGarage, isCorporateFleet, toggleMode, setMode } = appModeStore
|
|
|
|
const lastUpdated = ref('just now')
|
|
const isLoading = ref(false)
|
|
|
|
const currentComponent = shallowRef(FunStats)
|
|
|
|
// Watch mode changes and update component
|
|
import { watch } from 'vue'
|
|
watch(() => mode.value, (newMode) => {
|
|
if (newMode === 'private_garage') {
|
|
currentComponent.value = FunStats
|
|
} else {
|
|
currentComponent.value = BusinessBI
|
|
}
|
|
}, { immediate: true })
|
|
|
|
const refreshData = () => {
|
|
isLoading.value = true
|
|
// Simulate API call
|
|
setTimeout(() => {
|
|
const now = new Date()
|
|
lastUpdated.value = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
|
|
isLoading.value = false
|
|
|
|
// Show success notification
|
|
const event = new CustomEvent('show-toast', {
|
|
detail: {
|
|
message: 'Analytics data refreshed successfully',
|
|
type: 'success'
|
|
}
|
|
})
|
|
window.dispatchEvent(event)
|
|
}, 800)
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.analytics-dashboard {
|
|
font-family: 'Inter', sans-serif;
|
|
}
|
|
|
|
/* Smooth transitions for mode switching */
|
|
.component-enter-active,
|
|
.component-leave-active {
|
|
transition: opacity 0.3s ease, transform 0.3s ease;
|
|
}
|
|
|
|
.component-enter-from,
|
|
.component-leave-to {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
</style> |