|
|
@@ -1,17 +1,1258 @@
|
|
|
<template>
|
|
|
- <div>
|
|
|
- <div class="title">
|
|
|
- 分析面板
|
|
|
- </div>
|
|
|
+ <div class="teacher-dashboard" v-show="showDataBoard">
|
|
|
+ <!-- 顶部导航栏 -->
|
|
|
+ <nav class="nav-bar">
|
|
|
+ <div class="nav-container">
|
|
|
+ <!-- 左侧:返回按钮 + 班级选择 -->
|
|
|
+ <div class="nav-left">
|
|
|
+ <button class="nav-back-btn" type="button" aria-label="返回" @click="handleBack">
|
|
|
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M15 18l-6-6 6-6" />
|
|
|
+ </svg>
|
|
|
+ </button>
|
|
|
+ <span class="nav-title">班级</span>
|
|
|
+ <el-select
|
|
|
+ v-model="selectedClass"
|
|
|
+ size="mini"
|
|
|
+ class="nav-class-select"
|
|
|
+ @change="handleClassChange"
|
|
|
+ >
|
|
|
+ <el-option
|
|
|
+ v-for="cls in classList"
|
|
|
+ :key="cls"
|
|
|
+ :label="cls"
|
|
|
+ :value="cls"
|
|
|
+ />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 右侧:操作按钮 -->
|
|
|
+ <div class="nav-right">
|
|
|
+ <button type="button" class="nav-btn nav-btn-report" @click="handleStudentReport" v-show="false">学生报告</button>
|
|
|
+ <button type="button" class="nav-btn nav-btn-export" @click="handleExport" v-show="false">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3" />
|
|
|
+ </svg>
|
|
|
+ <span>导出</span>
|
|
|
+ </button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </nav>
|
|
|
+
|
|
|
+ <main class="main-content">
|
|
|
+ <!-- 一、课程概况 & KPI -->
|
|
|
+ <section class="overview-card">
|
|
|
+ <div class="overview-info">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-accent"></div>
|
|
|
+ <h2 class="section-heading">课程概况</h2>
|
|
|
+ </div>
|
|
|
+ <div class="course-info-block">
|
|
|
+ <h1 class="course-name">{{ courseInfo.title }}</h1>
|
|
|
+ <div class="course-meta-row">
|
|
|
+ <div class="course-meta-item">
|
|
|
+ <svg class="meta-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M22 10L12 5 2 10l10 5 10-5z" />
|
|
|
+ <path d="M6 12v5c0 1 2.5 3 6 3s6-2 6-3v-5" />
|
|
|
+ </svg>
|
|
|
+ <span class="meta-label">年级:</span>{{ courseInfo.grade }}
|
|
|
+ </div>
|
|
|
+ <span class="meta-divider">|</span>
|
|
|
+ <div class="course-meta-item">
|
|
|
+ <svg class="meta-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M4 19.5A2.5 2.5 0 016.5 17H20M6.5 2H20v20H6.5A2.5 2.5 0 014 19.5v-15A2.5 2.5 0 016.5 2z" />
|
|
|
+ </svg>
|
|
|
+ <span class="meta-label">学科:</span>{{ courseInfo.subject }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="course-extra-row">
|
|
|
+ <div class="course-extra-item">
|
|
|
+ <svg class="extra-icon" width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75M13 8a4 4 0 11-8 0 4 4 0 018 0z" />
|
|
|
+ </svg>
|
|
|
+ <span>班级: {{ courseInfo.class }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="course-extra-item">
|
|
|
+ <svg class="extra-icon" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <circle cx="12" cy="12" r="10" />
|
|
|
+ <path d="M12 6v6l4 2" />
|
|
|
+ </svg>
|
|
|
+ <span>上课时间: {{ courseInfo.classTime }}</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="kpi-row">
|
|
|
+ <div v-for="(kpi, idx) in kpis" :key="idx" class="kpi-card">
|
|
|
+ <div class="kpi-value" :style="{ color: kpi.color }">
|
|
|
+ {{ kpi.value }}<span v-if="kpi.suffix" class="kpi-suffix">{{ kpi.suffix }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="kpi-label">{{ kpi.label }}</div>
|
|
|
+ <div class="kpi-sub">{{ kpi.sub }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <!-- 二、课程详情 & AI 诊断报告 -->
|
|
|
+ <section class="detail-grid" v-show="false">
|
|
|
+ <!-- 课程概述 -->
|
|
|
+ <div class="detail-card course-detail-card">
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="card-icon brand-soft">
|
|
|
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2zM22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z" />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <h2 class="card-title">课程概述</h2>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <div class="paragraph">
|
|
|
+ <span class="strong">课程主题:</span>{{ courseSummary.theme }}
|
|
|
+ </div>
|
|
|
+ <div class="paragraph">
|
|
|
+ <span class="strong">教学目标:</span>
|
|
|
+ <ul class="bullet-list">
|
|
|
+ <li v-for="(goal, i) in courseSummary.objectives" :key="i">{{ goal }}</li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ <div class="paragraph">
|
|
|
+ <span class="strong">主要环节:</span>{{ courseSummary.segments }}
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- AI 教学智能诊断报告 -->
|
|
|
+ <div class="detail-card ai-report-card">
|
|
|
+ <div class="card-header relative-z">
|
|
|
+ <div class="card-icon yellow-soft">
|
|
|
+ <svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor">
|
|
|
+ <path d="M12 2l1.8 6L20 9.8l-6 1.8L12 18l-1.8-6.4L4 9.8l6.2-1.8z" />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ <h2 class="card-title">AI 教学智能诊断报告</h2>
|
|
|
+ </div>
|
|
|
+ <ul class="ai-report-list relative-z">
|
|
|
+ <li v-for="(item, i) in aiReport" :key="i" class="ai-report-item">
|
|
|
+ <svg
|
|
|
+ class="ai-icon"
|
|
|
+ :class="item.iconClass"
|
|
|
+ width="16"
|
|
|
+ height="16"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ fill="currentColor"
|
|
|
+ >
|
|
|
+ <path :d="item.iconPath" />
|
|
|
+ </svg>
|
|
|
+ <span><strong class="strong">{{ item.title }}:</strong>{{ item.content }}</span>
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <!-- 三、任务概况明细 -->
|
|
|
+ <section id="task-overview" class="task-section">
|
|
|
+ <div class="task-card">
|
|
|
+ <div class="task-card-header">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-accent"></div>
|
|
|
+ <h2 class="section-heading">任务概况明细</h2>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="table-scroll">
|
|
|
+ <table class="custom-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th class="th-num">#</th>
|
|
|
+ <th>任务与工具</th>
|
|
|
+ <th class="th-center">提交率</th>
|
|
|
+ <th class="th-center">正确率</th>
|
|
|
+ <th class="th-center">互动次数</th>
|
|
|
+ <!-- <th class="th-center">平均用时</th> -->
|
|
|
+ <th>AI 智能洞察</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr v-for="task in tasks" :key="task.id" class="table-row">
|
|
|
+ <td class="td-num">{{ task.id }}</td>
|
|
|
+ <td>
|
|
|
+ <div class="task-name">{{ task.name }}</div>
|
|
|
+ <div class="task-type">
|
|
|
+ <svg
|
|
|
+ class="task-type-icon"
|
|
|
+ :style="{ color: task.typeIconColor }"
|
|
|
+ width="14"
|
|
|
+ height="14"
|
|
|
+ viewBox="0 0 24 24"
|
|
|
+ fill="currentColor"
|
|
|
+ >
|
|
|
+ <path :d="task.typeIconPath" />
|
|
|
+ </svg>
|
|
|
+ {{ task.type }}
|
|
|
+ <span v-if="task.aiRounds" class="ai-rounds-badge">
|
|
|
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
|
|
|
+ <path d="M12 2l1.8 6L20 9.8l-6 1.8L12 18l-1.8-6.4L4 9.8l6.2-1.8z" />
|
|
|
+ </svg>
|
|
|
+ {{ task.aiRounds }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td class="td-center td-extrabold">{{ task.submitRate }}</td>
|
|
|
+ <td class="td-center">
|
|
|
+ <span
|
|
|
+ v-if="task.accuracy !== '—'"
|
|
|
+ :class="['accuracy-badge', task.accuracyTone]"
|
|
|
+ >{{ task.accuracy }}</span>
|
|
|
+ <span v-else class="accuracy-dash">{{ task.accuracy }}</span>
|
|
|
+ </td>
|
|
|
+ <td class="td-center td-bold-700">{{ task.interactions }}</td>
|
|
|
+ <!-- <td class="td-center td-medium">{{ task.avgTime }}</td> -->
|
|
|
+ <td class="td-insight">
|
|
|
+ <div class="insight-text">
|
|
|
+ {{ task.insightPrefix }}<strong v-if="task.insightStrong" class="insight-strong">{{ task.insightStrong }}</strong>{{ task.insightSuffix }}
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+
|
|
|
+ <!-- 四、学生详情矩阵 -->
|
|
|
+ <section id="student-details" class="student-section">
|
|
|
+ <div class="student-grid">
|
|
|
+ <!-- 参与度分层 -->
|
|
|
+ <div class="chart-card">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-accent"></div>
|
|
|
+ <h3 class="section-heading">参与度分层</h3>
|
|
|
+ </div>
|
|
|
+ <div class="chart-wrapper">
|
|
|
+ <div ref="performanceChart" class="echart-canvas"></div>
|
|
|
+ <div class="chart-center">
|
|
|
+ <span class="chart-center-value">92%</span>
|
|
|
+ <span class="chart-center-label">均参与度</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 学生详情表 -->
|
|
|
+ <div class="student-table-card">
|
|
|
+ <div class="student-table-header">
|
|
|
+ <div class="section-title-row">
|
|
|
+ <div class="section-accent"></div>
|
|
|
+ <h3 class="section-heading">学生详情矩阵</h3>
|
|
|
+ </div>
|
|
|
+ <el-input
|
|
|
+ v-model="searchKeyword"
|
|
|
+ placeholder="搜索学生..."
|
|
|
+ size="small"
|
|
|
+ class="search-input"
|
|
|
+ clearable
|
|
|
+ >
|
|
|
+ <i slot="prefix" class="search-icon-slot">
|
|
|
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <circle cx="11" cy="11" r="8" />
|
|
|
+ <path d="M21 21l-4.35-4.35" />
|
|
|
+ </svg>
|
|
|
+ </i>
|
|
|
+ </el-input>
|
|
|
+ </div>
|
|
|
+ <div class="student-table-scroll">
|
|
|
+ <table class="custom-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th class="th-num">#</th>
|
|
|
+ <th>姓名</th>
|
|
|
+ <th>
|
|
|
+ <div class="th-sortable">
|
|
|
+ 任务完成度
|
|
|
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M3 4h18l-7 8v6l-4 2v-8z" />
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ </th>
|
|
|
+ <th class="th-center">综合正确率</th>
|
|
|
+ <th class="th-center">AI对话轮次</th>
|
|
|
+ <th class="th-center">点赞/被赞</th>
|
|
|
+ <!-- <th class="th-center">操作</th> -->
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ <tr
|
|
|
+ v-for="student in filteredStudents"
|
|
|
+ :key="student.id"
|
|
|
+ :class="['table-row', { 'attention-row': student.attention }]"
|
|
|
+ >
|
|
|
+ <td :class="['td-num', { 'attention-num-color': student.attention }]">{{ student.id }}</td>
|
|
|
+ <td>
|
|
|
+ <div class="student-name-cell">
|
|
|
+ {{ student.name }}
|
|
|
+ <span v-if="student.attention" class="attention-badge">
|
|
|
+ <svg width="10" height="10" viewBox="0 0 24 24" fill="currentColor">
|
|
|
+ <path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z M12 9v4M12 17h.01" />
|
|
|
+ </svg>
|
|
|
+ 关注
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td>
|
|
|
+ <div class="progress-wrapper">
|
|
|
+ <div class="progress-bar" :class="{ 'progress-bar-amber-bg': student.attention }">
|
|
|
+ <div class="progress-fill" :class="{ 'fill-amber': student.attention }" style="width: 100%"></div>
|
|
|
+ </div>
|
|
|
+ <span class="progress-text">{{ student.tasksDone }}/{{ student.tasksTotal }}</span>
|
|
|
+ </div>
|
|
|
+ </td>
|
|
|
+ <td :class="['td-center', student.attention ? 'td-correct-red' : 'td-extrabold']">{{ student.correctRate }}</td>
|
|
|
+ <td class="td-center td-bold-700">{{ student.aiRounds }} 轮</td>
|
|
|
+ <td class="td-center td-medium">{{ student.likes }}</td>
|
|
|
+ <!-- <td class="td-center">
|
|
|
+ <button class="report-btn" type="button" @click="handleStudentReportRow(student)">
|
|
|
+ <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
|
+ <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
|
|
|
+ <path d="M14 2v6h6" />
|
|
|
+ <path d="M16 13H8M16 17H8M10 9H8" />
|
|
|
+ </svg>
|
|
|
+ 报告
|
|
|
+ </button>
|
|
|
+ </td> -->
|
|
|
+ </tr>
|
|
|
+ <tr v-if="filteredStudents.length === 0">
|
|
|
+ <td colspan="7" class="empty-row">无匹配学生</td>
|
|
|
+ </tr>
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </section>
|
|
|
+ </main>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
export default {
|
|
|
+ name: 'TeacherDataBoard',
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ selectedClass: '测试1班',
|
|
|
+ classList: ['测试1班', '高一(3)班'],
|
|
|
+ searchKeyword: '',
|
|
|
+ chartInstance: null,
|
|
|
+ courseInfo: {
|
|
|
+ title: '人工智能普及课程',
|
|
|
+ grade: '高中一年级',
|
|
|
+ subject: '信息技术',
|
|
|
+ class: '一班',
|
|
|
+ classTime: '2026-05-13 17:08'
|
|
|
+ },
|
|
|
+ kpis: [
|
|
|
+ { value: '90%', suffix: '', label: '出勤率', sub: '(45/50人)', color: '#F97316' },
|
|
|
+ { value: '89%', suffix: '', label: '平均提交率', sub: '(313次提交)', color: '#10B981' },
|
|
|
+ { value: '64%', suffix: '', label: '平均正确率', sub: '(最高94%·最低25%)', color: '#10B981' },
|
|
|
+ { value: '4', suffix: '轮', label: 'AI 轮次', sub: '(最多7·最少0)', color: '#3B82F6' },
|
|
|
+ { value: '47', suffix: '', label: '总互动量', sub: '(总点赞数)', color: '#EC4899' }
|
|
|
+ ],
|
|
|
+ courseSummary: {
|
|
|
+ theme: '探索人工智能的起源、核心技术与未来趋势,建立对AI基础概念的准确认知。',
|
|
|
+ objectives: [
|
|
|
+ '帮助学生建立对AI应用场景的认知,区分强/弱AI。',
|
|
|
+ '掌握机器学习的核心三要素(数据、算力、算法/模型)。',
|
|
|
+ '结合实际场景,培养学生对前沿科技的初步思考与创造力。'
|
|
|
+ ],
|
|
|
+ segments: '概念导入(单选) → 场景辨析(排序) → 核心原理解析(问答/填空) → 创意实践(拍照上传)。'
|
|
|
+ },
|
|
|
+ aiReport: [
|
|
|
+ {
|
|
|
+ iconPath: 'M12 2a10 10 0 100 20 10 10 0 000-20zm-3 14l-5-5 1.4-1.4L9 13.2l7.6-7.6L18 7l-9 9z',
|
|
|
+ iconClass: 'icon-green',
|
|
|
+ title: '课堂整体活跃度高',
|
|
|
+ content: '本节课整体互动氛围优异,学生出勤率达 90%(45/50人),平均提交率保持在 82%,说明多模态的互动环节设计有效吸引了绝大部分学生的注意力。'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ iconPath: 'M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z M12 9v4M12 17h.01',
|
|
|
+ iconClass: 'icon-red',
|
|
|
+ title: '部分核心概念掌握薄弱',
|
|
|
+ content: '在知识点巩固环节,关于“机器学习三个要素”的填空题正确率仅为 58%,“模型”一词易被大量学生漏填或混淆,建议在后续复习中增加针对性讲解。'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ iconPath: 'M12 2a10 10 0 100 20 10 10 0 000-20zm-1 5h2v2h-2V7zm0 4h2v6h-2v-6z',
|
|
|
+ iconClass: 'icon-brand',
|
|
|
+ title: '需关注后进生参与质量',
|
|
|
+ content: '班级尾部学生存在互动吃力现象,例如杨浩宇同学虽然完成了所有随堂任务,但整体正确率仅为 76%,建议利用课后 AI 助教功能对其进行个性化辅导。'
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ tasks: [
|
|
|
+ {
|
|
|
+ id: 1,
|
|
|
+ name: '以下哪项不属于 AI 应用领域',
|
|
|
+ type: '单选题',
|
|
|
+ typeIconPath: 'M12 2a10 10 0 100 20 10 10 0 000-20zm-3 14l-5-5 1.4-1.4L9 13.2l7.6-7.6L18 7l-9 9z',
|
|
|
+ typeIconColor: '#60A5FA',
|
|
|
+ aiRounds: null,
|
|
|
+ submitRate: '86%',
|
|
|
+ accuracy: '60%',
|
|
|
+ accuracyTone: 'tone-orange',
|
|
|
+ interactions: '43 次',
|
|
|
+ avgTime: '1:14',
|
|
|
+ insightPrefix: '概念边界混淆,',
|
|
|
+ insightStrong: '13人错误',
|
|
|
+ insightSuffix: ',建议优先复讲。'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 2,
|
|
|
+ name: 'AI 应用场景排序',
|
|
|
+ type: '排序题',
|
|
|
+ typeIconPath: 'M3 4h2v2H3V4zm4 0h14v2H7V4zM3 11h2v2H3v-2zm4 0h14v2H7v-2zM3 18h2v2H3v-2zm4 0h14v2H7v-2z',
|
|
|
+ typeIconColor: '#A78BFA',
|
|
|
+ aiRounds: null,
|
|
|
+ submitRate: '90%',
|
|
|
+ accuracy: '70%',
|
|
|
+ accuracyTone: 'tone-emerald',
|
|
|
+ interactions: '45 次',
|
|
|
+ avgTime: '3:43',
|
|
|
+ insightPrefix: '弱AI与强AI基本分清,',
|
|
|
+ insightStrong: '35人完全正确',
|
|
|
+ insightSuffix: '。'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: 3,
|
|
|
+ name: '什么是神经网络?',
|
|
|
+ type: '开放问答',
|
|
|
+ typeIconPath: 'M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z',
|
|
|
+ typeIconColor: '#818CF8',
|
|
|
+ aiRounds: '4.0轮',
|
|
|
+ submitRate: '90%',
|
|
|
+ accuracy: '—',
|
|
|
+ accuracyTone: '',
|
|
|
+ interactions: '45 次',
|
|
|
+ avgTime: '6:14',
|
|
|
+ insightPrefix: '优秀回答有类比能力,待提升者多停留在表层定义。',
|
|
|
+ insightStrong: '',
|
|
|
+ insightSuffix: ''
|
|
|
+ }
|
|
|
+ ],
|
|
|
+ students: [
|
|
|
+ { id: 1, name: '张伟', attention: false, tasksDone: 7, tasksTotal: 7, correctRate: '87%', aiRounds: 6, likes: '5/3' },
|
|
|
+ { id: 2, name: '李子涵', attention: false, tasksDone: 7, tasksTotal: 7, correctRate: '92%', aiRounds: 7, likes: '8/5' },
|
|
|
+ { id: 3, name: '王芳', attention: false, tasksDone: 7, tasksTotal: 7, correctRate: '86%', aiRounds: 5, likes: '4/2' },
|
|
|
+ { id: 4, name: '陈嘉怡', attention: false, tasksDone: 7, tasksTotal: 7, correctRate: '91%', aiRounds: 5, likes: '6/4' },
|
|
|
+ { id: 5, name: '杨浩宇', attention: true, tasksDone: 7, tasksTotal: 7, correctRate: '76%', aiRounds: 7, likes: '2/1' }
|
|
|
+ ],
|
|
|
+ chartData: {
|
|
|
+ labels: ['高频参与', '中等频率', '极少参与'],
|
|
|
+ values: [65, 25, 10],
|
|
|
+ colors: ['#10B981', '#60A5FA', '#F43F5E']
|
|
|
+ },
|
|
|
+ showDataBoard: false
|
|
|
+ };
|
|
|
+ },
|
|
|
+ computed: {
|
|
|
+ filteredStudents() {
|
|
|
+ if (!this.searchKeyword) return this.students;
|
|
|
+ const kw = this.searchKeyword.trim().toLowerCase();
|
|
|
+ return this.students.filter(s => s.name.toLowerCase().includes(kw));
|
|
|
+ }
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // this.initChart();
|
|
|
+ window.addEventListener('resize', this.handleResize);
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ window.removeEventListener('resize', this.handleResize);
|
|
|
+ if (this.chartInstance) {
|
|
|
+ this.chartInstance.dispose();
|
|
|
+ this.chartInstance = null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ initChart() {
|
|
|
+ this.$nextTick(() => {
|
|
|
+ if (!this.$refs.performanceChart) return;
|
|
|
+ const echarts = this.$echarts;
|
|
|
+ if (!echarts) return;
|
|
|
+ this.chartInstance = echarts.init(this.$refs.performanceChart);
|
|
|
+ const visibleTotal = this.chartData.values.reduce((a, b) => a + b, 0);
|
|
|
+ const option = {
|
|
|
+ tooltip: {
|
|
|
+ trigger: 'item',
|
|
|
+ backgroundColor: 'rgba(17, 24, 39, 0.95)',
|
|
|
+ padding: 12,
|
|
|
+ textStyle: { color: '#fff', fontSize: 13 },
|
|
|
+ formatter: function (params) {
|
|
|
+ if (!params.name) return '';
|
|
|
+ return params.name + ': ' + params.value + ' (' + params.percent + '%)';
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ show: true,
|
|
|
+ bottom: 0,
|
|
|
+ icon: 'circle',
|
|
|
+ itemWidth: 8,
|
|
|
+ itemHeight: 8,
|
|
|
+ textStyle: { fontSize: 12, fontWeight: 500, color: '#6B7280' },
|
|
|
+ itemGap: 20,
|
|
|
+ data: this.chartData.labels
|
|
|
+ },
|
|
|
+ series: [
|
|
|
+ {
|
|
|
+ name: '参与度分层',
|
|
|
+ type: 'pie',
|
|
|
+ radius: ['58%', '75%'],
|
|
|
+ center: ['50%', '45%'],
|
|
|
+ startAngle: 180,
|
|
|
+ avoidLabelOverlap: false,
|
|
|
+ label: { show: false },
|
|
|
+ labelLine: { show: false },
|
|
|
+ hoverOffset: 4,
|
|
|
+ data: [
|
|
|
+ { value: this.chartData.values[0], name: this.chartData.labels[0], itemStyle: { color: this.chartData.colors[0] } },
|
|
|
+ { value: this.chartData.values[1], name: this.chartData.labels[1], itemStyle: { color: this.chartData.colors[1] } },
|
|
|
+ { value: this.chartData.values[2], name: this.chartData.labels[2], itemStyle: { color: this.chartData.colors[2] } },
|
|
|
+ {
|
|
|
+ value: visibleTotal,
|
|
|
+ name: '',
|
|
|
+ itemStyle: { color: 'transparent' },
|
|
|
+ tooltip: { show: false },
|
|
|
+ label: { show: false },
|
|
|
+ labelLine: { show: false },
|
|
|
+ emphasis: { disabled: true },
|
|
|
+ silent: true
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ };
|
|
|
+ this.chartInstance.setOption(option);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleResize() {
|
|
|
+ if (this.chartInstance) this.chartInstance.resize();
|
|
|
+ },
|
|
|
+ open(){
|
|
|
|
|
|
-}
|
|
|
+ this.showDataBoard = true;
|
|
|
+ this.$nextTick(() => {
|
|
|
+ this.initChart();
|
|
|
+ });
|
|
|
+ },
|
|
|
+ handleBack() {
|
|
|
+ this.showDataBoard = false;
|
|
|
+ },
|
|
|
+ handleClassChange(val) {
|
|
|
+ this.$emit('class-change', val);
|
|
|
+ },
|
|
|
+ handleStudentReport() {
|
|
|
+ this.$emit('student-report');
|
|
|
+ },
|
|
|
+ handleExport() {
|
|
|
+ this.$emit('export');
|
|
|
+ },
|
|
|
+ handleStudentReportRow(row) {
|
|
|
+ this.$emit('student-row-report', row);
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
-<style>
|
|
|
+<style scoped>
|
|
|
+.teacher-dashboard {
|
|
|
+ height: 100vh;
|
|
|
+ padding-bottom: 80px;
|
|
|
+ background-color: #F4F6F8;
|
|
|
+ color: #111827;
|
|
|
+ -webkit-font-smoothing: antialiased;
|
|
|
+ -moz-osx-font-smoothing: grayscale;
|
|
|
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
|
+ position: absolute;
|
|
|
+ width: 100%;
|
|
|
+ z-index: 999;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+}
|
|
|
+
|
|
|
+.teacher-dashboard ::selection {
|
|
|
+ background: #FCCF04;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 顶部导航栏 ============ */
|
|
|
+.nav-bar {
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 50;
|
|
|
+ background-color: #FCCF04;
|
|
|
+}
|
|
|
+.nav-container {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ height: 56px;
|
|
|
+ padding: 0 16px;
|
|
|
+ max-width: 100vw;
|
|
|
+ overflow-x: auto;
|
|
|
+}
|
|
|
+.nav-container::-webkit-scrollbar { display: none; }
|
|
|
+.nav-container { -ms-overflow-style: none; scrollbar-width: none; }
|
|
|
+
|
|
|
+.nav-left {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.nav-back-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ width: 32px;
|
|
|
+ height: 32px;
|
|
|
+ margin-right: 12px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 8px;
|
|
|
+ background: transparent;
|
|
|
+ color: #111827;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+}
|
|
|
+.nav-back-btn:hover { background-color: rgba(0, 0, 0, 0.1); }
|
|
|
+
|
|
|
+.nav-title {
|
|
|
+ margin-right: 12px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-class-select {
|
|
|
+ width: 120px;
|
|
|
+}
|
|
|
+.nav-class-select >>> .el-input__inner {
|
|
|
+ height: 28px;
|
|
|
+ line-height: 28px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 500;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid rgba(209, 213, 219, 0.8);
|
|
|
+ color: #1F2937;
|
|
|
+}
|
|
|
+.nav-class-select >>> .el-input__icon {
|
|
|
+ line-height: 28px;
|
|
|
+}
|
|
|
+
|
|
|
+.nav-right {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ padding-left: 16px;
|
|
|
+}
|
|
|
+.nav-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ gap: 6px;
|
|
|
+ height: 28px;
|
|
|
+ padding: 0 16px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 700;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: background-color 0.2s;
|
|
|
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
|
+}
|
|
|
+.nav-btn-report {
|
|
|
+ background-color: #FCE478;
|
|
|
+ color: #333333;
|
|
|
+}
|
|
|
+.nav-btn-report:hover { background-color: #F9DA55; }
|
|
|
+.nav-btn-export {
|
|
|
+ background-color: #2A2A2A;
|
|
|
+ color: #FCCF04;
|
|
|
+}
|
|
|
+.nav-btn-export:hover { background-color: #1A1A1A; }
|
|
|
+
|
|
|
+/* ============ 主内容区 ============ */
|
|
|
+.main-content {
|
|
|
+ max-width: 1440px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 20px 16px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 20px;
|
|
|
+ overflow: auto;
|
|
|
+ height: calc(100% - 56px);
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 通用区块标题 ============ */
|
|
|
+.section-title-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+.section-accent {
|
|
|
+ width: 4px;
|
|
|
+ height: 16px;
|
|
|
+ border-radius: 9999px;
|
|
|
+ background-color: #FCCF04;
|
|
|
+}
|
|
|
+.section-heading {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 课程概况 + KPI ============ */
|
|
|
+.overview-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 24px;
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #E5E7EB;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.03), 0 2px 8px -2px rgba(0, 0, 0, 0.02);
|
|
|
+}
|
|
|
+.overview-info { flex-shrink: 0; width: 100%; }
|
|
|
+
|
|
|
+.course-info-block { display: flex; flex-direction: column; gap: 8px; }
|
|
|
+.course-name {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 900;
|
|
|
+ color: #111827;
|
|
|
+ letter-spacing: -0.01em;
|
|
|
+}
|
|
|
+.course-meta-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #4B5563;
|
|
|
+}
|
|
|
+.course-meta-item { display: flex; align-items: center; gap: 6px; }
|
|
|
+.meta-icon { color: #9CA3AF; }
|
|
|
+.meta-label { font-weight: 600; color: #374151; }
|
|
|
+.meta-divider { color: #D1D5DB; }
|
|
|
+
|
|
|
+.course-extra-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16px;
|
|
|
+ flex-wrap: wrap;
|
|
|
+}
|
|
|
+.course-extra-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #6B7280;
|
|
|
+}
|
|
|
+.extra-icon { color: #9CA3AF; }
|
|
|
+
|
|
|
+.kpi-row {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+ width: 100%;
|
|
|
+ overflow-x: auto;
|
|
|
+ padding-bottom: 8px;
|
|
|
+}
|
|
|
+.kpi-row::-webkit-scrollbar { display: none; }
|
|
|
+.kpi-row { -ms-overflow-style: none; scrollbar-width: none; }
|
|
|
|
|
|
+.kpi-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ min-width: 115px;
|
|
|
+ padding: 12px 16px;
|
|
|
+ background-color: rgba(249, 250, 251, 0.7);
|
|
|
+ border: 1px solid #F3F4F6;
|
|
|
+ border-radius: 12px;
|
|
|
+}
|
|
|
+.kpi-value {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 900;
|
|
|
+ line-height: 1;
|
|
|
+ margin-bottom: 4px;
|
|
|
+ display: flex;
|
|
|
+ align-items: baseline;
|
|
|
+}
|
|
|
+.kpi-suffix {
|
|
|
+ margin-left: 2px;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.kpi-label {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #374151;
|
|
|
+}
|
|
|
+.kpi-sub {
|
|
|
+ margin-top: 2px;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #9CA3AF;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 详情网格 ============ */
|
|
|
+.detail-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ gap: 20px;
|
|
|
+}
|
|
|
+.detail-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ height: 100%;
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid #F3F4F6;
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.03), 0 2px 8px -2px rgba(0, 0, 0, 0.02);
|
|
|
+ transition: box-shadow 0.3s;
|
|
|
+}
|
|
|
+.detail-card:hover {
|
|
|
+ box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.06), 0 4px 12px -3px rgba(0, 0, 0, 0.03);
|
|
|
+}
|
|
|
+.card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+}
|
|
|
+.card-icon {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 6px;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+.brand-soft { background-color: #FFFAEB; color: #D4AD00; }
|
|
|
+.yellow-soft { background-color: #FEF9C3; color: #D4AD00; }
|
|
|
+.card-title {
|
|
|
+ margin: 0;
|
|
|
+ font-size: 16px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #111827;
|
|
|
+}
|
|
|
+.card-body {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 16px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #4B5563;
|
|
|
+ line-height: 1.7;
|
|
|
+ flex-grow: 1;
|
|
|
+}
|
|
|
+.paragraph { margin: 0; }
|
|
|
+.strong { font-weight: 600; color: #1F2937; }
|
|
|
+.bullet-list {
|
|
|
+ margin: 4px 0 0;
|
|
|
+ padding-left: 20px;
|
|
|
+ list-style: disc;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 4px;
|
|
|
+ color: #6B7280;
|
|
|
+}
|
|
|
+.bullet-list li { line-height: 1.6; }
|
|
|
+
|
|
|
+/* AI 报告卡(玻璃拟物化) */
|
|
|
+.ai-report-card {
|
|
|
+ position: relative;
|
|
|
+ overflow: hidden;
|
|
|
+ background: linear-gradient(135deg, #FFFFFF 0%, #F8FAFC 100%);
|
|
|
+ border: 1px solid rgba(252, 207, 4, 0.2);
|
|
|
+ box-shadow: 0 8px 32px -8px rgba(252, 207, 4, 0.1), 0 4px 12px -4px rgba(0, 0, 0, 0.03);
|
|
|
+}
|
|
|
+.ai-report-card::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ top: 0; left: 0; right: 0; bottom: 0;
|
|
|
+ border-radius: inherit;
|
|
|
+ background: radial-gradient(circle at top right, rgba(252, 207, 4, 0.12) 0%, transparent 60%);
|
|
|
+ pointer-events: none;
|
|
|
+}
|
|
|
+.relative-z { position: relative; z-index: 1; }
|
|
|
+.ai-report-list {
|
|
|
+ margin: 0;
|
|
|
+ padding: 0;
|
|
|
+ list-style: none;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ gap: 14px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #4B5563;
|
|
|
+ line-height: 1.7;
|
|
|
+ flex-grow: 1;
|
|
|
+}
|
|
|
+.ai-report-item {
|
|
|
+ display: flex;
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 10px;
|
|
|
+}
|
|
|
+.ai-icon { flex-shrink: 0; margin-top: 4px; }
|
|
|
+.icon-green { color: #10B981; }
|
|
|
+.icon-red { color: #F43F5E; }
|
|
|
+.icon-brand { color: #D4AD00; }
|
|
|
+
|
|
|
+/* ============ 任务概况表 ============ */
|
|
|
+.task-section { scroll-margin-top: 80px; }
|
|
|
+.task-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid rgba(243, 244, 246, 0.6);
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.03), 0 2px 8px -2px rgba(0, 0, 0, 0.02);
|
|
|
+}
|
|
|
+.task-card-header {
|
|
|
+ padding: 20px;
|
|
|
+ border-bottom: 1px solid #F3F4F6;
|
|
|
+ background-color: #fff;
|
|
|
+ z-index: 10;
|
|
|
+}
|
|
|
+.table-scroll { overflow-x: auto; }
|
|
|
+
|
|
|
+.custom-table {
|
|
|
+ width: 100%;
|
|
|
+ text-align: left;
|
|
|
+ border-collapse: collapse;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.custom-table thead {
|
|
|
+ background-color: #F8FAFC;
|
|
|
+ color: #64748B;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+ text-transform: uppercase;
|
|
|
+ border-bottom: 1px solid #F1F5F9;
|
|
|
+}
|
|
|
+.custom-table th {
|
|
|
+ padding: 12px 20px;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.custom-table td {
|
|
|
+ padding: 16px 20px;
|
|
|
+ font-size: 13px;
|
|
|
+ border-bottom: 1px solid rgba(243, 244, 246, 0.6);
|
|
|
+}
|
|
|
+.custom-table tbody tr:last-child td { border-bottom: none; }
|
|
|
+.th-num { width: 48px; text-align: center; }
|
|
|
+.th-center { text-align: center; }
|
|
|
+.td-num {
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #9CA3AF;
|
|
|
+}
|
|
|
+.td-center { text-align: center; }
|
|
|
+.td-extrabold { font-weight: 800; color: #1F2937; font-size: 14px; }
|
|
|
+.td-bold-700 { font-weight: 700; color: #374151; }
|
|
|
+.td-medium { font-weight: 500; color: #6B7280; }
|
|
|
+.td-insight {
|
|
|
+ white-space: normal;
|
|
|
+ min-width: 250px;
|
|
|
+}
|
|
|
+.table-row { transition: background-color 0.2s; }
|
|
|
+.table-row:hover { background-color: #F8FAFC; }
|
|
|
+
|
|
|
+.task-name {
|
|
|
+ font-weight: 700;
|
|
|
+ color: #111827;
|
|
|
+ margin-bottom: 2px;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.task-type {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #6B7280;
|
|
|
+}
|
|
|
+.task-type-icon { display: inline-block; }
|
|
|
+.ai-rounds-badge {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ margin-left: 4px;
|
|
|
+ padding: 0 6px;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #D4AD00;
|
|
|
+ background-color: #FFFAEB;
|
|
|
+ border: 1px solid #FEF0A7;
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+
|
|
|
+.accuracy-badge {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ padding: 4px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 700;
|
|
|
+ border: 1px solid;
|
|
|
+}
|
|
|
+.tone-orange {
|
|
|
+ background-color: #FFF7ED;
|
|
|
+ color: #EA580C;
|
|
|
+ border-color: rgba(251, 146, 60, 0.6);
|
|
|
+}
|
|
|
+.tone-emerald {
|
|
|
+ background-color: #ECFDF5;
|
|
|
+ color: #059669;
|
|
|
+ border-color: rgba(52, 211, 153, 0.6);
|
|
|
+}
|
|
|
+.accuracy-dash {
|
|
|
+ color: #D1D5DB;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+.insight-text {
|
|
|
+ color: #4B5563;
|
|
|
+ line-height: 1.7;
|
|
|
+}
|
|
|
+.insight-strong {
|
|
|
+ color: #111827;
|
|
|
+ font-weight: 700;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 学生详情区 ============ */
|
|
|
+.student-section { scroll-margin-top: 80px; }
|
|
|
+.student-grid {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: 1fr;
|
|
|
+ gap: 20px;
|
|
|
+}
|
|
|
+
|
|
|
+.chart-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 20px;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid rgba(243, 244, 246, 0.6);
|
|
|
+ border-radius: 12px;
|
|
|
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.03), 0 2px 8px -2px rgba(0, 0, 0, 0.02);
|
|
|
+ transition: box-shadow 0.3s;
|
|
|
+}
|
|
|
+.chart-card:hover {
|
|
|
+ box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.06), 0 4px 12px -3px rgba(0, 0, 0, 0.03);
|
|
|
+}
|
|
|
+.chart-wrapper {
|
|
|
+ position: relative;
|
|
|
+ flex-grow: 1;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 192px;
|
|
|
+}
|
|
|
+.echart-canvas {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+.chart-center {
|
|
|
+ position: absolute;
|
|
|
+ inset: 0;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ pointer-events: none;
|
|
|
+ padding-top: 16px;
|
|
|
+}
|
|
|
+.chart-center-value {
|
|
|
+ font-size: 32px;
|
|
|
+ font-weight: 900;
|
|
|
+ color: #111827;
|
|
|
+ letter-spacing: -0.01em;
|
|
|
+}
|
|
|
+.chart-center-label {
|
|
|
+ margin-top: 2px;
|
|
|
+ font-size: 11px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #9CA3AF;
|
|
|
+ text-transform: uppercase;
|
|
|
+ letter-spacing: 0.05em;
|
|
|
+}
|
|
|
+
|
|
|
+.student-table-card {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ padding: 0;
|
|
|
+ background-color: #fff;
|
|
|
+ border: 1px solid rgba(243, 244, 246, 0.6);
|
|
|
+ border-radius: 12px;
|
|
|
+ overflow: hidden;
|
|
|
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.03), 0 2px 8px -2px rgba(0, 0, 0, 0.02);
|
|
|
+ transition: box-shadow 0.3s;
|
|
|
+}
|
|
|
+.student-table-card:hover {
|
|
|
+ box-shadow: 0 10px 30px -5px rgba(0, 0, 0, 0.06), 0 4px 12px -3px rgba(0, 0, 0, 0.03);
|
|
|
+}
|
|
|
+.student-table-header {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ gap: 16px;
|
|
|
+ padding: 20px;
|
|
|
+ border-bottom: 1px solid #F3F4F6;
|
|
|
+ background-color: #fff;
|
|
|
+ z-index: 10;
|
|
|
+}
|
|
|
+.search-input { width: 100%; max-width: 224px; }
|
|
|
+.search-input >>> .el-input__inner {
|
|
|
+ font-size: 13px;
|
|
|
+ font-weight: 600;
|
|
|
+ background-color: rgba(249, 250, 251, 0.5);
|
|
|
+ border-color: rgba(229, 231, 235, 0.8);
|
|
|
+}
|
|
|
+.search-input >>> .el-input__inner:focus {
|
|
|
+ border-color: #FCCF04;
|
|
|
+ box-shadow: 0 0 0 1px #FCCF04;
|
|
|
+}
|
|
|
+.search-icon-slot {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ height: 100%;
|
|
|
+ margin: 0 8px;
|
|
|
+ color: #9CA3AF;
|
|
|
+}
|
|
|
+
|
|
|
+.student-table-scroll {
|
|
|
+ flex-grow: 1;
|
|
|
+ overflow-x: auto;
|
|
|
+ overflow-y: auto;
|
|
|
+ max-height: 380px;
|
|
|
+}
|
|
|
+.student-table-scroll .custom-table thead th {
|
|
|
+ position: sticky;
|
|
|
+ top: 0;
|
|
|
+ z-index: 10;
|
|
|
+ background-color: #F8FAFC;
|
|
|
+}
|
|
|
+.th-sortable {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 6px;
|
|
|
+ cursor: pointer;
|
|
|
+ color: #64748B;
|
|
|
+ transition: color 0.2s;
|
|
|
+}
|
|
|
+.th-sortable:hover { color: #111827; }
|
|
|
+
|
|
|
+.student-name-cell {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 8px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #111827;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+.attention-badge {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 2px;
|
|
|
+ padding: 2px 6px;
|
|
|
+ background-color: #FEE2E2;
|
|
|
+ color: #DC2626;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 10px;
|
|
|
+ font-weight: 900;
|
|
|
+ letter-spacing: 0.05em;
|
|
|
+}
|
|
|
+.attention-row { background-color: rgba(254, 242, 242, 0.3); }
|
|
|
+.attention-row:hover { background-color: rgba(254, 242, 242, 0.5); }
|
|
|
+.attention-num-color { color: #F87171; }
|
|
|
+
|
|
|
+.progress-wrapper {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+.progress-bar {
|
|
|
+ width: 96px;
|
|
|
+ height: 8px;
|
|
|
+ border-radius: 9999px;
|
|
|
+ background-color: #F3F4F6;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.progress-bar-amber-bg { background-color: rgba(229, 231, 235, 0.8); }
|
|
|
+.progress-fill {
|
|
|
+ height: 100%;
|
|
|
+ border-radius: 9999px;
|
|
|
+ background-color: #10B981;
|
|
|
+}
|
|
|
+.fill-amber { background-color: #FBBF24; }
|
|
|
+.progress-text {
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+ color: #4B5563;
|
|
|
+}
|
|
|
+.td-correct-red {
|
|
|
+ text-align: center;
|
|
|
+ font-weight: 900;
|
|
|
+ color: #EF4444;
|
|
|
+ font-size: 14px;
|
|
|
+}
|
|
|
+
|
|
|
+.report-btn {
|
|
|
+ display: inline-flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
+ margin: 0 auto;
|
|
|
+ padding: 6px 12px;
|
|
|
+ border: none;
|
|
|
+ border-radius: 6px;
|
|
|
+ background-color: #FFFAEB;
|
|
|
+ color: #D4AD00;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 700;
|
|
|
+ cursor: pointer;
|
|
|
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
|
|
|
+ transition: background-color 0.2s, color 0.2s;
|
|
|
+}
|
|
|
+.report-btn:hover {
|
|
|
+ background-color: #FEF9C3;
|
|
|
+ color: #A16207;
|
|
|
+}
|
|
|
+.empty-row {
|
|
|
+ text-align: center;
|
|
|
+ padding: 24px;
|
|
|
+ color: #9CA3AF;
|
|
|
+ font-size: 13px;
|
|
|
+}
|
|
|
+
|
|
|
+/* ============ 响应式 ============ */
|
|
|
+@media (min-width: 640px) {
|
|
|
+ .main-content { padding: 20px 24px; }
|
|
|
+ .nav-container { padding: 0 24px; }
|
|
|
+}
|
|
|
+@media (min-width: 1024px) {
|
|
|
+ .main-content { padding: 20px 32px; }
|
|
|
+ .nav-container { padding: 0 32px; }
|
|
|
+ .detail-grid { grid-template-columns: 1fr 1fr; }
|
|
|
+ .student-grid { grid-template-columns: 1fr 2fr; }
|
|
|
+ .student-table-header { flex-direction: row; align-items: center; }
|
|
|
+}
|
|
|
+@media (min-width: 1280px) {
|
|
|
+ .overview-card {
|
|
|
+ flex-direction: row;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .overview-info { width: auto; align-self: center; }
|
|
|
+ .kpi-row { width: auto; padding-bottom: 0; }
|
|
|
+}
|
|
|
</style>
|