feat:教师咨询数据统计模块

This commit is contained in:
JiXinHui 2025-08-12 14:50:56 +08:00
parent 0b1dbf4d39
commit cf671344a7
4 changed files with 72 additions and 188 deletions

View File

@ -27,7 +27,7 @@ const props = withDefaults(
<style scoped lang="scss"> <style scoped lang="scss">
$item-title-height: 33px; $item-title-height: 33px;
$item_title_content-height: calc(100% - 33px); $item_title_content-height: calc(100% - 33px - 20px);
.item_wrap { .item_wrap {
background: #fff; background: #fff;

View File

@ -2,16 +2,23 @@
import { ref, onMounted } from "vue"; import { ref, onMounted } from "vue";
import { teacherConsultStats } from "@/api"; import { teacherConsultStats } from "@/api";
interface TeacherStats {
consultCount: number;
replyCount: number;
messageCount: number;
[key: string]: number; //
}
// //
const teacherStats = ref({ const teacherStats = ref<TeacherStats>({
consultCount: 0, consultCount: 0,
replyCount: 0, replyCount: 0,
messageCount: 0 messageCount: 0,
}); });
// //
const getTeacherStats = () => { const getTeacherStats = () => {
teacherConsultStats().then(res => { teacherConsultStats().then((res) => {
if (res.success) { if (res.success) {
teacherStats.value = res.data; teacherStats.value = res.data;
} }
@ -25,31 +32,33 @@ onMounted(() => {
<template> <template>
<div class="stats-container"> <div class="stats-container">
<div class="stat-item"> <div class="stat-item blue-card">
<div class="stat-icon blue-bg"> <div class="stat-icon">
<img src="@/assets/img/zheke/蓝色.png" alt="咨询次数"> <img src="@/assets/img/zheke/ai-stats1.png" alt="咨询次数" />
</div> </div>
<div class="stat-info"> <div class="stat-label">咨询次数</div>
<div class="stat-value">{{ teacherStats.consultCount }}</div> <div class="stat-value">
<div class="stat-label">咨询次数</div> {{ teacherStats.consultCount }}<span class="unit"></span>
</div> </div>
</div> </div>
<div class="stat-item">
<div class="stat-icon orange-bg"> <div class="stat-item orange-card">
<img src="@/assets/img/zheke/橙色.png" alt="回复数"> <div class="stat-icon">
<img src="@/assets/img/zheke/ai-stats2.png" alt="回复数" />
</div> </div>
<div class="stat-info"> <div class="stat-label">回复数</div>
<div class="stat-value">{{ teacherStats.replyCount }}</div> <div class="stat-value">
<div class="stat-label">回复数</div> {{ teacherStats.replyCount }}<span class="unit"></span>
</div> </div>
</div> </div>
<div class="stat-item">
<div class="stat-icon cyan-bg"> <div class="stat-item cyan-card">
<img src="@/assets/img/zheke/浅蓝色.png" alt="留言数"> <div class="stat-icon">
<img src="@/assets/img/zheke/ai-stats4.png" alt="留言数" />
</div> </div>
<div class="stat-info"> <div class="stat-label">留言数</div>
<div class="stat-value">{{ teacherStats.messageCount }}</div> <div class="stat-value">
<div class="stat-label">留言数</div> {{ teacherStats.messageCount }}<span class="unit"></span>
</div> </div>
</div> </div>
</div> </div>
@ -58,55 +67,62 @@ onMounted(() => {
<style scoped lang="scss"> <style scoped lang="scss">
.stats-container { .stats-container {
display: flex; display: flex;
flex-wrap: wrap; gap: 6px;
gap: 20px; height: 100%;
padding: 15px 0; margin-top: 10px;
} }
.stat-item { .stat-item {
display: flex; display: flex;
align-items: center; flex: 1;
width: 100%; flex-direction: column;
margin-bottom: 10px; align-items: flex-start;
border-radius: 10px;
padding: 9px 0 0 14px;
background-size: 100% 100%;
background-repeat: no-repeat;
&.blue-card {
background-image: url("@/assets/img/zheke/蓝色.png");
}
&.orange-card {
background-image: url("@/assets/img/zheke/橙色.png");
}
&.cyan-card {
background-image: url("@/assets/img/zheke/浅蓝色.png");
}
} }
.stat-icon { .stat-icon {
width: 50px; width: 40px;
height: 50px; height: 40px;
border-radius: 10px; border-radius: 10px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
margin-right: 15px; margin-bottom: 8px;
img { img {
width: 30px; width: 100%;
height: 30px; height: 100%;
}
&.blue-bg {
background-color: rgba(75, 150, 255, 0.1);
}
&.orange-bg {
background-color: rgba(250, 140, 22, 0.1);
}
&.cyan-bg {
background-color: rgba(24, 144, 255, 0.1);
} }
} }
.stat-info { .stat-value {
.stat-value { font-size: 24px;
font-size: 24px; font-weight: bold;
font-weight: bold; color: #fff;
color: #333;
} .unit {
.stat-label {
font-size: 14px; font-size: 14px;
color: #666; margin-left: 2px;
} }
} }
.stat-label {
font-size: 14px;
color: #fff;
opacity: 0.9;
}
</style> </style>

View File

@ -1,132 +0,0 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { teacherConsultStats } from "@/api";
interface TeacherStats {
consultCount: number;
replyCount: number;
messageCount: number;
[key: string]: number; //
}
//
const teacherStats = ref<TeacherStats>({
consultCount: 0,
replyCount: 0,
messageCount: 0,
});
//
const getTeacherStats = () => {
teacherConsultStats().then((res) => {
if (res.success) {
teacherStats.value = res.data;
}
});
};
onMounted(() => {
getTeacherStats();
});
</script>
<template>
<div class="stats-container">
<div class="stat-item blue-card">
<div class="stat-icon">
<img src="@/assets/img/zheke/ai-stats1.png" alt="咨询次数" />
</div>
<div class="stat-label">咨询次数</div>
<div class="stat-value">
{{ teacherStats.consultCount }}<span class="unit"></span>
</div>
</div>
<div class="stat-item orange-card">
<div class="stat-icon">
<img src="@/assets/img/zheke/ai-stats2.png" alt="回复数" />
</div>
<div class="stat-info">
<div class="stat-value">
{{ teacherStats.replyCount }}<span class="unit"></span>
</div>
<div class="stat-label">回复数</div>
</div>
</div>
<div class="stat-item cyan-card">
<div class="stat-icon">
<img src="@/assets/img/zheke/ai-stats4.png" alt="留言数" />
</div>
<div class="stat-info">
<div class="stat-value">
{{ teacherStats.messageCount }}<span class="unit"></span>
</div>
<div class="stat-label">留言数</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.stats-container {
display: flex;
gap: 6px;
height: 100%;
box-sizing: border-box;
margin-top: 10px;
}
.stat-item {
display: flex;
flex: 1;
flex-direction: column;
align-items: flex-start;
border-radius: 10px;
padding: 9px 0 0 14px;
background-size: 100% 100%;
background-repeat: no-repeat;
&.blue-card {
background-image: url("@/assets/img/zheke/蓝色.png");
}
&.orange-card {
background-image: url("@/assets/img/zheke/橙色.png");
}
&.cyan-card {
background-image: url("@/assets/img/zheke/浅蓝色.png");
}
}
.stat-icon {
width: 40px;
height: 40px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
img {
width: 100%;
height: 100%;
}
}
.stat-value {
font-size: 24px;
font-weight: bold;
color: #fff;
.unit {
font-size: 14px;
margin-left: 2px;
}
}
.stat-label {
font-size: 14px;
color: #fff;
opacity: 0.9;
}
</style>

View File

@ -4,7 +4,7 @@ import ItemWrap from "@/components/item-wrap";
const ContentHeader = defineAsyncComponent(() => import("./content-header.vue")); const ContentHeader = defineAsyncComponent(() => import("./content-header.vue"));
// //
const LeftTop = defineAsyncComponent(() => import("./components/LeftTop.vue")); const LeftTop = defineAsyncComponent(() => import("./LeftTop.vue"));
const LeftCenter = defineAsyncComponent(() => import("./LeftCenter.vue")); const LeftCenter = defineAsyncComponent(() => import("./LeftCenter.vue"));
const AverageDuration = defineAsyncComponent(() => import("./average-duration.vue")); const AverageDuration = defineAsyncComponent(() => import("./average-duration.vue"));
const LeftBottom = defineAsyncComponent(() => import("./components/LeftBottom.vue")); const LeftBottom = defineAsyncComponent(() => import("./components/LeftBottom.vue"));