fix lam bai
This commit is contained in:
@@ -415,6 +415,55 @@ body {
|
||||
color: var(--text-muted);
|
||||
}
|
||||
|
||||
.exam-resources {
|
||||
margin-top: 0.9rem;
|
||||
padding-top: 0.85rem;
|
||||
border-top: 1px dashed #c4b5fd;
|
||||
}
|
||||
|
||||
.exam-resources-title {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: #6d28d9;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.exam-resource-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.65rem;
|
||||
padding: 0.45rem 0;
|
||||
border-bottom: 1px solid #ede9fe;
|
||||
}
|
||||
|
||||
.exam-resource-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.exam-resource-name {
|
||||
font-size: 0.84rem;
|
||||
color: var(--text-secondary);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.exam-resource-btns {
|
||||
display: flex;
|
||||
gap: 0.35rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 0.35rem 0.65rem;
|
||||
font-size: 0.78rem;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
|
||||
@@ -178,6 +178,40 @@ function renderShiftsTable(shifts) {
|
||||
`;
|
||||
}
|
||||
|
||||
let examPaperFiles = null;
|
||||
|
||||
function renderExamResources() {
|
||||
if (!examPaperFiles?.resources?.length) return '';
|
||||
const rows = examPaperFiles.resources.map((r) => `
|
||||
<div class="exam-resource-row">
|
||||
<span class="exam-resource-name" title="${escapeHtml(r.fileName || '')}">${escapeHtml(r.fileName || 'Tài nguyên')}</span>
|
||||
<div class="exam-resource-btns">
|
||||
<button type="button" class="btn btn-secondary btn-sm btn-exam-res-view" data-id="${r.id}">Xem</button>
|
||||
<button type="button" class="btn btn-secondary btn-sm btn-exam-res-dl" data-id="${r.id}">Tải về</button>
|
||||
</div>
|
||||
</div>
|
||||
`).join('');
|
||||
return `
|
||||
<div class="exam-resources">
|
||||
<div class="exam-resources-title">Tài nguyên kèm đề</div>
|
||||
${rows}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async function loadExamPaperFiles() {
|
||||
const ex = stats.exam;
|
||||
if (!ex || stats.monitorMode !== 'exam' || !ex.paperSent) {
|
||||
examPaperFiles = null;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
examPaperFiles = await window.go.main.App.GetExamPaperFiles();
|
||||
} catch {
|
||||
examPaperFiles = null;
|
||||
}
|
||||
}
|
||||
|
||||
function renderExamPanel() {
|
||||
const ex = stats.exam;
|
||||
if (!ex || stats.monitorMode !== 'exam') return '';
|
||||
@@ -195,12 +229,13 @@ function renderExamPanel() {
|
||||
<div class="card-title-row">
|
||||
<div class="card-title">📝 ${ex.examName || 'Phòng thi'}</div>
|
||||
</div>
|
||||
<p class="exam-panel-desc">Bạn đang trong giờ thi. Làm bài theo hướng dẫn của giảng viên.</p>
|
||||
<p class="exam-panel-desc">Bạn đang trong giờ thi. Đề, link thi và tài nguyên mở trong app — không dùng trình duyệt ngoài.</p>
|
||||
<div class="exam-panel-actions">
|
||||
${paperBtn}
|
||||
${quizBtn}
|
||||
${submitBtn}
|
||||
</div>
|
||||
${renderExamResources()}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
@@ -221,16 +256,35 @@ function wireExamPanel() {
|
||||
alert(`Đã nộp bài: ${name}`);
|
||||
const fresh = await window.go.main.App.GetStats();
|
||||
stats = { ...stats, ...fresh };
|
||||
await loadExamPaperFiles();
|
||||
updateExamPanel();
|
||||
} catch (e) {
|
||||
alert(e?.message || e || 'Nộp bài thất bại');
|
||||
}
|
||||
});
|
||||
document.querySelectorAll('.btn-exam-res-view').forEach((btn) => {
|
||||
btn.addEventListener('click', () => {
|
||||
const id = Number(btn.getAttribute('data-id'));
|
||||
window.go.main.App.OpenExamResource(id).catch((e) => alert(e?.message || e));
|
||||
});
|
||||
});
|
||||
document.querySelectorAll('.btn-exam-res-dl').forEach((btn) => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = Number(btn.getAttribute('data-id'));
|
||||
try {
|
||||
const path = await window.go.main.App.DownloadExamResource(id);
|
||||
alert(`Đã tải về:\n${path}`);
|
||||
} catch (e) {
|
||||
alert(e?.message || e || 'Tải thất bại');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function updateExamPanel() {
|
||||
async function updateExamPanel() {
|
||||
const host = document.getElementById('exam-panel-host');
|
||||
if (!host) return;
|
||||
await loadExamPaperFiles();
|
||||
host.innerHTML = renderExamPanel();
|
||||
wireExamPanel();
|
||||
}
|
||||
@@ -485,7 +539,7 @@ function renderChatMessages(silent = false) {
|
||||
}
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
return String(s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
||||
}
|
||||
|
||||
async function sendStudentChat() {
|
||||
|
||||
10
client/frontend/wailsjs/go/main/App.d.ts
vendored
10
client/frontend/wailsjs/go/main/App.d.ts
vendored
@@ -5,12 +5,20 @@ export function CheckLoginStatus():Promise<boolean>;
|
||||
|
||||
export function ClearChatUnread():Promise<void>;
|
||||
|
||||
export function DownloadExamResource(arg1:number):Promise<string>;
|
||||
|
||||
export function GetChatConversations():Promise<Array<Record<string, any>>>;
|
||||
|
||||
export function GetChatMessages(arg1:number):Promise<Array<Record<string, any>>>;
|
||||
|
||||
export function GetChatUnread():Promise<number>;
|
||||
|
||||
export function GetExamPaperFiles():Promise<Record<string, any>>;
|
||||
|
||||
export function GetExamPaperViewURL():Promise<string>;
|
||||
|
||||
export function GetExamQuizViewURL():Promise<string>;
|
||||
|
||||
export function GetStats():Promise<Record<string, any>>;
|
||||
|
||||
export function GetStudentInfo():Promise<Record<string, any>>;
|
||||
@@ -23,6 +31,8 @@ export function OpenExamPaper():Promise<void>;
|
||||
|
||||
export function OpenExamQuiz():Promise<void>;
|
||||
|
||||
export function OpenExamResource(arg1:number):Promise<void>;
|
||||
|
||||
export function SendChatMessage(arg1:string):Promise<void>;
|
||||
|
||||
export function SendWebcamFrame(arg1:string):Promise<void>;
|
||||
|
||||
@@ -10,6 +10,10 @@ export function ClearChatUnread() {
|
||||
return window['go']['main']['App']['ClearChatUnread']();
|
||||
}
|
||||
|
||||
export function DownloadExamResource(arg1) {
|
||||
return window['go']['main']['App']['DownloadExamResource'](arg1);
|
||||
}
|
||||
|
||||
export function GetChatConversations() {
|
||||
return window['go']['main']['App']['GetChatConversations']();
|
||||
}
|
||||
@@ -22,6 +26,18 @@ export function GetChatUnread() {
|
||||
return window['go']['main']['App']['GetChatUnread']();
|
||||
}
|
||||
|
||||
export function GetExamPaperFiles() {
|
||||
return window['go']['main']['App']['GetExamPaperFiles']();
|
||||
}
|
||||
|
||||
export function GetExamPaperViewURL() {
|
||||
return window['go']['main']['App']['GetExamPaperViewURL']();
|
||||
}
|
||||
|
||||
export function GetExamQuizViewURL() {
|
||||
return window['go']['main']['App']['GetExamQuizViewURL']();
|
||||
}
|
||||
|
||||
export function GetStats() {
|
||||
return window['go']['main']['App']['GetStats']();
|
||||
}
|
||||
@@ -46,6 +62,10 @@ export function OpenExamQuiz() {
|
||||
return window['go']['main']['App']['OpenExamQuiz']();
|
||||
}
|
||||
|
||||
export function OpenExamResource(arg1) {
|
||||
return window['go']['main']['App']['OpenExamResource'](arg1);
|
||||
}
|
||||
|
||||
export function SendChatMessage(arg1) {
|
||||
return window['go']['main']['App']['SendChatMessage'](arg1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user