112 lines
3.1 KiB
Vue
112 lines
3.1 KiB
Vue
<template>
|
|
<v-sheet class="bg-surface" v-bind="$attrs">
|
|
<!-- Top Stats Cards -->
|
|
<v-row class="mb-4">
|
|
<v-col v-for="(stat, index) in props.stats" :key="index" cols="12" md="3" sm="6">
|
|
<AnalysisStatsCard
|
|
:color="stat.color"
|
|
:icon="stat.icon"
|
|
:label="stat.label"
|
|
:title="stat.title"
|
|
:total="stat.total"
|
|
:value="stat.value"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Main Trend Chart (Sparkline Area) -->
|
|
<v-row class="mb-4">
|
|
<v-col cols="12">
|
|
<AnalysisTrendChart
|
|
:active-filter="activeFilter"
|
|
:data="props.trendData"
|
|
:filters="props.trendFilters"
|
|
:title="props.trendTitle"
|
|
@filter-change="activeFilter = $event"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Bottom Charts Grid -->
|
|
<v-row>
|
|
<!-- Chart 1: Bar Chart (Proxy for Radar/Distribution) -->
|
|
<v-col cols="12" md="4">
|
|
<AnalysisBarChart :data="props.barData" :title="props.chart1Title" />
|
|
</v-col>
|
|
|
|
<!-- Chart 2: Donut Chart (Source) -->
|
|
<v-col cols="12" md="4">
|
|
<AnalysisPieChart :data="props.pie1Data" :title="props.chart2Title" />
|
|
</v-col>
|
|
|
|
<!-- Chart 3: Donut Chart (Distribution) -->
|
|
<v-col cols="12" md="4">
|
|
<AnalysisDonutChart :data="props.pie2Data" :title="props.chart3Title" />
|
|
</v-col>
|
|
</v-row>
|
|
</v-sheet>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { mdiSchool } from '@mdi/js'
|
|
import { ref } from 'vue'
|
|
import AnalysisBarChart from './base/analysis/AnalysisBarChart.vue'
|
|
import AnalysisDonutChart from './base/analysis/AnalysisDonutChart.vue'
|
|
import AnalysisPieChart from './base/analysis/AnalysisPieChart.vue'
|
|
import AnalysisStatsCard from './base/analysis/AnalysisStatsCard.vue'
|
|
import AnalysisTrendChart from './base/analysis/AnalysisTrendChart.vue'
|
|
|
|
interface StatsItem {
|
|
title: string
|
|
value: string | number
|
|
label: string
|
|
total: string | number
|
|
icon: string
|
|
color: string
|
|
}
|
|
|
|
interface BarDataItem {
|
|
label: string
|
|
value: number
|
|
color: string
|
|
}
|
|
|
|
interface PieData {
|
|
value: number
|
|
label: string
|
|
color: string
|
|
}
|
|
|
|
interface DonutData extends PieData {
|
|
icon: string
|
|
}
|
|
|
|
const props = defineProps({
|
|
// Stats Cards Data
|
|
stats: { type: Array as () => StatsItem[], default: () => [] },
|
|
|
|
// Trend Chart
|
|
trendTitle: { type: String, default: '流量趨勢' },
|
|
trendData: { type: Array as () => number[], default: () => [] },
|
|
trendFilters: { type: Array as () => string[], default: () => ['流量', '訪問量'] },
|
|
|
|
// Chart Titles
|
|
chart1Title: { type: String, default: '核心素養' },
|
|
chart2Title: { type: String, default: '訪問來源' },
|
|
chart3Title: { type: String, default: '成績分佈' },
|
|
|
|
// Data for Charts
|
|
barData: { type: Array as () => BarDataItem[], default: () => [] },
|
|
pie1Data: {
|
|
type: Object as () => PieData,
|
|
default: () => ({ value: 75, label: '直接訪問', color: 'primary' }),
|
|
},
|
|
pie2Data: {
|
|
type: Object as () => DonutData,
|
|
default: () => ({ value: 65, label: '及格率', color: 'success', icon: mdiSchool }),
|
|
},
|
|
})
|
|
|
|
const activeFilter = ref(props.trendFilters[0] || '')
|
|
</script>
|