feat: add P6 frontend console integration
This commit is contained in:
87
frontend/src/components/dashboard/DashboardOverview.vue
Normal file
87
frontend/src/components/dashboard/DashboardOverview.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<template>
|
||||
<section class="feature-page__section">
|
||||
<div class="feature-grid feature-grid--cards">
|
||||
<StatCard v-for="card in cards" :key="card.label" :label="card.label" :value="card.value" :hint="card.hint" />
|
||||
</div>
|
||||
|
||||
<div class="feature-grid feature-grid--dashboard">
|
||||
<article class="feature-panel app-panel">
|
||||
<h3>Recent tasks</h3>
|
||||
<div v-for="task in tasks" :key="task.id" class="row-card">
|
||||
<div>
|
||||
<strong>{{ task.name }}</strong>
|
||||
<div class="muted">{{ task.processedFiles }} / {{ task.totalFiles }} files</div>
|
||||
</div>
|
||||
<StatusBadge :label="task.status" :tone="mapTaskStatusTone(task.status)" />
|
||||
</div>
|
||||
</article>
|
||||
|
||||
<article class="feature-panel app-panel">
|
||||
<h3>Processing chart</h3>
|
||||
<div class="muted">Chart total {{ chartTotal }}</div>
|
||||
<div ref="chartRef" class="echart-panel" aria-label="Processing chart"></div>
|
||||
</article>
|
||||
|
||||
<article class="feature-panel app-panel">
|
||||
<h3>Quick entries</h3>
|
||||
<div v-for="entry in quickEntries" :key="entry.title" class="row-card row-card--stacked">
|
||||
<strong>{{ entry.title }}</strong>
|
||||
<div>{{ entry.value }}</div>
|
||||
<div class="muted">{{ entry.hint }}</div>
|
||||
<RouterLink :to="entry.to" class="quick-link">{{ entry.actionLabel }}</RouterLink>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
||||
import { RouterLink } from 'vue-router'
|
||||
import * as echarts from 'echarts'
|
||||
import StatCard from '../common/StatCard.vue'
|
||||
import StatusBadge from '../common/StatusBadge.vue'
|
||||
import type { DashboardQuickEntry } from '../../types/dashboard'
|
||||
import type { TaskSummary } from '../../types/task'
|
||||
import { mapTaskStatusTone } from '../../utils/task'
|
||||
|
||||
const props = defineProps<{
|
||||
cards: Array<{ label: string; value: string; hint: string }>
|
||||
tasks: TaskSummary[]
|
||||
quickEntries: DashboardQuickEntry[]
|
||||
chartBars: Array<{ label: string; value: number; raw: number }>
|
||||
}>()
|
||||
|
||||
const chartRef = ref<HTMLDivElement | null>(null)
|
||||
let chartInstance: echarts.ECharts | null = null
|
||||
const chartTotal = computed(() => props.chartBars.reduce((sum, item) => sum + item.raw, 0))
|
||||
|
||||
function renderChart() {
|
||||
if (!chartRef.value) return
|
||||
if (typeof HTMLCanvasElement === 'undefined') return
|
||||
if (!HTMLCanvasElement.prototype.getContext) return
|
||||
if (chartRef.value.clientWidth === 0 || chartRef.value.clientHeight === 0) return
|
||||
|
||||
chartInstance?.dispose()
|
||||
|
||||
chartInstance = echarts.init(chartRef.value)
|
||||
chartInstance.setOption({
|
||||
tooltip: { trigger: 'item' },
|
||||
series: [
|
||||
{
|
||||
type: 'pie',
|
||||
radius: ['45%', '70%'],
|
||||
label: { color: '#e8eef8' },
|
||||
data: props.chartBars.map((bar) => ({ name: bar.label, value: bar.raw }))
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(renderChart)
|
||||
watch(() => props.chartBars, renderChart, { deep: true })
|
||||
onBeforeUnmount(() => {
|
||||
chartInstance?.dispose()
|
||||
chartInstance = null
|
||||
})
|
||||
</script>
|
||||
Reference in New Issue
Block a user