這次全部都在google apps script完成前端與後端程式
可以用iframe嵌入網站
測試用的電子信箱:whittaker8907@gmail.com、「分科課程:國中數學」,裡面的資料同樣都是假的
架構
後端程式碼是.gs:程式碼.gs
前端程式碼是.html:index.html、style.css.html、sctipt.js.html
debug.gs是用來測試的,執行之後會觸發searchData(),並且將參數傳入
這樣就可以模擬接收前端網頁之後的執行情況
function test6() { searchData({ mailID:"whittaker8907@gmail.com",cID:"c0101,c0102,c02,ma01,ma02"} ); }
後端程式
#1-7 function doGet()
有點類似程式進入點
當發布成網頁程式之後,連結進來就會觸發doGet(),執行HtmlService,將index.html載入執行
其中 setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)的設定
可以讓網頁程式能夠崁入其他網站
#9-14 function include(filename)
createHtmlOutputFromFile(filename),顧名思義就是從檔案建立Html輸出
可以讓前端的頁面載入Html、JavaScript、Css等前端資料
#24 var params = e;
由於是在google apps script內的傳遞
所以前端傳來的物件就直接用物件的方式來取值
var params = e; var mailID = params.mailID; var cID= params.cID;
#17-144 function searchData(e)
接受前端傳來的參數
整體而言,程式碼基本上跟之前的API練習一樣
最大的差別是在最後的 return
這也是我卡住很久的地方
後來在網路論壇上看到有人建議強制轉型再傳出
我自己的測試之後可以有2種方式
方法1,先將內容是json格式的陣列轉成json字串,然後再轉成物件
這樣對應前端的接收是物件型態
方法2.只將內容是json格式的陣列轉成json字串
前端收到的是字串型態
//return dataAll; //無法傳遞 //#1 return JSON.parse(JSON.stringify(dataAll)); //#2 //return JSON.stringify(dataAll);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
function doGet() { var output = HtmlService.createTemplateFromFile("index").evaluate().setTitle("查詢系統"); output.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);//可以將發布成html介面的程式 崁入其他網站 return output; } //讓前端可以載入 css js function include(filename) { return HtmlService.createHtmlOutputFromFile(filename).getContent(); } //----------------------------------------------------------搜尋前端傳來的值 function searchData(e) { Logger.log(e); //取得參數 //var params = e.parameter; //console.log(e); var params = e; var mailID = params.mailID;// //console.log(mailID); var cID= params.cID; //console.log(cID); var arryC = cID.split(","); //console.log(arryC[0]); var arr1 =["c0101","c0102","c02","ch01","ch02","en01","en02","ma01","ma02"]; var arr2 =["1fuCeX0Frf_N1avskAaCZ8CZ_QPjpVmzt-MyLfmQ-tCU","1Or0-pD7GBI9icsXpGB5275o0hxuyZiBBGJ__0kXii6g","1GVha6hSEvntglGnTM3iO2tZqli70T3Q0zeg3cpI1aHE","1id-dB13xyx8rpBBNPZ6mEUvz25Y60p6AfWpW2E7oBrQ","1_2zCPSrxUyKzeVwi60DTFDM_8Zw_HRfSbzxQxMARmKE","12IZpoyma-SpbLWjUqIWsdivTMPGDJFBbu-rGsr0gG9U","1h4BO_5oiyE8uKgL84-iwEcP-cElkM7QxyLs73gfOSYU","1cYIy0Ojytx-F5yFhQnoc-ggmEiFdbsAlz5kr7J22-Ws","1oi8TLFDbsX_Q7YPakbheE7VAPI272SEyQkwpsWUm0kw"]; var dataAll = [];//用來存資料 for(var cc= 0; cc < arryC.length ; cc++){ var r =arr1.indexOf(arryC[cc]); //console.log(r); var sId = arr2[r]; //console.log(sId); ///* var Sheet = SpreadsheetApp.openById(sId).getSheets()[0]; var LastRow = Sheet.getLastRow(); var LastColumn = Sheet.getLastColumn(); var data = [];//用來存資料 // 取得全部資料 var listAll = Sheet.getSheetValues(1, 1, LastRow, LastColumn); //console.log( listAll[0]); //存標題 var listA =[]; for(var j=0; j < listAll[0].length ; j++){ listA.push(listAll[0][j]); } //console.log(listA); //[listAll[0][0],listAll[0][1],listAll[0][2],listAll[0][3],listAll[0][4]]; data.push({dataload: listA }) //第1列是標題,序號由0開始,設定JSON格式{dataload: listAll[0]} //console.log(data); for(var i = 1; i < listAll.length; i++){ //第2列才是資料,序號由0開始 if(listAll[i][1] == mailID){ //電子信箱在第2欄,序號由0開始 var listOne =[]; for(var k=0; k < listAll[0].length ; k++){ if( listAll[i][k].toString().search(/drive.google.com/i) > 0){ var rr= listAll[i][k].split(","); //console.log(rr[0]); //console.log(rr[1]); if(rr.length >0){ var nHref =""; for(var m =0 ; m < rr.length ; m++){ nHref += "<a href='" + rr[m].trim() +"' target='_blank'>" + rr[m].trim() + "</a> "; } //console.log("nHref"); //console.log(nHref); listAll[i][k] =nHref; }else{ listAll[i][k] = "<a href='" + listAll[i][k]+"' target='_blank'>"+ listAll[i][k] +"</a>"; } //console.log(listAll[i][k] ); listOne.push(listAll[i][k]); }else{ listOne.push(listAll[i][k]); } } // [listAll[i][0], listAll[i][1], listAll[i][2], listAll[i][3],listAll[i][4]] data.push({dataload: listOne}); //寫入資料 } } dataAll.push({course:data}); } //顯示資料 // Logger.log(data); Logger.log(dataAll); //將資料存成JSON格式並回傳 //結果不同 //return ContentService.createTextOutput(JSON.stringify(dataAll)).setMimeType(ContentService.MimeType.JSON); //物件 //return ContentService.createTextOutput(JSON.stringify(dataAll)); //字串 //*/ //參考 https://stackoverflow.com/questions/56480228/google-script-run-withsuccesshandler-does-not-return-value //return dataAll; //無法傳遞 //#1 return JSON.parse(JSON.stringify(dataAll)); //#2 //return JSON.stringify(dataAll); } |
前端程式
Html
#6 載入jQuery
#7 載入自訂的Css檔案
#8 <base target=”_top”> 最上層顯示
#36 載入自訂的JavaScript檔案
在</body>後載入以確保前面的DOM都已經輸出
這邊用到google apps script的強制列印指令碼
<?!= ... ?>
可以將包起來的程式碼執行的結果輸出到網頁
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
<!DOCTYPE html> <html> <head> <!-- Required meta tags --> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://code.jquery.com/jquery-3.3.1.js" integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60=" crossorigin="anonymous"></script> <?!= include("style.css"); ?> <base target="_top"> </head> <body> <!--測試資料: mailID:"alice5659@gmail.com", cID:"c0102" --> <div id="d1"> <label>電子信箱:<input id="mailID" type="text" /></label><br /><br /> <label>查詢填寫紀錄</label><br /> <label><input type="checkbox" name="courses1" value="c0101" />共同課程一 :低成就學生心理特質、學習動機及教學經營實務案例</label> <label><input type="checkbox" name="courses1" value="c0102" />共同課程一 :數位資源融入學習扶助教學知能</label><br /> <label><input type="checkbox" name="courses2" value="c02" />共同課程二 :科技化評量測驗結果應用</label><br /> <label><input type="checkbox" name="courses3" value="ch01" />分科課程 :國中國語文</label> <label><input type="checkbox" name="courses3" value="ch02" />分科課程 :國小國語文</label><br /> <label><input type="checkbox" name="courses3" value="en01" />分科課程 :國中英語文</label> <label><input type="checkbox" name="courses3" value="en02" />分科課程 :國小英語文</label><br /> <label><input type="checkbox" name="courses3" value="ma01" />分科課程 :國中數學  </label> <label><input type="checkbox" name="courses3" value="ma02" />分科課程 :國小數學</label> </div> <div id="d2"> <input name="search" id="sender" onclick="sender();" type="button" value="送出" /> <input name="clean" id="cleaner" onclick="cleanAll();" type="button" value="清除資料" /> </div> <span id="search_status"></span> <dialog id="infoModal"> <p>請輸入查詢資訊!!</p> <button id="close">關閉視窗</button> </dialog> </body> <?!= include("script.js"); ?> <!-- showData --> </html> |
Css
跟之前的練習一樣
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
<style> .table, .table * { margin: 10 auto; padding: 0; font-size: 10px; font-family: "Noto Sans CJK TC", "Microsoft JhengHei", PingFang, STHeiti, sans-serif, serif; } .table { display: table; width: 100%; border-collapse: collapse; } .table-tr { display: table-row; height: 30px; } .table-th { display: table-cell; font-weight: bold; height: 100%; border: 1px solid gray; text-align: start; vertical-align: middle; background-color: #E5E5E5; } .table-td { display: table-cell; height: 100%; border: 1px solid gray; text-align: start; vertical-align: middle; padding-left: 4px; } #d1 input[type=checkbox] { padding: 0; margin-top: 10px; width: 20px; height: 20px; border: 2px solid black; border-radius: 50%; cursor: pointer; transition: 0.5s; appearance: none; /*取消預設樣式 重要!!*/ } #d1 input[type=checkbox]:checked { background-color: #DFFF47; border-color: black; width: 25px; height: 25px; } /* #d1 input[type=radio].focus, #d1 input[type=radio]:hover { width: 25px; height: 25px; } */ #d1 label { margin-top: 10px; margin-bottom: 10px; padding-top: 20px; padding-bottom: 20px; } #d2 { margin-top: 20px; margin-bottom: 20px; } /* input[type=button] { background-color: transparent; padding: 8px; color: black; cursor: pointer; } input[type=button]:hover { background-color: rgba(240, 240, 240, 0.8); } */ </style> |
JavaScript
#54-164 有修改的部分
因為是在google apps script內進行前端與後端的溝通,程式碼有一些調整
將原本在sendData()內執行的ajax程式碼,在獲取後端資料的處理程式獨立成getAll()
在sendData()的最後增加google.script.run.withSuccessHandler(getAll).searchData(data[0]),則是類似ajax溝通後端的程序
意思是將data[0]傳入在後端的searchData(),執行之後回傳值到前端的getAll()
sendData()跟getAll()共用的變數也需要拉出來宣告為廣域變數
data也因為是直接傳到searchDat()之中,所以還是陣列(內容是物件型態),也只有1筆資料,所以是data[0]
在#109-113配合後端傳回值的型態有2種處理方式
#1 前端傳來 object var obj = JSON.parse(JSON.stringify(result, dateReviver)); #2 前端傳來 json string var obj = JSON.parse(result, dateReviver);
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
<script> // var dateReviver = function (key, value) { //將日期字串轉為日期資料型態 //console.log("key", key); //console.log("value", value); var a; if (typeof value === "string") { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec( value ); //比對是否符合日期型態 //console.log(a); if (a) { var dataString = new Date( Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]) ); //console.log("dataString", dataString); var weekday = new Array(6); weekday[0] = "日"; weekday[1] = "一"; weekday[2] = "二"; weekday[3] = "三"; weekday[4] = "四"; weekday[5] = "五"; weekday[6] = "六"; var hour = dataString.getHours(); var min = dataString.getMinutes(); var sec = dataString.getSeconds(); // 轉成字串,如果低於10,前面加上'0' var hourString = hour < 10 ? "0" + hour : "" + hour; var minString = min < 10 ? "0" + min : "" + min; var secString = sec < 10 ? "0" + sec : "" + sec; var formatted_date = dataString.getFullYear() + "/" + (dataString.getMonth() + 1) + "/" + dataString.getDate() + "(" + weekday[dataString.getDay()] + ")" + " " + hourString + ":" + minString + ":" + secString; return formatted_date; } } return value; } // var arryC =[]; var cName = []; function sendData(mailID, cID) { console.log("searchData-", mailID, cID); console.log("cID"); console.log(cID); arryC =[]; cName = []; arryC = cID.split(","); console.log("arryC"); console.log(arryC); var arr1 = ["c0101","c0102","c02","ch01","ch02","en01","en02","ma01","ma02"]; var arr2 = ["「共同課程一:低成就學生心理特質、學習動機及教學經營實務案例」","「共同課程一:數位資源融入學習扶助教學知能」","「共同課程二:科技化評量測驗結果應用」","「分科課程:國中國語文」","「分科課程:國小國語文」","「分科課程:國中英語文」","「分科課程:國小英語文」","「分科課程:國中數學」","「分科課程:國小數學」"]; for (var cc = 0; cc < arryC.length; cc++) { var r = arr1.indexOf(arryC[cc]); console.log("r"); console.log(r); cName[cc] = arr2[r]; console.log("arr2[r]"); console.log(arr2[r]); console.log("cName[cc]"); console.log(cName[cc]); } console.log("cName"); console.log(cName); var sender = $("#sender"); var cleaner = $("#cleaner"); sender.attr("disabled", true); sender.val("搜尋中"); cleaner.attr("disabled", true); var data=[]; data.push({mailID:mailID,cID: cID}); console.log(data); console.log(data[0]); google.script.run.withSuccessHandler(getAll).searchData(data[0]);//後端執行searchData 回傳值到success } ///* function getAll(e) { console.log("e"); console.log(e); var sender = $("#sender"); var cleaner = $("#cleaner"); sender.attr("disabled", false); sender.val("送出"); cleaner.attr("disabled", false); var result = e; console.log("result"); console.log(typeof result); //#1 後端傳來 object var obj = JSON.parse(JSON.stringify(result, dateReviver)); //JSON.stringify解析成json字串,dateReviver將日期字串轉為日期資料型態 JSON.parse解析json字串為json物件形式 //#2 後端傳來 json string //var obj = JSON.parse(result, dateReviver); // console.log(obj); var html = ""; for (var m = 0; m < obj.length; m++) { console.log(obj[m]); console.log(cName[m]); if (obj[m].course.length == 1) { //只有1筆(標題)代表查不到資料 html += "<h3>" + (m + 1) + "-" + cName[m] + ":查無資料<h3>"; $("#search_status").html(html); //寫入Html //alert('查無資料'); $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } else { // // html += "<h3>" + (m + 1) + "-" + cName[m] + "</h3>"; html += '<div class="table"><div class="table-tr">'; //取出標題 for (var k = 0; k < obj[m].course[0].dataload.length; k++) { html += '<div class="table-th">' + obj[m].course[0].dataload[k] + "</div>"; } html += "</div>"; //<div class="table-tr"><div class="table-th">填寫日期</div><div class="table-th">電子信箱</div><div class="table-th">姓名</div><div class="table-th">服務單位</div><div class="table-th">職稱</div></div>'; //將資料寫出在Html表格,配合2次迴圈讀取每1筆資料內的所有資料 // for (var i = 1; i < obj[m].course.length; i++) { //所有筆數的資料跑迴圈 html += '<div class="table-tr">'; // for ( var j = 0; j < obj[m].course[i].dataload.length; j++ //每1筆資料內的所有資料,dataload對應回傳的JSON格式 ) { html += '<div class="table-td">' + obj[m].course[i].dataload[j] + "</div>"; } html += "</div>"; } html += "</div>"; // $("#search_status").html(html); //寫入Html $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } } } //*/ // // function sender() { var courses = []; $('input[type="checkbox"]:checked').each(function (i) { courses.push($(this).val()); //console.log($(this).val()); //console.log(i); }); //console.log("sender"); console.log(courses.toString()); var email = $('#mailID').val(); if (courses.toString() == "" || email == "") { console.log("err"); //window.alert("請確認查詢資訊"); //var infoModal = document.getElementById("infoModal"); var infoModal = $("#infoModal").get(0); //重要 https://www.fooish.com/jquery/selectors.html var closeD = $("#close"); infoModal.show(); closeD.on("click", function () { console.log("close"); infoModal.close(); }); } else { $("#search_status").html(""); sendData(email, courses.toString()); } } // function cleanAll() { $("#search_status").html(""); $("#mailID").val(""); $('input[type="checkbox"]').prop("checked", false); } // /* $(document).ready(function() { //重要 $('input[type="radio"]').on("click", function() { //绑定click 事件 //var courses1 = $("input[type=radio]:checked").val(); //console.log("courses1"); //console.log($("input[type=radio]:checked").data("checked")); var $radio = $(this); //console.log($radio.data("checked")); if ($radio.data("checked") == true) { $radio.prop("checked", false); $radio.data("checked", false); //console.log("then"); //console.log($radio.data("checked")); } else { $radio.prop("checked", true); $radio.data("checked", true); //console.log("else"); //console.log($radio.data("checked")); } //console.log($radio.data("checked")); //var courses2 = $("input[type=radio]:checked").val(); //console.log("courses2"); //console.log($("input[type=radio]:checked").data("checked")); }); // }); */ </script> |