hookehuyr

refactor(studentPage): 重构学生详情页面布局和样式

- 使用van-config-provider包裹整个页面以支持主题变量
- 调整统计图表stroke-width为70以增强可视性
- 使用van-sticky优化标签页的粘性布局
- 添加返回顶部按钮并设置样式
- 统一调整时间显示字体大小
- 优化状态图标显示效果
......@@ -2,118 +2,110 @@
* @Author: hookehuyr hookehuyr@gmail.com
* @Date: 2025-06-19 17:12:19
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2025-06-19 21:32:23
* @LastEditTime: 2025-06-19 22:39:26
* @FilePath: /mlaj/src/views/teacher/studentPage.vue
* @Description: 学生详情页面
-->
<template>
<div class="bg-gradient-to-br from-green-50 via-green-100/30 to-blue-50/30 min-h-screen">
<!-- 学生基本信息 -->
<div class="bg-white p-4">
<div class="flex items-start mb-4">
<van-image round width="4rem" height="4rem"
:src="studentInfo.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" fit="cover" class="mr-4" />
<div class="flex-1">
<div class="flex items-center mb-2">
<h2 class="text-xl font-bold text-gray-800 mr-2">{{ studentInfo.name }}</h2>
<van-icon v-if="studentInfo.gender === 'male'" name="friends-o" color="#3b82f6" size="16" />
<van-icon v-else name="like-o" color="#ec4899" size="16" />
</div>
<div class="flex items-center mb-2">
<van-icon name="chat-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600 mr-4">{{ studentInfo.className }}</span>
<van-icon name="phone-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600">{{ formatPhone(studentInfo.phone) }}</span>
</div>
<!-- 标签 -->
<div class="flex flex-wrap gap-2">
<van-tag v-for="tag in studentInfo.tags" :key="tag" type="success" size="small">
{{ tag }}
</van-tag>
<van-config-provider :theme-vars="themeVars">
<div class="bg-gradient-to-br from-green-50 via-green-100/30 to-blue-50/30 min-h-screen">
<!-- 学生基本信息 -->
<div class="bg-white p-4">
<div class="flex items-start mb-4">
<van-image round width="4rem" height="4rem"
:src="studentInfo.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" fit="cover" class="mr-4" />
<div class="flex-1">
<div class="flex items-center mb-2">
<h2 class="text-xl font-bold text-gray-800 mr-2">{{ studentInfo.name }}</h2>
<van-icon v-if="studentInfo.gender === 'male'" name="friends-o" color="#3b82f6" size="16" />
<van-icon v-else name="like-o" color="#ec4899" size="16" />
</div>
<div class="flex items-center mb-2">
<van-icon name="chat-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600 mr-4">{{ studentInfo.className }}</span>
<van-icon name="phone-o" size="16" color="#10b981" class="mr-1" />
<span class="text-sm text-gray-600">{{ formatPhone(studentInfo.phone) }}</span>
</div>
<!-- 标签 -->
<div class="flex flex-wrap gap-2">
<van-tag v-for="tag in studentInfo.tags" :key="tag" type="success" size="small">
{{ tag }}
</van-tag>
</div>
</div>
</div>
</div>
</div>
<!-- 所学课程 -->
<div class="bg-white mt-2 p-4">
<div class="flex items-center mb-3">
<van-icon name="bookmark-o" size="16" color="#10b981" class="mr-2" />
<span class="text-sm font-medium text-gray-700">所学课程</span>
</div>
<div class="flex flex-wrap gap-2">
<van-tag v-for="course in studentInfo.courses" :key="course" type="primary" size="small">
{{ course }}
</van-tag>
<!-- 所学课程 -->
<div class="bg-white mt-2 p-4">
<div class="flex items-center mb-3">
<van-icon name="bookmark-o" size="16" color="#10b981" class="mr-2" />
<span class="text-sm font-medium text-gray-700">所学课程</span>
</div>
<div class="flex flex-wrap gap-2">
<van-tag v-for="course in studentInfo.courses" :key="course" type="primary" size="small">
{{ course }}
</van-tag>
</div>
</div>
</div>
<!-- 统计数据 -->
<div class="mt-2">
<van-row>
<!-- 出勤率 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.attendanceRate" :rate="studentStats.attendanceRate"
:speed="100" :text="studentStats.attendanceRate + '%'" stroke-width="50" color="#10b981" size="64" />
<!-- 统计数据 -->
<div class="mt-2">
<van-row>
<!-- 出勤率 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.attendanceRate" :rate="studentStats.attendanceRate"
:speed="100" :text="studentStats.attendanceRate + '%'" stroke-width="70" color="#10b981" size="64" />
</div>
<div class="text-sm text-gray-600">出勤率</div>
</div>
<div class="text-sm text-gray-600">出勤率</div>
</div>
</van-col>
<!-- 作业完成率 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.homeworkRate" :rate="studentStats.homeworkRate"
:speed="100" :text="studentStats.homeworkRate + '%'" stroke-width="50" color="#3b82f6" size="64" />
</van-col>
<!-- 作业完成率 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.homeworkRate" :rate="studentStats.homeworkRate"
:speed="100" :text="studentStats.homeworkRate + '%'" stroke-width="70" color="#3b82f6" size="64" />
</div>
<div class="text-sm text-gray-600">作业完成率</div>
</div>
<div class="text-sm text-gray-600">作业完成率</div>
</div>
</van-col>
<!-- 测验成绩 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.testScore" :rate="studentStats.testScore" :speed="100"
:text="studentStats.testScore + '%'" stroke-width="50" color="#f59e0b" size="64" />
</van-col>
<!-- 测验成绩 -->
<van-col span="8">
<div class="bg-white p-4 text-center">
<div class="relative w-16 h-16 mx-auto mb-2">
<van-circle v-model:current-rate="studentStats.testScore" :rate="studentStats.testScore" :speed="100"
:text="studentStats.testScore + '%'" stroke-width="70" color="#f59e0b" size="64" />
</div>
<div class="text-sm text-gray-600">测验成绩</div>
</div>
<div class="text-sm text-gray-600">测验成绩</div>
</div>
</van-col>
</van-row>
</div>
</van-col>
</van-row>
</div>
<!-- 功能按钮 -->
<div class="mt-2 p-4">
<!-- 状态筛选 -->
<div class="flex items-center justify-end mb-4">
<div @click="showStatusPopup = true" class="flex items-center text-sm text-gray-600 cursor-pointer">
<span>{{ statusFilter }}</span>
<van-icon name="arrow-down" size="14" class="ml-1" />
<!-- 功能按钮 -->
<div class="mt-2 p-4">
<!-- 状态筛选 -->
<div class="flex items-center justify-end mb-4">
<div @click="showStatusPopup = true" class="flex items-center text-sm text-gray-600 cursor-pointer">
<span>{{ statusFilter }}</span>
<van-icon name="arrow-down" size="14" class="ml-1" />
</div>
</div>
</div>
<!-- <div class="flex items-center justify-between mb-3">
<div @click="activeTab = 'homework'"
:class="['flex-1 text-center py-2 text-sm font-medium cursor-pointer', activeTab === 'homework' ? 'text-green-600 border-b-2 border-green-600' : 'text-gray-500']">
作业记录
</div>
<div @click="activeTab = 'evaluation'"
:class="['flex-1 text-center py-2 text-sm font-medium cursor-pointer', activeTab === 'evaluation' ? 'text-green-600 border-b-2 border-green-600' : 'text-gray-500']">
班主任点评
</div>
<div @click="activeTab = 'statistics'"
:class="['flex-1 text-center py-2 text-sm font-medium cursor-pointer', activeTab === 'statistics' ? 'text-green-600 border-b-2 border-green-600' : 'text-gray-500']">
打卡统计
<!-- 使用van-sticky包裹van-tabs实现粘性布局 -->
<van-sticky :offset-top="0">
<div class="bg-white">
<van-tabs v-model:active="activeTab" color="#10b981" animated swipeable @change="handleTabChange">
<van-tab title="作业记录" name="homework"></van-tab>
<van-tab title="班主任点评" name="evaluation"></van-tab>
<van-tab title="打卡统计" name="statistics"></van-tab>
</van-tabs>
</div>
</div> -->
<div class="px-4 py-3 bg-white" style="position: relative;">
<van-tabs v-model:active="activeTab" color="#10b981" sticky animated swipeable @change="handleTabChange">
<van-tab title="作业记录" name="homework"></van-tab>
<van-tab title="班主任点评" name="evaluation"></van-tab>
<van-tab title="打卡统计" name="statistics"></van-tab>
</van-tabs>
</div>
</van-sticky>
<!-- 记录列表 -->
<van-list v-show="activeTab === 'statistics'" v-model:loading="recordLoading" :finished="recordFinished"
......@@ -123,12 +115,12 @@
<div class="flex items-center flex-1">
<div class="mr-4">
<div style="display: flex; justify-content: center;">
<van-icon name="calendar-o" size="16" color="#6b7280" class="mb-1" /> &nbsp;
<span class="text-xs text-gray-500">{{ record.date }}</span>
<van-icon name="calendar-o" size="18" color="#6b7280" class="mb-1" /> &nbsp;
<span class="text-sm text-gray-500">{{ record.date }}</span>
</div>
<div style="display: flex; ">
<van-icon name="clock-o" size="16" color="#6b7280" class="mb-1" /> &nbsp;
<span class="text-xs text-gray-500">{{ record.time }}</span>
<van-icon name="clock-o" size="18" color="#6b7280" class="mb-1" /> &nbsp;
<span class="text-sm text-gray-500">{{ record.time }}</span>
</div>
</div>
</div>
......@@ -137,7 +129,7 @@
<span v-else-if="record.status === '迟到'" class="text-orange-500 text-sm mr-2">{{ record.status }}</span>
<span v-else class="text-red-500 text-sm mr-2">{{ record.status }}</span>
<van-icon v-if="record.status === '正常'" name="success" color="#10b981" size="16" />
<van-icon v-if="record.status === '正常'" name="passed" color="#10b981" size="16" />
<van-icon v-else-if="record.status === '迟到'" name="warning-o" color="#f59e0b" size="16" />
<van-icon v-else name="close" color="#ef4444" size="16" />
</div>
......@@ -214,27 +206,29 @@
</div>
</div>
</van-list>
</div>
<!-- 状态筛选弹窗 -->
<van-popup v-model:show="showStatusPopup" position="bottom" round>
<div class="p-4">
<div class="text-center text-lg font-bold mb-4">选择状态</div>
<van-cell-group>
<van-cell v-for="option in statusOptions" :key="option.value" :title="option.text" clickable
@click="onStatusSelect(option)" :border="false"
:class="{ 'text-green-600': statusFilter === option.value }">
<template #right-icon>
<van-icon v-if="statusFilter === option.value" name="success" color="#10b981" />
</template>
</van-cell>
</van-cell-group>
<div class="mt-4">
<van-button block @click="showStatusPopup = false">取消</van-button>
<van-back-top right="5vw" bottom="10vh" />
<div style="height: 5rem;"></div>
<!-- 状态筛选弹窗 -->
<van-popup v-model:show="showStatusPopup" position="bottom" round>
<div class="p-4">
<div class="text-center text-lg font-bold mb-4">选择状态</div>
<van-cell-group>
<van-cell v-for="option in statusOptions" :key="option.value" :title="option.text" clickable
@click="onStatusSelect(option)" :border="false"
:class="{ 'text-green-600': statusFilter === option.value }">
<template #right-icon>
<van-icon v-if="statusFilter === option.value" name="success" color="#10b981" />
</template>
</van-cell>
</van-cell-group>
<div class="mt-4">
<van-button block @click="showStatusPopup = false">取消</van-button>
</div>
</div>
</div>
</van-popup>
</div>
</van-popup>
</div>
</van-config-provider>
</template>
<script setup>
......@@ -253,6 +247,10 @@ const router = useRouter()
const route = useRoute()
useTitle(route.meta.title);
const themeVars = reactive({
buttonNormalFontSize: '1rem',
})
// 学生信息
const studentInfo = ref({
id: 1,
......@@ -685,7 +683,11 @@ const formatData = (data) => {
}
</script>
<style scoped lang="less">
<style lang="less">
.van-back-top {
background-color: #4caf50;
}
/* 自定义样式 */
.van-circle {
font-size: 12px;
......