tam
This commit is contained in:
@@ -140,7 +140,7 @@ function App() {
|
||||
onClick={() => navigate('learning')}
|
||||
>
|
||||
<span className="nav-icon"><IconLearning /></span>
|
||||
Giám sát & Lịch học
|
||||
Phòng Học
|
||||
</button>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
|
||||
@@ -816,53 +816,70 @@ export const ExamRoomWorkspace: React.FC<Props> = ({ examId, onBack }) => {
|
||||
)}
|
||||
|
||||
{studentPickerOpen && (
|
||||
<div className="modal-overlay">
|
||||
<div className="modal-container" style={{ maxWidth: '560px', width: '92%' }}>
|
||||
<div className="modal-header">
|
||||
<div className="modal-overlay exam-student-overlay" onClick={() => setStudentPickerOpen(false)}>
|
||||
<div className="modal-container exam-student-modal" onClick={(e) => e.stopPropagation()}>
|
||||
<div className="modal-header exam-student-modal-header">
|
||||
<div>
|
||||
<h2 className="modal-title">Thêm sinh viên</h2>
|
||||
<p style={{ margin: '4px 0 0', color: 'var(--text-muted)', fontSize: '0.85rem' }}>
|
||||
Tìm theo mã lớp, họ tên, mã sinh viên
|
||||
</p>
|
||||
<p className="exam-student-modal-desc">Tìm theo mã lớp, họ tên, mã sinh viên</p>
|
||||
</div>
|
||||
<button type="button" className="btn btn-secondary close-btn" onClick={() => setStudentPickerOpen(false)}>Đóng</button>
|
||||
<button type="button" className="modal-close-btn" onClick={() => setStudentPickerOpen(false)} aria-label="Đóng">
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div style={{ padding: '0 0 1rem' }}>
|
||||
<input
|
||||
type="search"
|
||||
className="app-pool-search"
|
||||
placeholder="Tìm sinh viên..."
|
||||
value={searchQ}
|
||||
onChange={(e) => setSearchQ(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
<div style={{ maxHeight: 'min(55vh, 420px)', overflowY: 'auto', marginTop: '1rem' }}>
|
||||
<div className="exam-student-modal-body">
|
||||
<div className="exam-student-modal-search search-input-wrap">
|
||||
<input
|
||||
type="search"
|
||||
className="search-input"
|
||||
placeholder="Tìm sinh viên..."
|
||||
value={searchQ}
|
||||
onChange={(e) => setSearchQ(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
<div className="exam-student-hits">
|
||||
{searchQ.trim() === '' ? (
|
||||
<p style={{ color: 'var(--text-muted)', textAlign: 'center' }}>Gõ ít nhất vài ký tự để tìm.</p>
|
||||
<div className="exam-student-hits-empty">
|
||||
<span>🔍</span>
|
||||
<p>Gõ ít nhất vài ký tự để tìm sinh viên.</p>
|
||||
</div>
|
||||
) : searchHits.length === 0 ? (
|
||||
<p style={{ color: 'var(--text-muted)', textAlign: 'center' }}>Không tìm thấy sinh viên phù hợp.</p>
|
||||
<div className="exam-student-hits-empty">
|
||||
<span>📭</span>
|
||||
<p>Không tìm thấy sinh viên phù hợp.</p>
|
||||
</div>
|
||||
) : (
|
||||
<ul className="learning-add-list">
|
||||
{searchHits.map((h) => {
|
||||
const added = enrolledIds.has(h.studentRkId);
|
||||
return (
|
||||
<li key={h.studentRkId} className="learning-add-item">
|
||||
<div>
|
||||
<div className="learning-class-code">{h.studentCode}</div>
|
||||
<div className="learning-class-meta">{h.fullName}</div>
|
||||
{(h.classCodes || h.email) && (
|
||||
<div style={{ fontSize: '0.75rem', color: 'var(--text-muted)', marginTop: '0.2rem' }}>
|
||||
{[h.classCodes, h.email].filter(Boolean).join(' · ')}
|
||||
</div>
|
||||
)}
|
||||
searchHits.map((h) => {
|
||||
const added = enrolledIds.has(h.studentRkId);
|
||||
const initials = h.fullName
|
||||
.split(/\s+/)
|
||||
.filter(Boolean)
|
||||
.slice(-2)
|
||||
.map((w) => w[0]?.toUpperCase() || '')
|
||||
.join('');
|
||||
return (
|
||||
<div key={h.studentRkId} className="exam-student-hit">
|
||||
<div className="exam-student-hit-avatar" aria-hidden="true">{initials || '?'}</div>
|
||||
<div className="exam-student-hit-info">
|
||||
<strong>{h.fullName}</strong>
|
||||
<div className="exam-student-hit-meta">
|
||||
Mã SV: <code>{h.studentCode}</code>
|
||||
{h.classCodes ? <> · Lớp: {h.classCodes}</> : null}
|
||||
{h.email ? <> · {h.email}</> : null}
|
||||
</div>
|
||||
<button type="button" className="btn btn-primary btn-sm" disabled={added} onClick={() => addStudent(h.studentRkId)}>
|
||||
{added ? 'Đã thêm' : 'Thêm'}
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
className={`btn btn-sm ${added ? 'btn-secondary' : 'btn-primary'}`}
|
||||
disabled={added}
|
||||
onClick={() => addStudent(h.studentRkId)}
|
||||
>
|
||||
{added ? '✓ Đã thêm' : '+ Thêm'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4212,6 +4212,21 @@ input:checked + .slider:before {
|
||||
box-shadow: 0 2px 10px rgba(187, 33, 38, 0.08);
|
||||
}
|
||||
|
||||
.exam-student-hit-avatar {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #fff5f5 0%, #fee2e2 100%);
|
||||
color: var(--accent);
|
||||
font-weight: 700;
|
||||
font-size: 0.82rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
border: 1px solid rgba(187, 33, 38, 0.12);
|
||||
}
|
||||
|
||||
.exam-student-hit-info {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user