Files
panel/resources/js/components/AnalysisCard.vue

442 lines
12 KiB
Vue
Raw Permalink Normal View History

2025-08-04 16:33:07 +03:30
<template>
<VCard class="h-100 overflow-visible position-relative" :style="cardBackgroundStyle">
<VCardText class="pa-6 h-100 d-flex flex-column">
<div class="d-flex justify-center align-center mb-4 flex-wrap gap-2">
<VChip color="primary" variant="tonal" size="small">
<VIcon icon="tabler-calendar" size="14" class="me-1" />
{{ getCurrentDate() }}
</VChip>
<VChip color="secondary" variant="outlined" size="small" v-if="chartName">
<VIcon icon="tabler-chart-line" size="14" class="me-1" />
{{ chartName }}
</VChip>
</div>
<div class="text-center mb-6">
<div class="progress-circle-container mb-4">
<VProgressCircular
:model-value="completionPercent"
:size="120"
:width="8"
color="success"
class="progress-main"
>
<div class="text-center">
<h3 class="text-h3 font-weight-bold">{{ completionPercent }}%</h3>
<span class="text-caption text-medium-emphasis">Completed</span>
</div>
</VProgressCircular>
</div>
</div>
<div class="mb-4">
<VBtn
block
color="primary"
variant="elevated"
size="large"
class="btn-analyze"
:loading="loading"
@click="onAnalyzeClick"
>
<VIcon
:icon="loading ? 'tabler-loader-2' : 'tabler-chart-bar'"
class="me-2"
:class="{ 'rotating': loading }"
/>
{{ loading ? "Analyzing..." : "Analyze" }}
</VBtn>
</div>
<div class="flex-grow-1 d-flex flex-column" style="min-height: 0; height: 250px;">
<VCard
variant="tonal"
color="surface"
class="analysis-container d-flex flex-column h-100"
>
<VCardText class="pa-4 d-flex flex-column h-100" style="min-height: 0;">
<div class="d-flex align-center mb-3">
<VIcon icon="tabler-report-analytics" class="me-2" />
<h6 class="text-h6">Analysis Results {{ chartName ? `- ${chartName}` : '' }}</h6>
</div>
<div
class="analysis-content custom-scrollbar"
style="overflow-y: auto; height: 1px; flex: 1; color: white;"
v-html="analysisResult"
></div>
</VCardText>
</VCard>
</div>
</VCardText>
</VCard>
</template>
<script setup>
import { ref, computed } from 'vue'
import { useTheme } from 'vuetify'
import { hexToRgb } from '@layouts/utils'
// Define props
const props = defineProps({
chartName: {
type: String,
default: '',
required: false
}
})
const vuetifyTheme = useTheme()
const loading = ref(false)
const completionPercent = ref(25)
const analysisResult = ref(`
<div class="text-center text-medium-emphasis py-8">
<div class="mb-3">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
<path d="M3 3v18h18"/>
<path d="M18.7 8l-5.1 5.2-2.8-2.7L7 14.3"/>
</svg>
</div>
<p class="mb-0">Click 'Analyze ${props.chartName || 'Projects'}' to generate detailed insights</p>
</div>
`)
const getCurrentDate = () => {
const today = new Date()
const options = {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric'
}
return today.toLocaleDateString('en-US', options)
}
const cardBackgroundStyle = computed(() => {
const currentTheme = vuetifyTheme.current.value.colors
const createGradientColor = (color, opacity = 0.08) =>
color.startsWith('#') ? `rgba(${hexToRgb(color)}, ${opacity})` : `rgba(${hexToRgb(color)}, ${opacity})`
return {
background: `linear-gradient(135deg,
${createGradientColor(currentTheme.primary, 0.12)} 0%,
${createGradientColor(currentTheme.success, 0.06)} 50%,
${createGradientColor(currentTheme.primary, 0.04)} 100%)`
}
})
function onAnalyzeClick() {
loading.value = true
analysisResult.value = `
<div class="text-center py-4">
<div class="mb-3">
<svg class="rotating" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 12a9 9 0 11-6.219-8.56"/>
</svg>
</div>
<p class="text-medium-emphasis">Analyzing ${props.chartName || 'project'} data...</p>
</div>
`
setTimeout(() => {
loading.value = false
analysisResult.value = `
<div class="analysis-results">
<div class="result-section mb-4">
<h6 class="text-subtitle-1 mb-3 d-flex align-center">
<span class="result-icon success me-2">📊</span>
${props.chartName || 'Project'} Overview
</h6>
<div class="result-grid">
<div class="result-item">
<span class="result-label">Avg. Completion Time</span>
<span class="result-value text-primary">14 days</span>
</div>
<div class="result-item">
<span class="result-label">Success Rate</span>
<span class="result-value text-success">85%</span>
</div>
</div>
</div>
<div class="result-section mb-4">
<h6 class="text-subtitle-1 mb-3 d-flex align-center">
<span class="result-icon warning me-2">📈</span>
Current Status
</h6>
<div class="status-list">
<div class="status-item">
<div class="status-dot success"></div>
<span>Completed ${props.chartName ? props.chartName.toLowerCase() : 'projects'}: <strong>1</strong></span>
</div>
<div class="status-item">
<div class="status-dot warning"></div>
<span>Pending ${props.chartName ? props.chartName.toLowerCase() : 'projects'}: <strong>2</strong></span>
</div>
<div class="status-item">
<div class="status-dot primary"></div>
<span>Average Progress: <strong>40%</strong></span>
</div>
</div>
</div>
<div class="result-section mb-4">
<h6 class="text-subtitle-1 mb-3 d-flex align-center">
<span class="result-icon info me-2">💡</span>
Recommendations
</h6>
<ul class="recommendation-list">
<li>Focus on completing pending ${props.chartName ? props.chartName.toLowerCase() : 'projects'}</li>
<li>Optimize resource allocation for better efficiency</li>
<li>Set up automated progress tracking</li>
<li>Review ${props.chartName ? props.chartName.toLowerCase() : 'project'} timelines and deadlines</li>
<li>Implement better team communication</li>
<li>Consider hiring additional resources</li>
</ul>
</div>
<div class="result-section mb-4">
<h6 class="text-subtitle-1 mb-3 d-flex align-center">
<span class="result-icon me-2">📅</span>
Detailed Timeline
</h6>
<div class="timeline-items">
<div class="timeline-item">
<div class="timeline-dot"></div>
<div class="timeline-content">
<strong>Alpha ${props.chartName || 'Project'}</strong> - Started 10 days ago, 80% complete
</div>
</div>
<div class="timeline-item">
<div class="timeline-dot"></div>
<div class="timeline-content">
<strong>Beta ${props.chartName || 'Project'}</strong> - Started 5 days ago, 30% complete
</div>
</div>
<div class="timeline-item">
<div class="timeline-dot"></div>
<div class="timeline-content">
<strong>Gamma ${props.chartName || 'Project'}</strong> - Starting next week, 0% complete
</div>
</div>
</div>
</div>
<div class="result-section">
<h6 class="text-subtitle-1 mb-3 d-flex align-center">
<span class="result-icon me-2"></span>
Performance Metrics
</h6>
<div class="metrics-grid">
<div class="metric-item">
<span class="metric-label">Tasks per Day</span>
<span class="metric-value">3.2</span>
</div>
<div class="metric-item">
<span class="metric-label">Efficiency Score</span>
<span class="metric-value">92%</span>
</div>
<div class="metric-item">
<span class="metric-label">Team Velocity</span>
<span class="metric-value">High</span>
</div>
<div class="metric-item">
<span class="metric-label">Quality Score</span>
<span class="metric-value">8.7/10</span>
</div>
</div>
</div>
</div>
`
}, 2000)
}
</script>
<style scoped>
.progress-circle-container {
position: relative;
display: inline-block;
}
.floating-stats {
position: absolute;
top: -10px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 8px;
}
.stat-chip {
backdrop-filter: blur(10px);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.btn-analyze {
box-shadow: 0 4px 12px rgba(var(--v-theme-primary), 0.3);
transition: all 0.3s ease;
}
.btn-analyze:hover {
transform: translateY(-2px);
box-shadow: 0 6px 16px rgba(var(--v-theme-primary), 0.4);
}
.analysis-container {
backdrop-filter: blur(10px);
border: 1px solid rgba(var(--v-border-color), 0.1);
}
.analysis-content {
scrollbar-width: thin;
scrollbar-color: rgba(var(--v-theme-primary), 0.3) transparent;
color: white !important;
}
.analysis-content * {
color: white !important;
}
.analysis-content .text-medium-emphasis {
color: rgba(255, 255, 255, 0.7) !important;
}
.analysis-content .text-primary {
color: rgb(var(--v-theme-primary)) !important;
}
.analysis-content .text-success {
color: rgb(var(--v-theme-success)) !important;
}
.custom-scrollbar::-webkit-scrollbar {
width: 6px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background-color: rgba(var(--v-theme-primary), 0.3);
border-radius: 4px;
}
.rotating {
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.result-section {
background: rgba(var(--v-theme-surface), 0.5);
border-radius: 8px;
padding: 16px;
border: 1px solid rgba(var(--v-border-color), 0.1);
}
.result-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.result-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.result-label {
font-size: 0.75rem;
opacity: 0.7;
}
.result-value {
font-weight: 600;
font-size: 0.875rem;
}
.status-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.status-item {
display: flex;
align-items: center;
gap: 8px;
font-size: 0.875rem;
}
.status-dot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.status-dot.success { background-color: rgb(var(--v-theme-success)); }
.status-dot.warning { background-color: rgb(var(--v-theme-warning)); }
.status-dot.primary { background-color: rgb(var(--v-theme-primary)); }
.result-icon {
font-size: 1.2rem;
}
.recommendation-list {
margin: 0;
padding-left: 16px;
}
.recommendation-list li {
margin-bottom: 6px;
font-size: 0.875rem;
opacity: 0.8;
}
.timeline-items {
display: flex;
flex-direction: column;
gap: 12px;
}
.timeline-item {
display: flex;
align-items: center;
gap: 12px;
}
.timeline-dot {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: rgb(var(--v-theme-primary));
flex-shrink: 0;
}
.timeline-content {
font-size: 0.875rem;
}
.metrics-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 12px;
}
.metric-item {
display: flex;
flex-direction: column;
gap: 4px;
}
.metric-label {
font-size: 0.75rem;
opacity: 0.7;
}
.metric-value {
font-weight: 600;
font-size: 0.875rem;
color: rgb(var(--v-theme-primary));
}
</style>