myClassPage.vue 11.4 KB
<!--
 * @Author: hookehuyr hookehuyr@gmail.com
 * @Date: 2025-01-20 10:00:00
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2025-06-19 16:46:06
 * @FilePath: /mlaj/src/views/teacher/myClassPage.vue
 * @Description: 我的班级页面
-->
<template>
  <div class="bg-gradient-to-br from-green-50 via-green-100/30 to-blue-50/30 min-h-screen">
    <!-- 用户信息卡片 -->
    <div>
      <div class="bg-white p-4">
        <div class="flex items-center mb-4">
          <van-image round width="3rem" height="3rem"
            :src="userInfo.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" fit="cover" class="mr-3" />
          <div class="flex-1">
            <h2 class="text-lg font-bold text-gray-800">{{ userInfo.name }}</h2>
            <div class="flex items-center mt-1">
              <van-icon name="clock-o" size="20" color="#10b981" class="mr-1" />
              <van-icon name="chat-o" size="20" color="#10b981" class="mr-1" />
              <van-icon name="comment-circle-o" size="20" color="#10b981" />
            </div>
          </div>
        </div>
      </div>
    </div>

    <!-- 筛选器 -->
    <div>
      <van-sticky>
        <van-dropdown-menu active-color="#10b981">
          <van-dropdown-item v-model="gradeFilter" :options="gradeOptions" @change="handleGradeChange" />
          <van-dropdown-item v-model="classFilter" :options="classOptions" @change="handleClassChange" />
          <van-dropdown-item v-model="courseFilter" :options="courseOptions" @change="handleCourseChange" />
        </van-dropdown-menu>
      </van-sticky>
    </div>

    <!-- 统计数据 -->
    <div>
      <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="attendanceRate" :rate="attendanceRate" :speed="100"
                :text="attendanceRate + '%'" stroke-width="50" color="#10b981" size="64" />
            </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="taskCompletionRate" :rate="taskCompletionRate" :speed="100"
                :text="taskCompletionRate + '%'" stroke-width="50" color="#3b82f6" size="64" />
            </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="learningProgress" :rate="learningProgress" :speed="100"
                :text="learningProgress + '%'" stroke-width="50" color="#f59e0b" size="64" />
            </div>
            <div class="text-sm text-gray-600">学习进度</div>
          </div>
        </van-col>
      </van-row>
    </div>

    <!-- 班级成员 -->
    <div class="">
      <div class="">
        <!-- 标题和搜索 -->
        <div class="p-4 border-b border-gray-100 bg-white">
          <div class="flex items-center justify-between mb-3">
            <h3 class="text-lg font-bold text-gray-800">班级成员 ({{ studentList.length }})</h3>
            <div @click="showSortPopup = true" class="flex items-center text-sm text-gray-600 cursor-pointer">
              <span>{{ sortFilter }}</span>
              <van-icon name="arrow-down" size="14" class="ml-1" />
            </div>
          </div>
          <van-search v-model="searchKeyword" placeholder="请搜索" @search="handleSearch" @input="handleSearch" />
        </div>

        <!-- 学生列表 -->
        <div class="p-4">
          <van-list v-model:loading="loading" :finished="finished" finished-text="没有更多了" @load="onLoad">
            <div v-for="student in filteredStudentList" :key="student.id"
              class="flex items-center justify-between py-3 border-gray-50 bg-white rounded-xl p-4 text-center shadow-sm mb-4"
              @click="handleStudentClick(student)">
              <div class="flex items-center flex-1">
                <van-image round width="2.5rem" height="2.5rem"
                  :src="student.avatar || 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'" fit="cover" class="mr-3" />
                <div class="flex-1">
                  <div class="flex items-center">
                    <span class="font-medium text-gray-800 mr-2">{{ student.name }}</span>
                    <van-icon v-if="student.gender === 'male'" name="friends-o" color="#3b82f6" size="14" />
                    <van-icon v-else name="like-o" color="#ec4899" size="14" />
                  </div>
                  <div class="text-sm text-gray-500" style="text-align: left;">{{ student.className }}</div>
                </div>
              </div>
              <div class="text-right">
                <div class="flex items-center text-sm text-gray-500 mb-1">
                  <van-icon name="phone-o" size="12" class="mr-1" />
                  <span>{{ formatPhone(student.phone) }}</span>
                </div>
                <div class="text-xs text-gray-400">{{ student.lastActiveTime }}</div>
              </div>
              <van-icon name="arrow" color="#d1d5db" size="16" class="ml-2" />
            </div>
          </van-list>
        </div>
      </div>
    </div>

    <!-- 排序弹窗 -->
    <van-popup v-model:show="showSortPopup" 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 sortOptions"
            :key="option.value"
            :title="option.text"
            clickable
            @click="onSortSelect(option)"
            :border="false"
            :class="{ 'text-green-600': sortFilter === option.value }"
          >
            <template #right-icon>
              <van-icon v-if="sortFilter === option.value" name="success" color="#10b981" />
            </template>
          </van-cell>
        </van-cell-group>
        <div class="mt-4">
          <van-button block @click="showSortPopup = false">取消</van-button>
        </div>
      </div>
    </van-popup>
  </div>
</template>

<script setup>
import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import AppLayout from '@/layouts/AppLayout.vue'

const router = useRouter()

// 用户信息
const userInfo = ref({
  name: '我的班级',
  avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
})

// 筛选器数据
const gradeFilter = ref('全部年级')
const classFilter = ref('全部班级')
const courseFilter = ref('全部课程')
const sortFilter = ref('按活跃度')
const searchKeyword = ref('')
const showSortPopup = ref(false)

// 筛选器选项
const gradeOptions = ref([
  { text: '全部年级', value: '全部年级' },
  { text: '高一年级', value: '高一年级' },
  { text: '高二年级', value: '高二年级' },
  { text: '高三年级', value: '高三年级' }
])

const classOptions = ref([
  { text: '全部班级', value: '全部班级' },
  { text: '高一(1)班', value: '高一(1)班' },
  { text: '高一(2)班', value: '高一(2)班' },
  { text: '高一(3)班', value: '高一(3)班' }
])

const courseOptions = ref([
  { text: '全部课程', value: '全部课程' },
  { text: '语文', value: '语文' },
  { text: '数学', value: '数学' },
  { text: '英语', value: '英语' }
])

const sortOptions = ref([
  { text: '按活跃度', value: '按活跃度' },
  { text: '按姓名', value: '按姓名' },
  { text: '按成绩', value: '按成绩' }
])

// 统计数据
const attendanceRate = ref(85)
const taskCompletionRate = ref(76)
const learningProgress = ref(92)

// 学生列表
const studentList = ref([
  {
    id: 1,
    name: '张明',
    gender: 'male',
    className: '高一(3)班',
    phone: '13812345678',
    lastActiveTime: '5分钟前活跃',
    avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
  },
  {
    id: 2,
    name: '李华',
    gender: 'female',
    className: '高一(3)班',
    phone: '13987654321',
    lastActiveTime: '10分钟前活跃',
    avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
  },
  {
    id: 3,
    name: '王强',
    gender: 'male',
    className: '高一(2)班',
    phone: '13512349876',
    lastActiveTime: '15分钟前活跃',
    avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
  },
  {
    id: 4,
    name: '赵敏',
    gender: 'female',
    className: '高一(1)班',
    phone: '13643214321',
    lastActiveTime: '30分钟前活跃',
    avatar: 'https://cdn.ipadbiz.cn/mlaj/images/icon_1.jpeg'
  }
])

// 列表加载状态
const loading = ref(false)
const finished = ref(false)

/**
 * 过滤后的学生列表
 */
const filteredStudentList = computed(() => {
  let filtered = studentList.value

  // 按班级筛选
  if (classFilter.value !== '全部班级') {
    filtered = filtered.filter(student => student.className === classFilter.value)
  }

  // 按搜索关键词筛选
  if (searchKeyword.value) {
    filtered = filtered.filter(student =>
      student.name.toLowerCase().includes(searchKeyword.value.toLowerCase())
    )
  }

  // 排序
  if (sortFilter.value === '按姓名') {
    filtered.sort((a, b) => a.name.localeCompare(b.name))
  }

  return filtered
})

/**
 * 格式化手机号
 * @param {string} phone - 手机号
 * @returns {string} 格式化后的手机号
 */
const formatPhone = (phone) => {
  if (!phone) return ''
  return phone.replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3')
}

/**
 * 处理年级筛选变化
 * @param {string} value - 选中的年级
 */
const handleGradeChange = (value) => {
  console.log('年级筛选:', value)
  // 这里可以根据年级筛选更新班级选项
}

/**
 * 处理班级筛选变化
 * @param {string} value - 选中的班级
 */
const handleClassChange = (value) => {
  console.log('班级筛选:', value)
}

/**
 * 处理课程筛选变化
 * @param {string} value - 选中的课程
 */
const handleCourseChange = (value) => {
  console.log('课程筛选:', value)
}

/**
 * 处理排序变化
 * @param {string} value - 选中的排序方式
 */
const handleSortChange = (value) => {
  console.log('排序变化:', value)
}

/**
 * 处理排序选择
 * @param {Object} option - 选中的排序选项
 */
const onSortSelect = (option) => {
  sortFilter.value = option.value
  showSortPopup.value = false
  handleSortChange(option.value)
}

/**
 * 处理搜索
 * @param {string} value - 搜索关键词
 */
const handleSearch = (value) => {
  console.log('搜索:', value)
}

/**
 * 处理学生点击
 * @param {Object} student - 学生信息
 */
const handleStudentClick = (student) => {
  console.log('点击学生:', student)
  // 这里可以跳转到学生详情页
}

/**
 * 加载更多数据
 */
const onLoad = () => {
  setTimeout(() => {
    loading.value = false
    finished.value = true
  }, 1000)
}

/**
 * 组件挂载时初始化数据
 */
onMounted(() => {
  // 这里可以调用API获取实际数据
  console.log('我的班级页面已加载')
})
</script>

<style scoped>
/* 自定义样式 */
.van-dropdown-menu {
  background-color: white;
  border-radius: 0.75rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
}

.van-circle {
  font-size: 12px;
  font-weight: bold;
}

.van-search {
  background-color: #f9fafb;
  border-radius: 0.5rem;
}

.van-list {
  min-height: 200px;
}
</style>