|
|
@@ -0,0 +1,98 @@
|
|
|
+<template>
|
|
|
+ <div class="grid-4">
|
|
|
+ <div
|
|
|
+ v-for="s in students"
|
|
|
+ :key="s.userId"
|
|
|
+ class="student-card"
|
|
|
+ :class="['status-' + s.status]"
|
|
|
+ @click="$emit('click', s)"
|
|
|
+ >
|
|
|
+ <div class="avatar" :class="'avatar-' + s.status">
|
|
|
+ {{ s.name.charAt(0) }}
|
|
|
+ </div>
|
|
|
+ <span class="name">{{ s.name }}</span>
|
|
|
+ <span v-if="s.status === 'submitted'" class="indicator check">✓</span>
|
|
|
+ <span v-else-if="s.status === 'unsubmitted'" class="indicator dot pulse" />
|
|
|
+ <span v-else class="indicator dash">—</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import type { ClassStudentSummary } from './types'
|
|
|
+
|
|
|
+defineProps<{ students: ClassStudentSummary[] }>()
|
|
|
+defineEmits<{ click: [student: ClassStudentSummary] }>()
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.grid-4 {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
|
+ gap: 12px;
|
|
|
+}
|
|
|
+
|
|
|
+.student-card {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 10px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ border-radius: 8px;
|
|
|
+ cursor: pointer;
|
|
|
+ transition: box-shadow .15s ease;
|
|
|
+ background: #fff;
|
|
|
+ border: 2px solid transparent;
|
|
|
+
|
|
|
+ &:hover { box-shadow: 0 2px 8px rgba(0,0,0,.08); }
|
|
|
+
|
|
|
+ &.status-submitted { border-color: #facc15; }
|
|
|
+ &.status-unsubmitted { border-color: #fde68a; }
|
|
|
+ &.status-not_started {
|
|
|
+ background: #f3f4f6;
|
|
|
+ border: 2px dashed #9ca3af;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.avatar {
|
|
|
+ flex-shrink: 0;
|
|
|
+ width: 32px; height: 32px;
|
|
|
+ border-radius: 50%;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 600;
|
|
|
+}
|
|
|
+.avatar-submitted { background: #facc15; color: #111827; }
|
|
|
+.avatar-unsubmitted { background: #fef3c7; color: #92400e; }
|
|
|
+.avatar-not_started { background: #e5e7eb; color: #6b7280; }
|
|
|
+
|
|
|
+.name {
|
|
|
+ flex: 1;
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: #111827;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+}
|
|
|
+.status-not_started .name { color: #9ca3af; }
|
|
|
+
|
|
|
+.indicator {
|
|
|
+ flex-shrink: 0;
|
|
|
+ font-size: 12px;
|
|
|
+}
|
|
|
+.indicator.check { color: #ca8a04; font-weight: 600; }
|
|
|
+.indicator.dash { color: #9ca3af; }
|
|
|
+
|
|
|
+.indicator.dot.pulse {
|
|
|
+ width: 8px; height: 8px;
|
|
|
+ border-radius: 50%;
|
|
|
+ background: #fbbf24;
|
|
|
+ animation: pulse 1.5s ease-in-out infinite;
|
|
|
+}
|
|
|
+@keyframes pulse {
|
|
|
+ 0%, 100% { opacity: 1; }
|
|
|
+ 50% { opacity: .4; }
|
|
|
+}
|
|
|
+</style>
|