Lashtw commited on
Commit
5adc53b
·
verified ·
1 Parent(s): 7a399ee

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +74 -19
index.html CHANGED
@@ -421,6 +421,11 @@
421
  <label for="edit-sentence-zh-input" class="block text-sm font-semibold text-gray-700 mb-1">中文例句</label>
422
  <input id="edit-sentence-zh-input" type="text" class="w-full p-3 border border-gray-300 rounded-lg text-lg">
423
  </div>
 
 
 
 
 
424
  </div>
425
  <div class="flex justify-end gap-4 mt-8">
426
  <button type="button" id="cancel-edit-btn" class="px-6 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 transition-colors">取消</button>
@@ -656,6 +661,7 @@
656
  const editChineseInput = document.getElementById('edit-chinese-input');
657
  const editSentenceEnInput = document.getElementById('edit-sentence-en-input');
658
  const editSentenceZhInput = document.getElementById('edit-sentence-zh-input');
 
659
  const saveEditBtn = document.getElementById('save-edit-btn');
660
  const cancelEditBtn = document.getElementById('cancel-edit-btn');
661
  const shareModal = document.getElementById('share-modal');
@@ -786,6 +792,7 @@
786
  editChineseInput.value = word.chinese;
787
  editSentenceEnInput.value = word.sentence?.en || '';
788
  editSentenceZhInput.value = word.sentence?.zh || '';
 
789
  editWordModal.classList.remove('hidden');
790
  } else if (button.classList.contains('delete-btn')) {
791
  indexToDelete = index;
@@ -800,15 +807,26 @@
800
  const newChinese = editChineseInput.value.trim();
801
  const newSentenceEn = editSentenceEnInput.value.trim();
802
  const newSentenceZh = editSentenceZhInput.value.trim();
 
803
 
804
  if (index >= 0 && newEnglish && newChinese) {
805
  words[index].english = newEnglish;
806
  words[index].chinese = newChinese;
 
 
807
  if (newSentenceEn && newSentenceZh) {
808
- words[index].sentence = { en: newSentenceEn, zh: newSentenceZh };
 
 
 
 
 
 
 
809
  } else {
810
  delete words[index].sentence;
811
  }
 
812
  saveWordsToStorage();
813
  renderWordList();
814
  editWordModal.classList.add('hidden');
@@ -956,7 +974,7 @@
956
  sentenceZhDisplay.textContent = `(${card.sentence.zh})`;
957
  sentenceZhDisplay.classList.add('hidden');
958
  toggleTranslationBtn.textContent = '顯示翻譯';
959
- backText = card.english;
960
  answerInput.placeholder = "請填入空格中的單字...";
961
  break;
962
  }
@@ -1000,11 +1018,12 @@
1000
  } else {
1001
  wordPool = [...words];
1002
  }
1003
-
 
1004
  if (mode === 'sentence-cloze') {
1005
- wordsForCurrentMode = wordPool.filter(w => w.sentence && w.sentence.en && w.sentence.zh);
1006
  if (wordsForCurrentMode.length === 0) {
1007
- alert("題庫中沒有附帶例句的單字可供此模式使用。");
1008
  return;
1009
  }
1010
  } else if (mode === 'review') {
@@ -1076,7 +1095,13 @@
1076
  let effectiveMode = isSpeed ? currentSpeedQuestionType : (currentMode === 'hard' ? 'zh-en' : currentMode);
1077
  let rawAnswer;
1078
  switch (effectiveMode) {
1079
- case 'zh-en': case 'listen': case 'sentence-cloze':
 
 
 
 
 
 
1080
  rawAnswer = card.english;
1081
  answerLang = 'en';
1082
  break;
@@ -1085,7 +1110,13 @@
1085
  answerLang = 'zh';
1086
  break;
1087
  }
1088
- correctAnswer = rawAnswer.replace(/[\((\[【].*?[\))\]】]/g, "").trim();
 
 
 
 
 
 
1089
  }
1090
 
1091
  let isCorrect;
@@ -1467,7 +1498,8 @@
1467
  aiProgressContainer.classList.add('hidden');
1468
  }
1469
  });
1470
-
 
1471
  async function callGeminiToParseText(text) {
1472
  const apiKey = apiKeyInput.value.trim();
1473
  if (!apiKey) {
@@ -1482,9 +1514,10 @@
1482
  請分析以下從英文單字學習講義擷取的文字。你的任務是辨識出每一個單字條目,並為每個條目提取以下資訊:
1483
  1. "english": 完整的英文單字,包含詞性標註,例如 "yesterday (adv.)" 或 "study (v.)"。
1484
  2. "chinese": 對應的中文翻譯。
1485
- 3. "sentence": 一個包含例句的物件。這個物件應該有兩個屬性:
1486
  - "en": 英文例句。請將該條目的主要英文單字(不含詞性)替換成 "___"。
1487
  - "zh": 完整的中文例句翻譯。
 
1488
 
1489
  規則:
1490
  - 如果一個單字條目有多個例句,請只選擇第一個或最能代表該單字用法的例句。
@@ -1514,7 +1547,8 @@
1514
  type: "OBJECT",
1515
  properties: {
1516
  en: { type: "STRING" },
1517
- zh: { type: "STRING" }
 
1518
  }
1519
  }
1520
  }
@@ -1559,7 +1593,8 @@
1559
  parsePdfBtn.disabled = false;
1560
  }
1561
  }
1562
-
 
1563
  function showParseConfirmation(parsedWords) {
1564
  parseResultsContainer.innerHTML = '';
1565
  selectAllCheckbox.checked = true;
@@ -1576,6 +1611,7 @@
1576
  <div class="mt-2 pt-2 border-t border-gray-200">
1577
  <p class="text-sm text-gray-600"><strong>例句 (英):</strong> ${word.sentence.en}</p>
1578
  <p class="text-sm text-gray-600"><strong>例句 (中):</strong> ${word.sentence.zh}</p>
 
1579
  </div>
1580
  ` : ''}
1581
  </div>
@@ -1709,8 +1745,10 @@
1709
  if (!card) return;
1710
  const questionType = currentMode === 'speed' ? currentSpeedQuestionType : (currentMode === 'hard' ? 'zh-en' : currentMode);
1711
  let correctAnswer;
 
1712
  switch (questionType) {
1713
- case 'zh-en': case 'listen': case 'sentence-cloze': correctAnswer = card.english.replace(/[\((\[【].*?[\))\]】]/g, "").trim(); break;
 
1714
  case 'en-zh': correctAnswer = card.chinese.replace(/[\((\[【].*?[\))\]】]/g, "").trim(); break;
1715
  default: return;
1716
  }
@@ -2023,14 +2061,32 @@
2023
  incorrectCount: word.incorrectCount || 0
2024
  }));
2025
  } else {
 
2026
  const defaultWords = [
2027
- { english: 'yesterday (adv.)', chinese: '昨天', sentence: { en: 'I walked to school ___.', zh: '我昨天走路上學。' } },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2028
  { english: 'study (v.)', chinese: '研讀' },
2029
- { english: 'jog (v.)', chinese: '慢跑' }, { english: 'watch (v.)', chinese: '觀看' },
2030
- { english: 'last (adj.)', chinese: '前一個的' }, { english: 'death (n.)', chinese: '死亡' },
2031
- { english: 'a few (adj.)', chinese: '一些' }, { english: 'ago (adv.)', chinese: '以前' },
2032
- { english: 'parents (n.)', chinese: '父母親' }, { english: 'were (v.)', chinese: '是 (複數/you/we/they)' },
2033
- { english: 'was (v.)', chinese: '是 (單數/I/he/she)' }
2034
  ];
2035
  words = defaultWords.map(word => ({ ...word, proficiency: 0, incorrectCount: 0 }));
2036
  saveWordsToStorage();
@@ -2075,4 +2131,3 @@
2075
  </script>
2076
  </body>
2077
  </html>
2078
-
 
421
  <label for="edit-sentence-zh-input" class="block text-sm font-semibold text-gray-700 mb-1">中文例句</label>
422
  <input id="edit-sentence-zh-input" type="text" class="w-full p-3 border border-gray-300 rounded-lg text-lg">
423
  </div>
424
+ <!-- 【修改】新增例句答案輸入框 -->
425
+ <div>
426
+ <label for="edit-sentence-answer-input" class="block text-sm font-semibold text-gray-700 mb-1">例句正確答案 (克漏字用)</label>
427
+ <input id="edit-sentence-answer-input" type="text" class="w-full p-3 border border-gray-300 rounded-lg text-lg bg-yellow-50" placeholder="例如 watches, jogging...">
428
+ </div>
429
  </div>
430
  <div class="flex justify-end gap-4 mt-8">
431
  <button type="button" id="cancel-edit-btn" class="px-6 py-2 bg-gray-200 text-gray-800 rounded-lg hover:bg-gray-300 transition-colors">取消</button>
 
661
  const editChineseInput = document.getElementById('edit-chinese-input');
662
  const editSentenceEnInput = document.getElementById('edit-sentence-en-input');
663
  const editSentenceZhInput = document.getElementById('edit-sentence-zh-input');
664
+ const editSentenceAnswerInput = document.getElementById('edit-sentence-answer-input'); // 【新增】
665
  const saveEditBtn = document.getElementById('save-edit-btn');
666
  const cancelEditBtn = document.getElementById('cancel-edit-btn');
667
  const shareModal = document.getElementById('share-modal');
 
792
  editChineseInput.value = word.chinese;
793
  editSentenceEnInput.value = word.sentence?.en || '';
794
  editSentenceZhInput.value = word.sentence?.zh || '';
795
+ editSentenceAnswerInput.value = word.sentence?.answer || ''; // 【新增】
796
  editWordModal.classList.remove('hidden');
797
  } else if (button.classList.contains('delete-btn')) {
798
  indexToDelete = index;
 
807
  const newChinese = editChineseInput.value.trim();
808
  const newSentenceEn = editSentenceEnInput.value.trim();
809
  const newSentenceZh = editSentenceZhInput.value.trim();
810
+ const newSentenceAnswer = editSentenceAnswerInput.value.trim(); // 【新增】
811
 
812
  if (index >= 0 && newEnglish && newChinese) {
813
  words[index].english = newEnglish;
814
  words[index].chinese = newChinese;
815
+
816
+ // 【修改】更新 sentence 物件
817
  if (newSentenceEn && newSentenceZh) {
818
+ words[index].sentence = {
819
+ en: newSentenceEn,
820
+ zh: newSentenceZh
821
+ };
822
+ // 只有在答案存在時才加入
823
+ if (newSentenceAnswer) {
824
+ words[index].sentence.answer = newSentenceAnswer;
825
+ }
826
  } else {
827
  delete words[index].sentence;
828
  }
829
+
830
  saveWordsToStorage();
831
  renderWordList();
832
  editWordModal.classList.add('hidden');
 
974
  sentenceZhDisplay.textContent = `(${card.sentence.zh})`;
975
  sentenceZhDisplay.classList.add('hidden');
976
  toggleTranslationBtn.textContent = '顯示翻譯';
977
+ backText = card.sentence.answer || card.english; // 【修改】背面顯示正確答案
978
  answerInput.placeholder = "請填入空格中的單字...";
979
  break;
980
  }
 
1018
  } else {
1019
  wordPool = [...words];
1020
  }
1021
+
1022
+ // 【修改】過濾克漏字模式的單字,必須包含 sentence 和 answer
1023
  if (mode === 'sentence-cloze') {
1024
+ wordsForCurrentMode = wordPool.filter(w => w.sentence && w.sentence.en && w.sentence.zh && w.sentence.answer);
1025
  if (wordsForCurrentMode.length === 0) {
1026
+ alert("題庫中沒有附帶完整例句(包含克漏字答案)的單字可供此模式使用。");
1027
  return;
1028
  }
1029
  } else if (mode === 'review') {
 
1095
  let effectiveMode = isSpeed ? currentSpeedQuestionType : (currentMode === 'hard' ? 'zh-en' : currentMode);
1096
  let rawAnswer;
1097
  switch (effectiveMode) {
1098
+ // 【修改】此處是核心邏輯修改
1099
+ case 'sentence-cloze':
1100
+ // 直接使用 sentence.answer 作為正確答案
1101
+ rawAnswer = card.sentence.answer;
1102
+ answerLang = 'en';
1103
+ break;
1104
+ case 'zh-en': case 'listen':
1105
  rawAnswer = card.english;
1106
  answerLang = 'en';
1107
  break;
 
1110
  answerLang = 'zh';
1111
  break;
1112
  }
1113
+ // 如果 rawAnswer 存在才進行處理
1114
+ if (rawAnswer) {
1115
+ correctAnswer = rawAnswer.replace(/[\((\[【].*?[\))\]】]/g, "").trim();
1116
+ } else {
1117
+ // 預防性程式碼,如果找不到答案就判定為錯
1118
+ correctAnswer = `__NO_ANSWER_DEFINED__${Date.now()}`;
1119
+ }
1120
  }
1121
 
1122
  let isCorrect;
 
1498
  aiProgressContainer.classList.add('hidden');
1499
  }
1500
  });
1501
+
1502
+ // 【修改】升級 AI Prompt 和 Schema
1503
  async function callGeminiToParseText(text) {
1504
  const apiKey = apiKeyInput.value.trim();
1505
  if (!apiKey) {
 
1514
  請分析以下從英文單字學習講義擷取的文字。你的任務是辨識出每一個單字條目,並為每個條目提取以下資訊:
1515
  1. "english": 完整的英文單字,包含詞性標註,例如 "yesterday (adv.)" 或 "study (v.)"。
1516
  2. "chinese": 對應的中文翻譯。
1517
+ 3. "sentence": 一個包含例句的物件。這個物件應該有以下三個屬性:
1518
  - "en": 英文例句。請將該條目的主要英文單字(不含詞性)替換成 "___"。
1519
  - "zh": 完整的中文例句翻譯。
1520
+ - "answer": 在 "en" 屬性的 "___" 空格中,文法正確的答案。例如,如果單字是 "watch",例句是 "He ___ TV.",那 "answer" 就應該是 "watches"。
1521
 
1522
  規則:
1523
  - 如果一個單字條目有多個例句,請只選擇第一個或最能代表該單字用法的例句。
 
1547
  type: "OBJECT",
1548
  properties: {
1549
  en: { type: "STRING" },
1550
+ zh: { type: "STRING" },
1551
+ answer: { type: "STRING" } // 新增 answer 欄位
1552
  }
1553
  }
1554
  }
 
1593
  parsePdfBtn.disabled = false;
1594
  }
1595
  }
1596
+
1597
+ // 【修改】更新 AI 結果預覽畫面
1598
  function showParseConfirmation(parsedWords) {
1599
  parseResultsContainer.innerHTML = '';
1600
  selectAllCheckbox.checked = true;
 
1611
  <div class="mt-2 pt-2 border-t border-gray-200">
1612
  <p class="text-sm text-gray-600"><strong>例句 (英):</strong> ${word.sentence.en}</p>
1613
  <p class="text-sm text-gray-600"><strong>例句 (中):</strong> ${word.sentence.zh}</p>
1614
+ ${word.sentence.answer ? `<p class="text-sm text-blue-700 font-semibold"><strong>克漏字答案:</strong> ${word.sentence.answer}</p>` : ''}
1615
  </div>
1616
  ` : ''}
1617
  </div>
 
1745
  if (!card) return;
1746
  const questionType = currentMode === 'speed' ? currentSpeedQuestionType : (currentMode === 'hard' ? 'zh-en' : currentMode);
1747
  let correctAnswer;
1748
+ // 【修改】提示功能現在也使用正確的答案來源
1749
  switch (questionType) {
1750
+ case 'sentence-cloze': correctAnswer = card.sentence.answer; break;
1751
+ case 'zh-en': case 'listen': correctAnswer = card.english.replace(/[\((\[【].*?[\))\]】]/g, "").trim(); break;
1752
  case 'en-zh': correctAnswer = card.chinese.replace(/[\((\[【].*?[\))\]】]/g, "").trim(); break;
1753
  default: return;
1754
  }
 
2061
  incorrectCount: word.incorrectCount || 0
2062
  }));
2063
  } else {
2064
+ // 【修改】使用新的預設單字,展示文法感知功能
2065
  const defaultWords = [
2066
+ {
2067
+ english: 'watch (v.)',
2068
+ chinese: '觀看',
2069
+ sentence: {
2070
+ en: 'Mike usually ___ TV on Mondays.',
2071
+ zh: '麥克通常在週一會看電視。',
2072
+ answer: 'watches'
2073
+ }
2074
+ },
2075
+ {
2076
+ english: 'jog (v.)',
2077
+ chinese: '慢跑',
2078
+ sentence: {
2079
+ en: 'She is ___ in the park now.',
2080
+ zh: '她現在正在公園慢跑。',
2081
+ answer: 'jogging'
2082
+ }
2083
+ },
2084
  { english: 'study (v.)', chinese: '研讀' },
2085
+ { english: 'last (adj.)', chinese: '前一個的' },
2086
+ { english: 'death (n.)', chinese: '死亡' },
2087
+ { english: 'a few (adj.)', chinese: '一些' },
2088
+ { english: 'ago (adv.)', chinese: '以前' },
2089
+ { english: 'parents (n.)', chinese: '父母親' },
2090
  ];
2091
  words = defaultWords.map(word => ({ ...word, proficiency: 0, incorrectCount: 0 }));
2092
  saveWordsToStorage();
 
2131
  </script>
2132
  </body>
2133
  </html>