xlx_teacher_app/src/components/class-analysis/QuestionScoreChart.vue

130 lines
2.8 KiB
Vue
Raw Normal View History

2025-10-08 17:17:22 +08:00
<script lang="ts" setup>
import type * as API from '@/service/types'
import UniEcharts from 'uni-echarts'
import { computed } from 'vue'
const props = defineProps<{
data: API.StudentScoreStat[]
loading?: boolean
}>()
const emit = defineEmits<{
viewStudents: [score: number]
}>()
// 图表配置(横向柱状图)
const chartOption = computed(() => {
if (!props.data || props.data.length === 0) {
return {}
}
// 按分数排序
const sortedData = [...props.data].sort((a, b) => (a.score || 0) - (b.score || 0))
const categories = sortedData.map(item => `${item.score || 0}`)
const counts = sortedData.map(item => item.student_count || 0)
return {
tooltip: {
trigger: 'axis',
confine: true,
axisPointer: {
type: 'shadow',
},
formatter: (params: any) => {
if (!Array.isArray(params))
return ''
const param = params[0]
// 使用 \n 换行而不是 <br/>
return `${param.axisValue}\n${param.marker} 人数: ${param.value}`
},
},
grid: {
left: 50,
right: 30,
bottom: 30,
top: 20,
containLabel: false,
},
// 横向柱状图xAxis 为数值轴yAxis 为类目轴
xAxis: {
type: 'value',
name: '人数',
nameTextStyle: {
fontSize: 11,
},
axisLabel: {
fontSize: 10,
},
splitLine: {
lineStyle: {
type: 'dashed',
color: '#eeeeee',
},
},
},
yAxis: {
type: 'category',
data: categories,
axisLabel: {
fontSize: 10,
},
axisLine: {
lineStyle: {
color: '#cccccc',
},
},
// 反转 Y 轴,让分数从上到下递增
inverse: true,
},
series: [
{
name: '人数',
type: 'bar',
data: counts,
itemStyle: {
color: '#3b82f6',
},
barMaxWidth: 30,
label: {
show: true,
position: 'right',
fontSize: 10,
formatter: '{c}人',
},
},
],
}
})
const showChart = computed(() => {
return !props.loading && props.data && props.data.length > 0
})
</script>
<template>
<view class="score-chart">
<!-- 图表 -->
<view v-if="showChart" class="chart-container">
<uni-echarts :option="chartOption" custom-class="chart" />
</view>
<!-- 加载状态 -->
<view v-if="loading" class="h-60 flex items-center justify-center">
<wd-loading size="24" />
</view>
<!-- 暂无数据 -->
<view v-if="!loading && (!data || data.length === 0)" class="py-8 text-center">
<text class="text-sm text-gray-500">暂无数据</text>
</view>
</view>
</template>
<style scoped>
.chart {
width: 100%;
height: 250px;
}
</style>