25
src/oj/ai/components/AI.vue
Normal file
25
src/oj/ai/components/AI.vue
Normal file
@@ -0,0 +1,25 @@
|
||||
<template>
|
||||
<n-spin :show="aiStore.loading.ai">
|
||||
<div>AI 小助手友情提醒</div>
|
||||
</n-spin>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { useAIStore } from "~/oj/store/ai"
|
||||
|
||||
const aiStore = useAIStore()
|
||||
|
||||
watch(
|
||||
() => [
|
||||
aiStore.loading.details,
|
||||
aiStore.loading.weekly,
|
||||
],
|
||||
(newVal, oldVal) => {
|
||||
if (!oldVal) return
|
||||
const loaded = newVal.some((val, idx) => val === false && oldVal[idx] === true)
|
||||
if (loaded) {
|
||||
aiStore.fetchAIAnalysis()
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
@@ -1,33 +1,40 @@
|
||||
<template>
|
||||
<n-spin :show="detailLoading">
|
||||
<n-spin :show="aiStore.loading.details">
|
||||
<n-flex vertical size="large">
|
||||
<n-alert :show-icon="false" type="success" v-if="solvedProblems.length">
|
||||
<n-alert
|
||||
:show-icon="false"
|
||||
type="success"
|
||||
v-if="aiStore.detailsData.solved.length"
|
||||
>
|
||||
<span>{{ durationLabel }},</span>
|
||||
<span>{{ !!username ? username : "你" }}一共解决 </span>
|
||||
<b class="charming"> {{ solvedProblems.length }} </b>
|
||||
<span>{{ aiStore.theFirstPerson }}一共解决 </span>
|
||||
<b class="charming"> {{ aiStore.detailsData.solved.length }} </b>
|
||||
<span> 道题,</span>
|
||||
<span v-if="contest_count > 0">
|
||||
<span v-if="aiStore.detailsData.contest_count > 0">
|
||||
并且参加
|
||||
<b class="charming"> {{ contest_count }} </b> 次比赛,
|
||||
<b class="charming"> {{ aiStore.detailsData.contest_count }} </b>
|
||||
次比赛,
|
||||
</span>
|
||||
<span>综合评价给到</span>
|
||||
<Grade :grade="grade" />
|
||||
<Grade :grade="aiStore.detailsData.grade" />
|
||||
<span>{{ greeting }}</span>
|
||||
</n-alert>
|
||||
<n-alert
|
||||
type="error"
|
||||
v-else
|
||||
:title="(!!username ? username : '你') + '还没有完成任何题目'"
|
||||
></n-alert>
|
||||
<n-flex vertical size="large" v-else>
|
||||
<n-alert
|
||||
type="error"
|
||||
:title="aiStore.theFirstPerson + '还没有完成任何题目'"
|
||||
></n-alert>
|
||||
<AI />
|
||||
</n-flex>
|
||||
<n-flex>
|
||||
<TagsChart :tags="tags" />
|
||||
<DifficultyChart :difficulty="difficulty" />
|
||||
<TagsChart :tags="aiStore.detailsData.tags" />
|
||||
<DifficultyChart :difficulty="aiStore.detailsData.difficulty" />
|
||||
</n-flex>
|
||||
<n-data-table
|
||||
v-if="solvedProblems.length"
|
||||
v-if="aiStore.detailsData.solved.length"
|
||||
striped
|
||||
:max-height="400"
|
||||
:data="solvedProblems"
|
||||
:data="aiStore.detailsData.solved"
|
||||
:columns="columns"
|
||||
/>
|
||||
</n-flex>
|
||||
@@ -39,43 +46,18 @@ import Grade from "./Grade.vue"
|
||||
import TagsChart from "./TagsChart.vue"
|
||||
import DifficultyChart from "./DifficultyChart.vue"
|
||||
import TagTitle from "./TagTitle.vue"
|
||||
import AI from "./AI.vue"
|
||||
import { parseTime } from "~/utils/functions"
|
||||
import { getAIDetailData } from "~/oj/api"
|
||||
import { SolvedProblem } from "~/utils/types"
|
||||
import { useAIStore } from "~/oj/store/ai"
|
||||
|
||||
const props = defineProps<{
|
||||
start: string
|
||||
end: string
|
||||
duration: string
|
||||
username: string
|
||||
}>()
|
||||
|
||||
const router = useRouter()
|
||||
|
||||
interface SolvedProblem {
|
||||
problem: {
|
||||
title: string
|
||||
display_id: string
|
||||
contest_title: string
|
||||
contest_id: number
|
||||
}
|
||||
ac_time: string
|
||||
rank: number
|
||||
ac_count: number
|
||||
grade: "S" | "A" | "B" | "C"
|
||||
}
|
||||
|
||||
const detailLoading = ref(false)
|
||||
|
||||
const startLabel = ref("")
|
||||
const endLabel = ref("")
|
||||
|
||||
const grade = ref<"S" | "A" | "B" | "C">("B")
|
||||
const class_name = ref("")
|
||||
const tags = ref<{ [key: string]: number }>({})
|
||||
const difficulty = ref<{ [key: string]: number }>({})
|
||||
const contest_count = ref(0)
|
||||
|
||||
const solvedProblems = ref<SolvedProblem[]>([])
|
||||
const aiStore = useAIStore()
|
||||
|
||||
const columns: DataTableColumn<SolvedProblem>[] = [
|
||||
{
|
||||
@@ -109,7 +91,7 @@ const columns: DataTableColumn<SolvedProblem>[] = [
|
||||
),
|
||||
},
|
||||
{
|
||||
title: () => (class_name ? "班级排名" : "全服排名"),
|
||||
title: () => (aiStore.detailsData.class_name ? "班级排名" : "全服排名"),
|
||||
key: "rank",
|
||||
width: 100,
|
||||
align: "center",
|
||||
@@ -124,17 +106,17 @@ const columns: DataTableColumn<SolvedProblem>[] = [
|
||||
]
|
||||
|
||||
const durationLabel = computed(() => {
|
||||
if (props.duration.includes("hours")) {
|
||||
return `在 ${parseTime(startLabel.value, "HH:mm")} - ${parseTime(endLabel.value, "HH:mm")} 期间`
|
||||
} else if (props.duration.includes("days")) {
|
||||
return `在 ${parseTime(endLabel.value, "MM月DD日")}`
|
||||
if (aiStore.duration.includes("hours")) {
|
||||
return `在 ${parseTime(aiStore.detailsData.start, "HH:mm")} - ${parseTime(aiStore.detailsData.end, "HH:mm")} 期间`
|
||||
} else if (aiStore.duration.includes("days")) {
|
||||
return `在 ${parseTime(aiStore.detailsData.end, "MM月DD日")}`
|
||||
} else if (
|
||||
props.duration.includes("weeks") ||
|
||||
props.duration.includes("months")
|
||||
aiStore.duration.includes("weeks") ||
|
||||
aiStore.duration.includes("months")
|
||||
) {
|
||||
return `在 ${parseTime(startLabel.value, "MM月DD日")} - ${parseTime(endLabel.value, "MM月DD日")} 期间`
|
||||
return `在 ${parseTime(aiStore.detailsData.start, "MM月DD日")} - ${parseTime(aiStore.detailsData.end, "MM月DD日")} 期间`
|
||||
} else {
|
||||
return `在 ${parseTime(startLabel.value, "YYYY年MM月DD日")} - ${parseTime(endLabel.value, "YYYY年MM月DD日")} 期间`
|
||||
return `在 ${parseTime(aiStore.detailsData.start, "YYYY年MM月DD日")} - ${parseTime(aiStore.detailsData.end, "YYYY年MM月DD日")} 期间`
|
||||
}
|
||||
})
|
||||
|
||||
@@ -144,25 +126,16 @@ const greeting = computed(() => {
|
||||
A: "你很棒,继续保持!",
|
||||
B: "请再接再厉!",
|
||||
C: "你还需要努力!",
|
||||
}[grade.value]
|
||||
}[aiStore.detailsData.grade]
|
||||
})
|
||||
|
||||
async function getDetail() {
|
||||
detailLoading.value = true
|
||||
const res = await getAIDetailData(props.start, props.end, props.username)
|
||||
detailLoading.value = false
|
||||
|
||||
startLabel.value = res.data.start
|
||||
endLabel.value = res.data.end
|
||||
solvedProblems.value = res.data.solved
|
||||
grade.value = res.data.grade
|
||||
class_name.value = res.data.class_name
|
||||
tags.value = res.data.tags
|
||||
difficulty.value = res.data.difficulty
|
||||
contest_count.value = res.data.contest_count
|
||||
}
|
||||
|
||||
watch(() => [props.duration, props.username], getDetail, { immediate: true })
|
||||
watch(
|
||||
() => [aiStore.duration, aiStore.username],
|
||||
() => {
|
||||
aiStore.fetchDetailsData(props.start, props.end, aiStore.username)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
<style scoped>
|
||||
.charming {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<n-spin :show="weeklyLoading">
|
||||
<n-spin :show="aiStore.loading.weekly">
|
||||
<div class="chart">
|
||||
<Chart type="bar" :data="data" :options="options" />
|
||||
</div>
|
||||
@@ -8,26 +8,23 @@
|
||||
<script setup lang="ts">
|
||||
import type { ChartData, ChartOptions, TooltipItem } from "chart.js"
|
||||
import { Chart } from "vue-chartjs"
|
||||
import { useAIStore } from "~/oj/store/ai"
|
||||
import { parseTime } from "~/utils/functions"
|
||||
import { WeeklyData } from "~/utils/types"
|
||||
import { getAIWeeklyData } from "~/oj/api"
|
||||
|
||||
const props = defineProps<{
|
||||
duration: string
|
||||
end: string
|
||||
username: string
|
||||
}>()
|
||||
|
||||
const weeklyLoading = ref(false)
|
||||
const aiStore = useAIStore()
|
||||
|
||||
const gradeOrder = ["C", "B", "A", "S"] as const
|
||||
|
||||
const title = computed(() => {
|
||||
if (props.duration === "months:2") {
|
||||
if (aiStore.duration === "months:2") {
|
||||
return "过去两个月的每周综合情况一览图"
|
||||
} else if (props.duration === "months:6") {
|
||||
} else if (aiStore.duration === "months:6") {
|
||||
return "过去半年的每月综合情况一览图"
|
||||
} else if (props.duration === "years:1") {
|
||||
} else if (aiStore.duration === "years:1") {
|
||||
return "过去一年的每月综合情况一览图"
|
||||
} else {
|
||||
return "过去四周的综合情况一览图"
|
||||
@@ -36,12 +33,11 @@ const title = computed(() => {
|
||||
|
||||
const data = computed<ChartData<"bar" | "line">>(() => {
|
||||
return {
|
||||
labels: weeklyData.value.map((weekly) => {
|
||||
labels: aiStore.weeklyData.map((weekly) => {
|
||||
let prefix = "周"
|
||||
if (weekly.unit === "months") {
|
||||
prefix = "月"
|
||||
}
|
||||
|
||||
return [
|
||||
parseTime(weekly.start, "M月D日"),
|
||||
parseTime(weekly.end, "M月D日"),
|
||||
@@ -51,19 +47,19 @@ const data = computed<ChartData<"bar" | "line">>(() => {
|
||||
{
|
||||
type: "bar",
|
||||
label: "完成题目数量",
|
||||
data: weeklyData.value.map((weekly) => weekly.problem_count),
|
||||
data: aiStore.weeklyData.map((weekly) => weekly.problem_count),
|
||||
yAxisID: "y",
|
||||
},
|
||||
{
|
||||
type: "bar",
|
||||
label: "总提交次数",
|
||||
data: weeklyData.value.map((weekly) => weekly.submission_count),
|
||||
data: aiStore.weeklyData.map((weekly) => weekly.submission_count),
|
||||
yAxisID: "y",
|
||||
},
|
||||
{
|
||||
type: "line",
|
||||
label: "等级",
|
||||
data: weeklyData.value.map((weekly) =>
|
||||
data: aiStore.weeklyData.map((weekly) =>
|
||||
gradeOrder.indexOf(weekly.grade || "C"),
|
||||
),
|
||||
tension: 0.4,
|
||||
@@ -124,18 +120,13 @@ const options = computed<ChartOptions<"bar" | "line">>(() => {
|
||||
}
|
||||
})
|
||||
|
||||
const weeklyData = ref<WeeklyData[]>([])
|
||||
|
||||
async function getWeeklyData() {
|
||||
weeklyLoading.value = true
|
||||
const res = await getAIWeeklyData(props.end, props.duration, props.username)
|
||||
weeklyData.value = res.data
|
||||
weeklyLoading.value = false
|
||||
}
|
||||
|
||||
watch(() => [props.duration, props.username], getWeeklyData, {
|
||||
immediate: true,
|
||||
})
|
||||
watch(
|
||||
() => [aiStore.duration, aiStore.username],
|
||||
() => {
|
||||
aiStore.fetchWeeklyData(props.end, aiStore.duration, aiStore.username)
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
</script>
|
||||
<style scoped>
|
||||
.chart {
|
||||
|
||||
Reference in New Issue
Block a user