let jsonData = []; let currentPage = 1; let rowsPerPage = 15; let filteredData = []; const SHEET_ID = "1ZNh_Hh_2Mm9mVbUY_MS_Za-vmZpvrVmh9lp5RBSXTy0"; const SHEET_URL = `https://docs.google.com/spreadsheets/d/${SHEET_ID}/gviz/tq?tqx=out:json`; fetch(SHEET_URL) .then(response => response.text()) .then(data => { const jsonText = data.substring(47, data.length - 2); // 去除 Google API 包裝 const json = JSON.parse(jsonText); jsonData = json.table.rows.slice(1).map(row => ({ "年度": row.c[6]?.v || "", "學院": row.c[0]?.v || "", "系所": row.c[1]?.v || "", "姓名": row.c[2]?.v || "", "研修國家": row.c[5]?.v || "", "研修學校": row.c[4]?.v || "", "研修類型": row.c[3]?.v || "", "學期報告": formatCustomLink(row.c[7], "學期報告"), "出國心得": formatCustomLink(row.c[8], "出國心得") })); populateFilters(jsonData); search(); }) .catch(error => console.error("讀取 Google Sheets 失敗:", error)); function formatCustomLink(cell, defaultText) { if (!cell || !cell.v) return "無資料"; // **如果 cell 為空或沒有值,顯示「無資料」** let text = cell.v; // **顯示的文字** let link = cell.p?.link || ""; // **Google Sheets 內的超連結** // **如果 `p.link` 沒有值,則檢查 `cell.v` 是否為網址** if (!link && typeof text === "string" && text.startsWith("http")) { link = text; } return link ? `` : text; } document.getElementById("search-btn").addEventListener("click", search); // 讓輸入或切換篩選時自動查詢(可依需要保留/移除) ["search-input", "country-filter", "college-filter", "type-filter", "year-filter"] .forEach(id => { const el = document.getElementById(id); if (!el) return; el.addEventListener(el.tagName === "INPUT" ? "input" : "change", () => { currentPage = 1; search(); }); }); function populateFilters(data) { const countryFilter = document.getElementById("country-filter"); const collegeFilter = document.getElementById("college-filter"); const typeFilter = document.getElementById("type-filter"); const yearFilter = document.getElementById("year-filter"); const unique = arr => [...new Set(arr.filter(v => v !== "" && v != null))]; // 年度:去重後依數字(或字串)由新到舊排序 const years = unique(data.map(item => item.年度)) .sort((a, b) => { const na = Number(a), nb = Number(b); // 兩者皆為數字則以數字排序;否則以字串排序 if (!Number.isNaN(na) && !Number.isNaN(nb)) return nb - na; return String(b).localeCompare(String(a), "zh-Hant"); }); const countries = unique(data.map(item => item.研修國家)).sort((a, b) => a.localeCompare(b, "zh-Hant")); const colleges = unique(data.map(item => item.學院)).sort((a, b) => a.localeCompare(b, "zh-Hant")); const types = unique(data.map(item => item.研修類型)).sort((a, b) => a.localeCompare(b, "zh-Hant")); const appendOptions = (selectEl, values) => { if (!selectEl) return; // 保留第一個「全部…」選項 values.forEach(v => { const option = document.createElement("option"); option.value = v; option.textContent = v; selectEl.appendChild(option); }); }; appendOptions(countryFilter, countries); appendOptions(collegeFilter, colleges); appendOptions(typeFilter, types); appendOptions(yearFilter, years); } function search() { const keyword = document.getElementById("search-input").value.trim(); const selectedCountry = document.getElementById("country-filter").value; const selectedCollege = document.getElementById("college-filter").value; const selectedType = document.getElementById("type-filter").value; const selectedYear = document.getElementById("year-filter").value; filteredData = jsonData.filter(entry => { const keywordMatch = keyword === "" || Object.values(entry).some(value => String(value).includes(keyword)); const countryMatch = selectedCountry === "" || entry.研修國家 === selectedCountry; const collegeMatch = selectedCollege === "" || entry.學院 === selectedCollege; const typeMatch = selectedType === "" || entry.研修類型 === selectedType; const yearMatch = selectedYear === "" || String(entry.年度) === String(selectedYear); return keywordMatch && countryMatch && collegeMatch && typeMatch && yearMatch; }); currentPage = 1; displayResults(); } function displayResults() { const tableBody = document.getElementById("table-body"); const totalCount = document.getElementById("total-count"); const totalPages = Math.ceil(filteredData.length / rowsPerPage); tableBody.innerHTML = ""; // 清空舊結果 const start = (currentPage - 1) * rowsPerPage; const end = start + rowsPerPage; const pageData = filteredData.slice(start, end); pageData.forEach(item => { const row = document.createElement("tr"); row.innerHTML = ` $调颈迟别尘.年度皑 $调颈迟别尘.学院皑 $调颈迟别尘.系所皑 $调颈迟别尘.姓名皑 $调颈迟别尘.研修国家皑 $调颈迟别尘.研修学校皑 $调颈迟别尘.研修类型皑 $调颈迟别尘.学期报告皑 $调颈迟别尘.出国心得皑`; tableBody.appendChild(row); }); if (totalCount) { totalCount.textContent = `共 ${filteredData.length} 筆`; } updatePagination(totalPages); } function updatePagination(totalPages) { if (totalPages < 1) return; const pageNumbers = document.getElementById("page-numbers"); pageNumbers.innerHTML = ""; const maxPagesToShow = 5; let startPage = Math.max(1, currentPage - Math.floor(maxPagesToShow / 2)); let endPage = Math.min(totalPages, startPage + maxPagesToShow - 1); if (endPage - startPage + 1 < maxPagesToShow) { startPage = Math.max(1, endPage - maxPagesToShow + 1); } const mkBtn = (text, disabled, handler, extraClass) => { const btn = document.createElement("button"); btn.textContent = text; btn.classList.add("page-btn"); if (extraClass) btn.classList.add(extraClass); btn.disabled = !!disabled; btn.addEventListener("click", handler); return btn; }; pageNumbers.appendChild(mkBtn("?", currentPage === 1, () => { currentPage = 1; displayResults(); })); pageNumbers.appendChild(mkBtn("?", currentPage === 1, () => { if (currentPage > 1) { currentPage--; displayResults(); } })); for (let i = startPage; i <= endPage; i++) { const btn = mkBtn(String(i), false, () => { currentPage = i; displayResults(); }); if (i === currentPage) btn.classList.add("active"); pageNumbers.appendChild(btn); } pageNumbers.appendChild(mkBtn("?", currentPage === totalPages, () => { if (currentPage < totalPages) { currentPage++; displayResults(); } })); pageNumbers.appendChild(mkBtn("?", currentPage === totalPages, () => { currentPage = totalPages; displayResults(); })); } // **阻止 F12、Ctrl+Shift+I、Ctrl+Shift+J、Ctrl+U** document.addEventListener("keydown", function(event) { if ( event.key === "F12" || (event.ctrlKey && event.shiftKey && (event.key === "I" || event.key === "J")) || (event.ctrlKey && event.key === "U") ) { event.preventDefault(); } }); // **禁用右鍵** document.addEventListener("contextmenu", function(event) { event.preventDefault(); });