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">
$item-title-height: 33px;
$item_title_content-height: calc(100% - 33px);
$item_title_content-height: calc(100% - 33px - 20px);
.item_wrap {
background: #fff;

View File

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