Files
ojnext/src/oj/ai/components/WeeklyChart.vue
yuetsh e71611ff1c
Some checks failed
Deploy / deploy (push) Has been cancelled
新增AI分析
2025-09-24 01:02:34 +08:00

127 lines
2.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="chart">
<Chart type="bar" :data="data" :options="options" />
</div>
</template>
<script setup lang="ts">
import type { ChartData, ChartOptions, TooltipItem } from "chart.js"
import { Chart } from "vue-chartjs"
import { parseTime } from "~/utils/functions"
import { WeeklyData } from "~/utils/types"
const props = defineProps<{
weeklyData: WeeklyData[]
duration: string
}>()
const gradeOrder = ["C", "B", "A", "S"] as const
const title = computed(() => {
if (props.duration === "months:2") {
return "过去两个月的每周综合情况一览图"
} else if (props.duration === "months:6") {
return "过去半年的每月综合情况一览图"
} else if (props.duration === "years:1") {
return "过去一年的每月综合情况一览图"
} else {
return "过去四周的综合情况一览图"
}
})
const data = computed<ChartData<"bar" | "line">>(() => {
return {
labels: props.weeklyData.map((weekly) => {
let prefix = "周"
if (weekly.unit === "months") {
prefix = "月"
}
return [
parseTime(weekly.start, "M月D日"),
parseTime(weekly.end, "M月D日"),
].join("")
}),
datasets: [
{
type: "bar",
label: "完成题目数量",
data: props.weeklyData.map((weekly) => weekly.problem_count),
yAxisID: "y",
},
{
type: "bar",
label: "总提交次数",
data: props.weeklyData.map((weekly) => weekly.submission_count),
yAxisID: "y",
},
{
type: "line",
label: "等级",
data: props.weeklyData.map((weekly) =>
gradeOrder.indexOf(weekly.grade || "C"),
),
tension: 0.4,
yAxisID: "y1",
barThickness: 10,
},
],
}
})
const options = computed<ChartOptions<"bar" | "line">>(() => {
return {
interaction: {
intersect: false,
},
maintainAspectRatio: false,
scales: {
y: {
ticks: {
stepSize: 1,
},
},
y1: {
type: "linear",
position: "right",
min: -1,
max: gradeOrder.length,
ticks: {
stepSize: 1,
callback: (v) => {
const idx = Number(v)
return gradeOrder[idx] || ""
},
},
},
},
plugins: {
title: {
text: title.value,
display: true,
font: {
size: 20,
},
},
tooltip: {
callbacks: {
label: (ctx: TooltipItem<"bar">) => {
const dsLabel = ctx.dataset.label || ""
if ((ctx.dataset as any).yAxisID === "y1") {
const idx = Number(ctx.parsed.y)
return `${dsLabel}: ${gradeOrder[idx] || ""}`
}
return `${dsLabel}: ${ctx.formattedValue}`
},
},
},
},
}
})
</script>
<style scoped>
.chart {
height: 300px;
width: 100%;
}
</style>