305 lines
8.0 KiB
Vue
305 lines
8.0 KiB
Vue
<!-- frontend/src/views/Dashboard.vue -->
|
|
<template>
|
|
<div class="dashboard">
|
|
<!-- Page header with Fluent Design -->
|
|
<div class="page-header fluent-entrance mb-8">
|
|
<div class="d-flex justify-space-between align-center">
|
|
<div>
|
|
<h1 class="text-title1 mb-2">Dashboard</h1>
|
|
<p class="text-body1" style="color: #605E5C;">
|
|
Welcome back! Here's an overview of your assets.
|
|
</p>
|
|
</div>
|
|
<v-btn
|
|
color="primary"
|
|
variant="elevated"
|
|
size="large"
|
|
prepend-icon="mdi-plus"
|
|
class="fluent-layer-2"
|
|
@click="createAsset"
|
|
>
|
|
Add Asset
|
|
</v-btn>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stats cards with Fluent Design -->
|
|
<v-row class="mb-8">
|
|
<v-col cols="12" sm="6" md="3">
|
|
<v-card class="stat-card fluent-layer-1 pa-6 text-center" elevation="0">
|
|
<v-icon size="40" color="primary" class="mb-3">
|
|
mdi-package-variant
|
|
</v-icon>
|
|
<div class="text-title2 font-weight-bold mb-1" style="color: #0078D4;">
|
|
{{ totalAssets }}
|
|
</div>
|
|
<div class="text-caption1" style="color: #605E5C;">Total Assets</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<v-col cols="12" sm="6" md="3">
|
|
<v-card class="stat-card fluent-layer-1 pa-6 text-center" elevation="0">
|
|
<v-icon size="40" color="success" class="mb-3">
|
|
mdi-check-circle
|
|
</v-icon>
|
|
<div class="text-title2 font-weight-bold mb-1" style="color: #107C10;">
|
|
{{ activeAssets }}
|
|
</div>
|
|
<div class="text-caption1" style="color: #605E5C;">Active Assets</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<v-col cols="12" sm="6" md="3">
|
|
<v-card class="stat-card fluent-layer-1 pa-6 text-center" elevation="0">
|
|
<v-icon size="40" color="warning" class="mb-3">mdi-wrench</v-icon>
|
|
<div class="text-title2 font-weight-bold mb-1" style="color: #FFB900;">
|
|
{{ maintenanceAssets }}
|
|
</div>
|
|
<div class="text-caption1" style="color: #605E5C;">In Maintenance</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<v-col cols="12" sm="6" md="3">
|
|
<v-card class="stat-card fluent-layer-1 pa-6 text-center" elevation="0">
|
|
<v-icon size="40" color="info" class="mb-3">
|
|
mdi-currency-usd
|
|
</v-icon>
|
|
<div class="text-title2 font-weight-bold mb-1" style="color: #0078D4;">
|
|
{{ formatCurrency(totalValue) }}
|
|
</div>
|
|
<div class="text-caption1" style="color: #605E5C;">Total Value</div>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Quick actions and recent activity -->
|
|
<v-row>
|
|
<!-- Quick actions -->
|
|
<v-col cols="12" md="4">
|
|
<v-card class="pa-4">
|
|
<v-card-title class="text-h6 pa-0 mb-4"> Quick Actions </v-card-title>
|
|
|
|
<div class="d-flex flex-column ga-2">
|
|
<v-btn
|
|
variant="outlined"
|
|
block
|
|
prepend-icon="mdi-plus"
|
|
@click="createAsset"
|
|
>
|
|
Add New Asset
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
variant="outlined"
|
|
block
|
|
prepend-icon="mdi-wrench"
|
|
@click="createWorkOrder"
|
|
>
|
|
Create Work Order
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
variant="outlined"
|
|
block
|
|
prepend-icon="mdi-qrcode"
|
|
@click="scanQRCode"
|
|
>
|
|
Scan QR Code
|
|
</v-btn>
|
|
|
|
<v-btn
|
|
variant="outlined"
|
|
block
|
|
prepend-icon="mdi-chart-bar"
|
|
@click="viewReports"
|
|
>
|
|
View Reports
|
|
</v-btn>
|
|
</div>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<!-- Recent assets -->
|
|
<v-col cols="12" md="8">
|
|
<v-card class="pa-4">
|
|
<v-card-title
|
|
class="text-h6 pa-0 mb-4 d-flex justify-space-between align-center"
|
|
>
|
|
Recent Assets
|
|
<v-btn variant="text" size="small" @click="viewAllAssets">
|
|
View All
|
|
</v-btn>
|
|
</v-card-title>
|
|
|
|
<v-data-table
|
|
:headers="assetHeaders"
|
|
:items="recentAssets"
|
|
:loading="isLoading"
|
|
hide-default-footer
|
|
density="compact"
|
|
>
|
|
<template #item.status="{ item }">
|
|
<v-chip
|
|
:color="getStatusColor(item.status)"
|
|
size="small"
|
|
variant="flat"
|
|
>
|
|
{{ item.status }}
|
|
</v-chip>
|
|
</template>
|
|
|
|
<template #item.actions="{ item }">
|
|
<v-btn
|
|
icon="mdi-eye"
|
|
size="small"
|
|
variant="text"
|
|
@click="viewAsset(item.id)"
|
|
/>
|
|
</template>
|
|
</v-data-table>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, computed, onMounted } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { useAssetsStore } from '../stores/assets';
|
|
import { useUIStore } from '../stores/ui';
|
|
|
|
export default {
|
|
name: 'Dashboard',
|
|
setup() {
|
|
const router = useRouter();
|
|
const assetsStore = useAssetsStore();
|
|
const uiStore = useUIStore();
|
|
|
|
const assetHeaders = [
|
|
{ title: 'Name', value: 'name', sortable: false },
|
|
{ title: 'Identifier', value: 'asset_identifier', sortable: false },
|
|
{ title: 'Category', value: 'category', sortable: false },
|
|
{ title: 'Status', value: 'status', sortable: false },
|
|
{ title: 'Actions', value: 'actions', sortable: false, width: 80 },
|
|
];
|
|
|
|
// Mock data for demo
|
|
const mockAssets = [
|
|
{
|
|
id: '1',
|
|
name: 'Dell Laptop #001',
|
|
asset_identifier: 'IT001',
|
|
category: 'IT Equipment',
|
|
status: 'active',
|
|
},
|
|
{
|
|
id: '2',
|
|
name: 'Conference Table',
|
|
asset_identifier: 'FUR001',
|
|
category: 'Office Furniture',
|
|
status: 'active',
|
|
},
|
|
{
|
|
id: '3',
|
|
name: 'X-Ray Machine',
|
|
asset_identifier: 'MED001',
|
|
category: 'Medical Equipment',
|
|
status: 'maintenance',
|
|
},
|
|
];
|
|
|
|
const totalAssets = computed(() => 24); // Mock data
|
|
const activeAssets = computed(() => 20); // Mock data
|
|
const maintenanceAssets = computed(() => 3); // Mock data
|
|
const totalValue = computed(() => 125000); // Mock data
|
|
const recentAssets = computed(() => mockAssets);
|
|
const isLoading = computed(() => assetsStore.isLoading);
|
|
|
|
const createAsset = () => {
|
|
router.push('/assets/add');
|
|
};
|
|
|
|
const createWorkOrder = () => {
|
|
router.push('/work-orders/new');
|
|
};
|
|
|
|
const scanQRCode = () => {
|
|
uiStore.showInfo('QR Code scanner feature coming soon!');
|
|
};
|
|
|
|
const viewReports = () => {
|
|
router.push('/reports');
|
|
};
|
|
|
|
const viewAllAssets = () => {
|
|
router.push('/assets');
|
|
};
|
|
|
|
const viewAsset = (id) => {
|
|
router.push(`/assets/${id}`);
|
|
};
|
|
|
|
const formatCurrency = (amount) => {
|
|
return new Intl.NumberFormat('en-US', {
|
|
style: 'currency',
|
|
currency: 'USD',
|
|
}).format(amount);
|
|
};
|
|
|
|
const getStatusColor = (status) => {
|
|
const colors = {
|
|
active: 'success',
|
|
inactive: 'default',
|
|
maintenance: 'warning',
|
|
retired: 'error',
|
|
};
|
|
return colors[status] || 'default';
|
|
};
|
|
|
|
onMounted(() => {
|
|
uiStore.setPageTitle('Dashboard');
|
|
});
|
|
|
|
return {
|
|
assetHeaders,
|
|
totalAssets,
|
|
activeAssets,
|
|
maintenanceAssets,
|
|
totalValue,
|
|
recentAssets,
|
|
isLoading,
|
|
createAsset,
|
|
createWorkOrder,
|
|
scanQRCode,
|
|
viewReports,
|
|
viewAllAssets,
|
|
viewAsset,
|
|
formatCurrency,
|
|
getStatusColor,
|
|
};
|
|
},
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.dashboard {
|
|
padding: 24px;
|
|
}
|
|
|
|
.v-card {
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.v-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.dashboard {
|
|
padding: 16px;
|
|
}
|
|
}
|
|
</style>
|