0. 作品介紹

作者 新竹教師測試員 教育處

我想要建立一個 【學生個人成績表】


71 1 0
成績
預設封面圖 預設圖片

1. AI 提示詞

把這段指令貼給 AI,讓它幫你生成程式碼。

1.我想要建立一個 【學生個人成績表

1.google 試算表建立 【學生資料庫

2.需求說明【然後生成各科各別成績 做排序 我會去抓學生資料庫的學生成績 將全部的各科成績依照高到低排列 又可以生成自己的各別成績列表 成為一個表格上面有自己的各科成績 又將低於60分的成績變成紅色表示 下方用表格表示各科成績排序 讓每個學生自己可以看見自己的成績外也可以看到全班各科成績從高到低排序 】

3.要把它變成程式碼我要發佈



作業環境

GOOGLE 試算表

Google Apps Script 我不會寫程式 請將程式碼完全的附上

2. 資料表規則

請照下面規則建立分頁與欄位。

第1分頁: 成績資料 A 欄: 學號 B 欄: 姓名 C 欄: 國文 D 欄: 英文 E 欄: 數學 F 欄: 社會 G 欄: 自然

📄 解析結果(自動表格)

分頁:成績資料
A 欄 B 欄 C 欄 D 欄 E 欄 F 欄 G 欄
學號 姓名 國文 英文 數學 社會 自然

3. 開啟 Apps Script

從試算表開 Apps Script,才能直接用 SpreadsheetApp 讀寫資料。

  1. 試算表上方選單:擴充功能 → Apps Script
  2. 刪掉預設的程式碼(或全部選取覆蓋)
  3. 保留/建立檔案:
    • Code.gs
    • index.html

4. 貼上後端(Code.gs)

把後端程式貼到 Apps Script 的 Code.gs。

Code.gs(後端)
function doGet() {
  return HtmlService.createTemplateFromFile('Index')
    .evaluate()
    .setTitle('學生個人成績查詢系統')
    .addMetaTag('viewport', 'width=device-width, initial-scale=1');
}

function getGrades(studentId) {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("成績資料");
  
  if (!sheet) {
    throw new Error("找不到名為 '成績資料' 的工作表");
  }

  var data = sheet.getDataRange().getDisplayValues();
  var headers = data[0]; 
  var students = data.slice(1);

  // 1. 尋找該名學生
  var targetStudent = null;
  for (var i = 0; i < students.length; i++) {
    // 轉成字串比較,避免格式問題
    if (String(students[i][0]).trim() === String(studentId).trim()) {
      targetStudent = students[i];
      break;
    }
  }

  if (!targetStudent) {
    return { found: false };
  }

  // 2. 整理全班各科成績排序 (只取分數,隱藏人名)
  var subjectsData = [];
  var maxStudents = students.length; 

  // 從第 3 欄 (Index 2) 開始是科目
  for (var col = 2; col < headers.length; col++) {
    var subjectName = headers[col];
    
    // 收集該科所有分數
    var scores = students.map(function(row) {
      return parseFloat(row[col]) || 0; // 轉為數字排序
    });

    // 由高到低排序
    scores.sort(function(a, b) {
      return b - a;
    });

    subjectsData.push({
      name: subjectName,
      scores: scores
    });
  }

  // 3. 整理個人成績
  var personalGrades = [];
  for (var col = 2; col < headers.length; col++) {
    personalGrades.push({
      subject: headers[col],
      score: targetStudent[col] // 這裡保留原始文字(例如可能有"缺考")
    });
  }

  return {
    found: true,
    name: targetStudent[1],
    personal: personalGrades,
    allSubjectsRankings: subjectsData, // 這是關鍵變數名稱
    maxRows: maxStudents
  };
}
貼到 Apps Script 的 Code.gs 檔案

5. 貼上前端(index.html)

把前端程式貼到 Apps Script 的 index.html。

index.html(前端)
<!DOCTYPE html>
<html>
<head>
  <base target="_top">
  <style>
    /* --- 字體與版面設定 --- */
    @page { size: A4; margin: 10mm; }
    
    body { 
      font-family: "DFKai-SB", "BiaoKai", "標楷體", serif; 
      font-weight: bold; 
      background-color: #fff0f5; 
      color: #5d4037; 
      margin: 0; 
      padding: 15px;
      font-size: 15px;
    }

    .container { 
      max-width: 210mm; 
      margin: 0 auto; 
      background: white;
      border-radius: 20px; 
      border: 4px dashed #ffb7b2; 
      padding: 20px;
      box-shadow: 0 4px 15px rgba(255, 183, 178, 0.4); 
    }

    h1 { margin: 10px 0; font-size: 26px; text-align: center; color: #ff6f61; text-shadow: 1px 1px 0px #ffe0b2; }
    h2 { font-size: 20px; text-align: center; margin-bottom: 10px; color: #888; }
    h3 { 
      font-size: 18px; 
      background-color: #b2ebf2; 
      color: #006064;
      padding: 8px 15px; 
      border-radius: 15px;
      display: inline-block;
      margin: 20px 0 10px 0; 
      box-shadow: 2px 2px 0px #80deea;
    }

    /* --- 搜尋區塊 --- */
    .search-box { 
      text-align: center; margin-bottom: 20px; padding: 20px; 
      background: #fff9c4; border-radius: 15px; border: 2px solid #fff176;
    }
    input[type="text"] { 
      padding: 8px; width: 160px; font-size: 16px; border: 2px solid #ffcc80;
      border-radius: 10px; outline: none; font-family: "標楷體"; font-weight: bold; color: #5d4037;
    }
    button { 
      padding: 8px 20px; background-color: #ff8a65; color: white; 
      border: none; border-radius: 20px; cursor: pointer; font-size: 16px; 
      font-family: "標楷體"; font-weight: bold; box-shadow: 0 3px 0 #e64a19;
    }
    button:active { transform: translateY(3px); box-shadow: none; }

    @media print {
      .search-box { display: none; }
      body { background-color: white; padding: 0; }
      .container { border: none; box-shadow: none; }
    }

    /* --- 表格樣式 --- */
    table { 
      width: 100%; border-collapse: separate; border-spacing: 0;
      margin-top: 5px; font-size: 14px; border-radius: 10px;
      overflow: hidden; border: 2px solid #ffe0b2;
    }
    th, td { padding: 10px 5px; text-align: center; border-bottom: 1px dashed #ffe0b2; }
    th { background-color: #ffccbc; color: #bf360c; font-size: 16px; }
    tbody tr:nth-child(even) { background-color: #fff8e1; }
    
    .score-fail { color: #ff4081; font-weight: 900; background-color: #fce4ec; border-radius: 5px; padding: 2px 5px; }
    .score-normal { color: #3e2723; }

    #ranking-table th { background-color: #b39ddb; color: white; }
    #ranking-table td:first-child { background-color: #ede7f6; color: #5e35b1; font-weight: bold; } 

    #loading, #error-msg { display: none; text-align: center; margin: 20px; }
    #error-msg { color: #d32f2f; }
    #result-area { display: none; }
  </style>
</head>
<body>

  <div class="container">
    <div class="search-box">
      <h1>🐰 快樂學習 • 成績查詢 🐻</h1>
      <p style="color:#888; font-size:14px; margin-top:5px;">輸入學號來看看小主人的表現吧!</p>
      <br>
      <input type="text" id="studentId" placeholder="在此輸入學號...">
      <button onclick="searchGrades()">🔍 查詢</button>
    </div>

    <div id="loading">🐾 小狗正在幫您跑腿找資料中...</div>
    <div id="error-msg">😿 找不到這個學號,請檢查一下喔!</div>

    <div id="result-area">
      <div style="text-align: center; margin-bottom: 15px;">
        <span style="font-size: 40px;">🌟</span>
        <h1 id="print-title" style="display:inline;">成績通知單</h1>
        <span style="font-size: 40px;">🌟</span>
        <h2 id="student-name-title" style="margin-top:10px;"></h2>
      </div>

      <h3>🍓 我的成績單</h3>
      <table id="personal-table">
        <thead></thead>
        <tbody></tbody>
      </table>

      <h3>🏆 全班英雄榜 (分數排序)</h3>
      <div style="font-size:12px; color:#888; text-align:right; margin-bottom:5px;">* 僅顯示分數,不顯示姓名 *</div>
      <table id="ranking-table">
        <thead id="ranking-head"></thead>
        <tbody id="ranking-body"></tbody>
      </table>
      
      <div style="text-align: center; margin-top: 30px; font-size: 12px; color: #aaa;">
        🐾 Keep Learning, Keep Growing! 🐾
      </div>
    </div>
  </div>

  <script>
    function searchGrades() {
      var id = document.getElementById('studentId').value;
      if (!id) { alert("請輸入學號喔!🐰"); return; }

      document.getElementById('loading').style.display = 'block';
      document.getElementById('result-area').style.display = 'none';
      document.getElementById('error-msg').style.display = 'none';

      google.script.run
        .withSuccessHandler(showResult)
        .withFailureHandler(showError)
        .getGrades(id);
    }

    function showResult(data) {
      document.getElementById('loading').style.display = 'none';
      
      // 檢查資料是否存在
      if (!data || !data.found) {
        document.getElementById('error-msg').style.display = 'block';
        return;
      }

      document.getElementById('result-area').style.display = 'block';
      document.getElementById('student-name-title').innerText = "學號:" + document.getElementById('studentId').value + "  |  姓名:" + data.name;

      // --- 1. 個人成績 (修正版:分開處理 thead 和 tbody) ---
      var pTableHead = document.querySelector('#personal-table thead');
      var pTableBody = document.querySelector('#personal-table tbody');
      
      var headerHTML = "<tr><th style='width:15%'>科目</th>";
      var bodyHTML = "<tr><td><b>得分</b></td>";

      if (data.personal && data.personal.length > 0) {
        data.personal.forEach(function(item) {
          headerHTML += `<th>${item.subject}</th>`;
          
          // 確保分數轉換為數字進行比較
          var scoreNum = parseFloat(item.score);
          // 如果分數不是數字(例如缺考),視為0或不做判斷
          if (isNaN(scoreNum)) scoreNum = 0;

          var colorClass = (scoreNum < 60) ? 'score-fail' : 'score-normal';
          var icon = (scoreNum < 60) ? '🌧️' : '☀️';
          
          bodyHTML += `<td class="${colorClass}">${item.score} <span style='font-size:10px'>${icon}</span></td>`;
        });
      }
      
      headerHTML += "</tr>";
      bodyHTML += "</tr>";
      
      pTableHead.innerHTML = headerHTML;
      pTableBody.innerHTML = bodyHTML;

      // --- 2. 全班排序合併總表 ---
      var rankHead = document.getElementById('ranking-head');
      var rankBody = document.getElementById('ranking-body');
      
      var headHtml = "<tr><th style='width:50px;'>名次</th>";
      if (data.allSubjectsRankings) {
        data.allSubjectsRankings.forEach(function(subj) {
          headHtml += `<th>${subj.name}</th>`;
        });
      }
      headHtml += "</tr>";
      rankHead.innerHTML = headHtml;

      var bodyHtml = "";
      if (data.maxRows) {
        for (var i = 0; i < data.maxRows; i++) {
          var rankDisplay = i + 1;
          if (i === 0) rankDisplay = "👑 1";
          if (i === 1) rankDisplay = "🥈 2";
          if (i === 2) rankDisplay = "🥉 3";

          var rowHtml = `<tr><td>${rankDisplay}</td>`;
          
          data.allSubjectsRankings.forEach(function(subj) {
            var score = (subj.scores[i] !== undefined) ? subj.scores[i] : "";
            rowHtml += `<td>${score}</td>`;
          });
          
          rowHtml += "</tr>";
          bodyHtml += rowHtml;
        }
      }
      rankBody.innerHTML = bodyHtml;
    }

    function showError(e) {
      document.getElementById('loading').style.display = 'none';
      alert("發生錯誤囉: " + e.message);
    }
  </script>
</body>
</html>
貼到 Apps Script 的 index.html 檔案

6. 部署

部署成 Web App 後,就會拿到可分享網址。

  1. Apps Script 右上:部署 → 新部署
  2. 類型選:Web app
  3. 執行身分:你
  4. 存取權限:任何人
  5. 完成後複製網址

💬 評論區

老師們的交流與提問

載入評論中...