Lashtw commited on
Commit
fd5bb5f
·
verified ·
1 Parent(s): ae79a68

Upload 10 files

Browse files
Files changed (2) hide show
  1. src/views/AdminView.js +6 -1
  2. src/views/StudentView.js +100 -0
src/views/AdminView.js CHANGED
@@ -52,6 +52,10 @@ export function renderAdminView() {
52
  <label class="block text-gray-400 mb-1">連結 (GeminiCanvas Link/Code)</label>
53
  <input type="text" id="edit-link" class="w-full bg-gray-900 border border-gray-600 rounded p-2 text-white">
54
  </div>
 
 
 
 
55
  <div>
56
  <label class="block text-gray-400 mb-1">排序 (Order)</label>
57
  <input type="number" id="edit-order" class="w-full bg-gray-900 border border-gray-600 rounded p-2 text-white" value="1">
@@ -107,6 +111,7 @@ export function setupAdminEvents() {
107
  level: document.getElementById('edit-level').value,
108
  description: document.getElementById('edit-desc').value,
109
  link: document.getElementById('edit-link').value,
 
110
  order: parseInt(document.getElementById('edit-order').value) || 0
111
  };
112
 
@@ -203,10 +208,10 @@ window.openModal = function (challenge = null, defaultLevel = 'beginner') {
203
  // Reset or Fill
204
  document.getElementById('edit-id').value = challenge ? challenge.id : '';
205
  document.getElementById('edit-title').value = challenge ? challenge.title : '';
206
- // Use challenge level if editing, otherwise use defaultLevel passed from section button
207
  document.getElementById('edit-level').value = challenge ? challenge.level : defaultLevel;
208
  document.getElementById('edit-desc').value = challenge ? challenge.description : '';
209
  document.getElementById('edit-link').value = challenge ? challenge.link : '';
 
210
  document.getElementById('edit-order').value = challenge ? challenge.order : '1';
211
 
212
  title.textContent = challenge ? '編輯題目' : '新增題目';
 
52
  <label class="block text-gray-400 mb-1">連結 (GeminiCanvas Link/Code)</label>
53
  <input type="text" id="edit-link" class="w-full bg-gray-900 border border-gray-600 rounded p-2 text-white">
54
  </div>
55
+ <div>
56
+ <label class="block text-gray-400 mb-1">參考答案 (Reference Answer)</label>
57
+ <textarea id="edit-reference" rows="4" class="w-full bg-gray-900 border border-gray-600 rounded p-2 text-white placeholder-gray-500" placeholder="提示詞沒有標準答案,只要能有效修正程式,就是好的提示詞,此答案僅供參考..."></textarea>
58
+ </div>
59
  <div>
60
  <label class="block text-gray-400 mb-1">排序 (Order)</label>
61
  <input type="number" id="edit-order" class="w-full bg-gray-900 border border-gray-600 rounded p-2 text-white" value="1">
 
111
  level: document.getElementById('edit-level').value,
112
  description: document.getElementById('edit-desc').value,
113
  link: document.getElementById('edit-link').value,
114
+ reference: document.getElementById('edit-reference').value,
115
  order: parseInt(document.getElementById('edit-order').value) || 0
116
  };
117
 
 
208
  // Reset or Fill
209
  document.getElementById('edit-id').value = challenge ? challenge.id : '';
210
  document.getElementById('edit-title').value = challenge ? challenge.title : '';
 
211
  document.getElementById('edit-level').value = challenge ? challenge.level : defaultLevel;
212
  document.getElementById('edit-desc').value = challenge ? challenge.description : '';
213
  document.getElementById('edit-link').value = challenge ? challenge.link : '';
214
+ document.getElementById('edit-reference').value = challenge ? (challenge.reference || '') : '';
215
  document.getElementById('edit-order').value = challenge ? challenge.order : '1';
216
 
217
  title.textContent = challenge ? '編輯題目' : '新增題目';
src/views/StudentView.js CHANGED
@@ -477,6 +477,17 @@ export function setupStudentEvents() {
477
  app.innerHTML = await renderStudentView();
478
  }
479
 
 
 
 
 
 
 
 
 
 
 
 
480
  } catch (error) {
481
  console.error(error);
482
  btn.textContent = originalText;
@@ -584,6 +595,95 @@ window.closePeerModal = () => {
584
  document.getElementById('peer-modal').classList.add('hidden');
585
  };
586
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
587
  // Helper to render a level group (Accordion)
588
  function renderLevelGroup(level, tasks, userProgress, levelNames) {
589
  const detailsId = `details-group-${level}`;
 
477
  app.innerHTML = await renderStudentView();
478
  }
479
 
480
+ // 檢查是否已完成該層級所有題目
481
+ const levelTasks = levelGroups[level] || [];
482
+ const completedCount = levelTasks.filter(t => newProgress[t.id]?.status === 'completed').length;
483
+ if (completedCount === levelTasks.length && levelTasks.length > 0) {
484
+ setTimeout(() => {
485
+ if (confirm(`恭喜!您已完成${levelNames[level]}所有關卡!是否要與參考答案進行核對?`)) {
486
+ window.showReferenceComparison(level, levelTasks, newProgress);
487
+ }
488
+ }, 500);
489
+ }
490
+
491
  } catch (error) {
492
  console.error(error);
493
  btn.textContent = originalText;
 
595
  document.getElementById('peer-modal').classList.add('hidden');
596
  };
597
 
598
+ function renderReferenceModal(level, tasks, progress) {
599
+ const levelNames = {
600
+ beginner: "初級 (Beginner)",
601
+ intermediate: "中級 (Intermediate)",
602
+ advanced: "高級 (Advanced)"
603
+ };
604
+
605
+ let listHtml = tasks.map(c => {
606
+ const p = progress[c.id] || {};
607
+ const refAnswer = c.reference || '尚無參考答案\n(No reference answer provided)';
608
+ return `
609
+ <div class="bg-gray-800 rounded-xl p-6 border border-gray-600 shadow-md transform transition-all hover:-translate-y-1 hover:shadow-cyan-900/50">
610
+ <h4 class="text-xl text-cyan-400 font-bold mb-4 drop-shadow-md pb-2 border-b border-gray-700">${c.title}</h4>
611
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
612
+ <div class="flex flex-col">
613
+ <div class="text-sm font-bold text-gray-400 mb-2 uppercase tracking-wide flex items-center">
614
+ <svg class="w-4 h-4 mr-1 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" /></svg>
615
+ 您的提示詞 (Your Prompt):
616
+ </div>
617
+ <div class="flex-1 bg-black/60 border border-gray-600 p-4 rounded-lg font-mono text-gray-200 text-sm whitespace-pre-wrap leading-relaxed shadow-[inset_0_2px_10px_rgba(0,0,0,0.5)] overflow-x-auto">${p.submission_prompt || '<span class="text-gray-600 italic">未提交 (Not Submitted)</span>'}</div>
618
+ </div>
619
+ <div class="flex flex-col">
620
+ <div class="text-sm font-bold text-green-400 mb-2 uppercase tracking-wide flex items-center">
621
+ <svg class="w-4 h-4 mr-1 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" /></svg>
622
+ 參考答案 (Reference Answer):
623
+ </div>
624
+ <div class="flex-1 bg-green-900/10 border border-green-700/50 p-4 rounded-lg font-mono text-green-300 text-sm whitespace-pre-wrap leading-relaxed shadow-[inset_0_2px_10px_rgba(34,197,94,0.1)] overflow-x-auto">${refAnswer}</div>
625
+ </div>
626
+ </div>
627
+ </div>
628
+ `;
629
+ }).join('');
630
+
631
+ return `
632
+ <div id="reference-modal" class="fixed inset-0 bg-gray-900/95 backdrop-blur-md flex items-center justify-center z-[100] p-4 transition-all duration-300">
633
+ <div class="bg-gray-800 rounded-2xl w-full max-w-5xl max-h-[90vh] flex flex-col border border-gray-700 shadow-[0_0_50px_rgba(6,182,212,0.15)] overflow-hidden scale-100 origin-center animate-fade-in-up">
634
+ <div class="bg-gradient-to-r from-blue-900 to-cyan-900 p-6 flex justify-between items-center border-b border-cyan-800">
635
+ <div>
636
+ <h3 class="text-2xl font-black text-white flex items-center space-x-3 drop-shadow-md">
637
+ <span class="text-3xl filter drop-shadow-[0_0_5px_rgba(34,211,238,0.8)]">✨</span>
638
+ <span>${levelNames[level]} - 參考答案核對</span>
639
+ </h3>
640
+ </div>
641
+ <button onclick="window.closeReferenceModal()" class="text-cyan-200 hover:text-white bg-cyan-900/50 hover:bg-cyan-800 p-2 rounded-full transition-all">
642
+ <svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg>
643
+ </button>
644
+ </div>
645
+
646
+ <div class="p-6 flex-1 overflow-y-auto space-y-6 bg-gray-900 custom-scrollbar shadow-inner">
647
+ ${listHtml}
648
+ </div>
649
+
650
+ <div class="bg-gray-800 p-5 border-t border-gray-700 text-center">
651
+ <p class="text-yellow-400 text-sm md:text-base font-bold flex flex-col md:flex-row items-center justify-center md:space-x-2">
652
+ <span class="text-xl mb-1 md:mb-0">💡</span>
653
+ <span>提示詞沒有標準答案,只要能有效修正程式,就是好的提示詞,此答案僅供參考。</span>
654
+ </p>
655
+ </div>
656
+ </div>
657
+ </div>
658
+ <style>
659
+ @keyframes fade-in-up {
660
+ 0% { opacity: 0; transform: translateY(20px) scale(0.95); }
661
+ 100% { opacity: 1; transform: translateY(0) scale(1); }
662
+ }
663
+ .animate-fade-in-up {
664
+ animation: fade-in-up 0.4s cubic-bezier(0.16, 1, 0.3, 1) forwards;
665
+ }
666
+ </style>
667
+ `;
668
+ }
669
+
670
+ window.showReferenceComparison = (level, tasks, progress) => {
671
+ const existing = document.getElementById('reference-modal');
672
+ if (existing) existing.remove();
673
+
674
+ const div = document.createElement('div');
675
+ div.innerHTML = renderReferenceModal(level, tasks, progress);
676
+
677
+ // Cleanup any existing event listeners before adding new modal to prevent issues
678
+ document.body.appendChild(div);
679
+ };
680
+
681
+ window.closeReferenceModal = () => {
682
+ const el = document.getElementById('reference-modal');
683
+ // Wrap removal in transition logic if needed, simple remove for now
684
+ if (el) el.parentElement.remove();
685
+ };
686
+
687
  // Helper to render a level group (Accordion)
688
  function renderLevelGroup(level, tasks, userProgress, levelNames) {
689
  const detailsId = `details-group-${level}`;