You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
5.8 KiB
Vue

<template>
<div class="page-container">
<!-- 核心数据区 -->
<div class="stats-grid">
<DataCard
label="今日出勤率"
:value="stats.attendanceRate"
unit="%"
icon="UserFilled"
iconColor="#52c41a"
iconBg="#e8f9e0"
:trend="2.5"
@click="activeTab = 'manage'"
/>
<DataCard
label="教室平均使用率"
:value="stats.classroomUsage"
unit="%"
icon="OfficeBuilding"
iconColor="#1890ff"
iconBg="#e8f4ff"
:trend="-1.2"
@click="$router.push('/bigscreen')"
/>
<DataCard
label="异常行为预警数"
:value="stats.warningCount"
unit="次"
icon="WarningFilled"
iconColor="#f5222d"
iconBg="#fff1f0"
:trend="-15.0"
@click="$router.push('/behavior')"
/>
</div>
<!-- 快捷入口 -->
<div class="quick-actions">
<el-button type="primary" :icon="Plus" @click="activeTab = 'manage'">新增考勤任务</el-button>
<el-button :icon="Download" @click="handleExportAll"></el-button>
<el-button :icon="VideoCamera" @click="$router.push('/bigscreen')"></el-button>
</div>
<!-- 图表区 -->
<div class="charts-row">
<AttendanceTrendChart />
<ClassRanking />
</div>
<!-- 考勤记录区 -->
<div class="records-card">
<el-tabs v-model="activeTab">
<el-tab-pane label="考勤概览" name="overview">
<div class="records-header">
<h3>最近考勤记录</h3>
</div>
<el-table :data="recentRecords" stripe>
<el-table-column prop="courseName" label="课程名称" min-width="150" />
<el-table-column prop="classroom" label="教室" width="120" />
<el-table-column prop="time" label="上课时间" width="170" sortable />
<el-table-column prop="total" label="应到" width="70" align="center" />
<el-table-column prop="actual" label="实到" width="70" align="center" />
<el-table-column prop="absentRate" label="缺勤率" width="90" align="center">
<template #default="{ row }">
<el-tag :type="row.absentRate > 10 ? 'danger' : 'success'" size="small">
{{ row.absentRate }}%
</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="140" align="center">
<template #default="{ row }">
<el-button link type="primary" size="small" @click="showDetail(row)"></el-button>
<el-button link size="small" @click="handleExport(row)"></el-button>
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<el-tab-pane label="考勤管理" name="manage">
<AttendanceManage @showDetail="showDetail" />
</el-tab-pane>
</el-tabs>
</div>
<!-- 详情弹窗 -->
<AttendanceDetail v-model="detailVisible" :detail-data="currentDetail" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import DataCard from '@/components/DataCard.vue'
import AttendanceTrendChart from './components/AttendanceTrendChart.vue'
import ClassRanking from './components/ClassRanking.vue'
import AttendanceManage from './components/AttendanceManage.vue'
import AttendanceDetail from './components/AttendanceDetail.vue'
// ===== 数据卡片 =====
const stats = ref({ attendanceRate: 96.8, classroomUsage: 78.5, warningCount: 3 })
// ===== tabs =====
const activeTab = ref('overview')
// ===== 考勤概览 =====
const recentRecords = ref([
{ courseName: '高等数学A', teacher: '王教授', classroom: '301教室', time: '2024-06-01 08:00-09:40', total: 45, actual: 44, absentCount: 1, absentRate: 2.2 },
{ courseName: '大学英语B', teacher: '李老师', classroom: '205教室', time: '2024-06-01 10:00-11:40', total: 38, actual: 38, absentCount: 0, absentRate: 0 },
{ courseName: '计算机导论', teacher: '张教授', classroom: '102实验室', time: '2024-06-01 14:00-15:40', total: 52, actual: 49, absentCount: 3, absentRate: 5.8 },
{ courseName: '线性代数', teacher: '赵教授', classroom: '408教室', time: '2024-05-31 08:00-09:40', total: 40, actual: 38, absentCount: 2, absentRate: 5.0 },
{ courseName: '马克思原理', teacher: '刘老师', classroom: '大阶梯教室', time: '2024-05-31 10:00-11:40', total: 120, actual: 108, absentCount: 12, absentRate: 10.0 }
])
// ===== 详情弹窗 =====
const detailVisible = ref(false)
const currentDetail = ref({})
const showDetail = (row) => {
currentDetail.value = row
detailVisible.value = true
}
// ===== 导出 =====
const handleExport = (row) => ElMessage.success(`正在导出 ${row.courseName} 考勤明细...`)
const handleExportAll = () => ElMessage.info('正在生成考勤报表...')
</script>
<style lang="scss" scoped>
.quick-actions {
display: flex;
gap: 12px;
margin-bottom: 20px;
.el-button {
height: 40px;
border-radius: 8px;
font-size: 14px;
&:not(.el-button--primary) {
border-color: #d9d9d9;
color: #525252;
&:hover {
color: #52c41a;
border-color: #52c41a;
}
}
}
}
.charts-row {
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: 16px;
margin-bottom: 20px;
}
.records-card {
background: #fff;
border-radius: 8px;
padding: 8px 20px 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.records-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
h3 {
font-size: 16px;
font-weight: 600;
color: #262626;
}
}
@media (max-width: 1024px) {
.charts-row {
grid-template-columns: 1fr;
}
}
</style>