if (m < 10){ m = "0" + m } let s = (seconds % 3600) % 60 if (s < 10){ s = "0" + s } return [h, m, s].join(":") } let data = { message: null, submitting: false, start: false, title: "แบบทดสอบออนไลน กอนเรียน วิชายุทธวิธี", countDown: null, counter: 0, email: "", config: {}, questions: null, emails: [], selectedQuestions: null } let computed = { timer: function(){ return formatTime(this.counter) }
} let methods = { startQuiz: function(){ if (this.email === ""){ this.message = { type: "Error", message: "กรุณากรอกเลขที่กองพัน" } }else if(this.emails.includes(this.email.toString().trim().toLowerCase())){ this.message = { type: "Error", message: `เลขที่ ${this.email} ทำแบบทดสอบไปแลว.` } }else{ this.start = true this.counter = this.config.time * 60 let selectedQuestions = randomSelectArray(this.questions, this.config.count) selectedQuestions.forEach(function(item){ item.disabled = false item.selected = [] item.correct = true }) this.selectedQuestions = selectedQuestions this.countDown = setInterval(function(){ this.counter -= 1 if (this.counter === 0){
clearInterval(this.countDown) this.endQuiz() } }.bind(this), 1000) } }, endQuiz: function(){ this.start = false this.submitting = true clearInterval(this.countDown) let totalScore = 0 let tempArray this.selectedQuestions.forEach((q)=>{ if (typeof(q.selected) !== "object"){ tempArray = [q.selected] }else{ tempArray = [... q.selected] } if (tempArray.join() == q.corrects.join()){ console.log(true) q.correct = true totalScore += q.point }else{ console.log(false) q.correct = false }
q.disabled = true }) let result = [this.email,totalScore] google.script.run .withSuccessHandler(function(){ this.submitting = false this.message = { type: "Confirmation", message: `ขอบคุณ , ${this.email}, คุณทำคะแแนได ${totalScore}.ขอที่ไมถูกตองจะถูกเนนดวยสีแดง` } this.emails = [...this.emails, this.email] this.email = "" }.bind(this)) .withFailureHandler(function(e){ this.submitting = false this.message = { type: "Error", message: e.message } }.bind(this)) .saveData(result) }, closeMessageBox: function(){ this.message = null }
} google.script.run .withSuccessHandler(function(appData){ data.config = appData.config data.questions = appData.questions data.emails = appData.emails new Vue({ el: "#app", data, computed, methods }) }) .getData() </script> index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <!-- <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> -->
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> <link rel="stylesheet" href="https://www.w3schools.com/lib/w3-theme-green.css"> <?!= include("css") ?> </head> <body> <div id="app" v-cloak> <header class="w3-card w3-theme"> <div class="w3-bar"> <p class="w3-bar-item w3-mobile"><b>{{title}}</b></p> <p class="w3-bar-item w3-tag w3-round w3-theme-l5 w3-margin-right w3-mobile"> <input class="w3-mobile w3-center" type="email" style="border: none; background: transparent; outline: none; padding: 0px;" v-model="email" placeholder="เลขที่กองพัน 4 หลัก" :disabled="start" required > </p> <template v-if="!start"> <p class="w3-bar-item w3-button w3-round w3-theme-d4 w3-margin-right w3-mobile" @click="startQuiz" >เริ่มทำแบบทดสอบ</p> </template> <template v-else>
<p class="w3-bar-item w3-button w3-round w3-theme-d4 w3-margin-right w3-mobile" @click="endQuiz" >สงคำตอบ</p> <p class="w3-bar-item w3-tag w3-round w3-theme-l4 w3-margin-right w3-mobile" >จำนวน {{config.count}} ขอ</p> <p class="w3-bar-item w3-tag w3-round w3-theme-l4 w3-margin-right w3- mobile">{{timer}}</p> </template> </div> </header> <main v-if="selectedQuestions"> <div class="w3-card w3-container w3-padding" v-for="(q, qIndex) in selectedQuestions" :key="q.id"> <label class="w3-block w3-mobile w3-container w3-padding w3-round" :class="q.correct ? 'w3- theme-l3': 'w3-pale-red'"> <span class="w3-tag w3-theme w3-round">{{qIndex + 1}} </span> <b>{{q.title}}</b> <span class="w3-tag w3-theme-l4 w3-round">{{q.point}}</span> <span v-if="q.corrects.length > 1" class="w3-tag w3-red w3-round">M</span> <span class="w3-tag w3-theme-l4 w3-round" v-else>S</span> </label> <template v-if="q.corrects.length > 1"> <template v-for="(option, i) in q.options"> <label class="w3-block w3-mobile"> <input class="w3-check" type="checkbox" v-model="q.selected" :name="q.id" :value="option" :disabled="q.disabled"> {{option}}</label>
</template> </template> <template v-else> <template v-for="(option, i) in q.options"> <label class="w3-block w3-mobile"> <input class="w3-radio" type="radio" v-model="q.selected" :name="q.id" :value="option" :disabled="q.disabled"> {{option}}</label> </template> </template> </div> </main> <footer v-if="selectedQuestions"> <div class="w3-container w3-theme"> <p class="w3-center w3-mobile">พัฒนา โดย ร.ท.พิษณุ ปนชาติ แผนกยุทธวิธี กองการศึกษา โรงเรียนนาย สิบทหารบก</p> </div> </footer> <div class="message" v-if="message"> <div class="w3-card"> <div class="w3-padding" :class="message.type=='Error' ? 'w3-red': 'w3-theme'"> {{message.type}} </div>
<div class="w3-padding"> <p class="w3-small">{{message.message}}</p> <button class="w3-button w3-round" :class="message.type=='Error' ? 'w3-red': 'w3-theme'" @click="closeMessageBox">OK</button> </div> </div> </div> <div class="message loading" v-if="submitting"> </div> </div> <?!= include("js") ?> </body> </html> css.html <style> #app .message { width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; padding: 0px; margin: 0px;
z-index: 99; background: rgba(255, 255, 255, 0.6); display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-orient: vertical; -webkit-box-direction: normal; -ms-flex-direction: column; flex-direction: column; -webkit-box-pack: center; -ms-flex-pack: center; justify-content: center; -webkit-box-align: center; -ms-flex-align: center; align-items: center; } #app .message > div { max-width: 500px; min-width: 300px; background: #fff; } #app header, #app footer { } #app header{ position: fixed;
width: 100%; top: 0px; left: 0px; z-index: 88; } #app main { display: -ms-grid; display: grid; -ms-grid-columns: 1fr; grid-template-columns: 1fr; grid-gap: 16px; padding: 16px 0px; margin-top: 70px; } #app main table { width: 100%; } #app main td { text-align: center; } #app main td div { display: -webkit-box; display: -ms-flexbox; display: flex; -webkit-box-pack: center; -ms-flex-pack: center;
justify-content: center; } [v-cloak], .loading{ width: 100%; height: 100%; background: rgba(255, 255, 255, 0.7); position: fixed; display: block; } [v-cloak] * { display: none; } [v-cloak]::before, .loading::before{ content: ''; width: 4em; height: 4em; border: 5px solid #eee; border-top-color: #4CAF50; position: absolute; border-radius: 50%; left: 50%; top: 50%; margin-top: -2em; margin-left: -2em;
-webkit-animation: spin 1s linear infinite; animation: spin 1s linear infinite; } @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } @keyframes spin { 0% { -webkit-transform: rotate(0deg); transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); transform: rotate(360deg); } } @media screen and (max-width: 750px) { #app header{ position: relative;
} #app main{ margin: 0px; } } /*# sourceMappingURL=style.css.map */ </style> Sidebar.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <!-- <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> --> <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> <link rel="stylesheet" href="https://www.w3schools.com/lib/w3-theme-green.css"> <?!= include("css") ?> </head>
<body> <div id="app" v-cloak> <form @submit.prevent="submit" class="w3-panel"> <label for="quiz-count">จำนวนขอ</label> <input class="w3-input w3-margin-bottom" id="quiz-count" name="quiz-count" v-model="config.count" type="number" min=1 max=50 placeholder="Between 1 and 50" required > <label for="quiz-time">เวลาทำแบบทดสอบ <span class="w3-small">(min)</span></label> <input class="w3-input w3-margin-bottom" id="quiz-time" name="quiz-count" v-model="config.time" type="number" min=1 max=120 placeholder="Between 1 and 120 minutes" required >
<input type="submit" class="w3-button w3-theme w3-round" value="Save"> <p class="w3-small w3-text-theme">{{message}}</p> </form> </div> <script> let data = { title: "Quiz Sheet App", submitting: false, message: "", config: { count: 10, time: 30, } } let methods = { submit: function(){ this.message = "Saving..." this.submitting = true google.script.run .withSuccessHandler(function(){ this.message = "Configuration saved." }.bind(this)) .withFailureHandler(function(e){ this.message = e.message })
.saveConfiguration(this.config) this.submitting = false } } google.script.run .withSuccessHandler(function(config){ data.config = config data.message = "Configuration loaded." new Vue({ el: "#app", data, methods }) }) .withFailureHandler(function(e){ }) .loadConfiguration() </script> </body> </html>
Line Hackathon27 ระบบ มอบงาน-สงงานออนไลน แสดงผลผาน line Hackathon27 Code
Code.gs function doGet() { return HtmlService.createTemplateFromFile('index').evaluate() .setTitle('PSN work NCO') .setFaviconUrl('https://sv1.picz.in.th/images/2022/11/02/v5V9zI.png') .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL) } /** เรียกเชื่อม include */ function include(file){ return HtmlService.createHtmlOutputFromFile(file).getContent()} /** เรียก URL */ function getURL() { return url = ScriptApp.getService().getUrl();} function getDataSheet(sh) { return ss= SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sh).getDataRange().getDisplayValues().slice(1) } /** @ดึงขอมูลจาก sheet */ function getList() { var ss= SpreadsheetApp.getActiveSpreadsheet(); var sheet = ss.getSheetByName("list"); var getLastRow = sheet.getLastRow(); return sheet.getRange(2, 4, getLastRow - 1, 2).getValues().filter(r=>r[0]!=""); } /** @เก็บขอมูลจากนร.สง */ function saveDataSTD(e) {
const ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('data'); const folderIMG = DriveApp.getFolderById('1hAim9oL4_qq-adKKpgQKQw11uEzrg7Aj')// const file = folderIMG .createFile(e.myFile).getUrl() ss.appendRow([ "", e.idSTD, e.nameSTD, e.roomSTD, e.nameSub, e.subID, e.subName, file, "รอตรวจ", ]) } js.html <!-- Modal --> <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" ariahidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalLabel">สงงาน</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div>
<div class="modal-body"> <form id="myform" onsubmit="saveForm(this)"> <p><b>คำอธิบาย</b> ใหนักเรียน กรอกรหัสนักเรียน/นักศึกษา แลวเลือกวิชาที่ตองการสง แนบไฟลเอกสารใบงาน (PDF DOC EXCEL ZIP)แลวกดสงขอมูล</b> <div class="row g-1"> <div class="col-md-3"> <input type="text" class="form-control" placeholder="รหัสนักเรียน" name="idSTD" id="idSTD" readonly> </div> <div class="col-md-6"> <input type="text" class="form-control" placeholder="ชื่อสกุล" name="nameSTD" id="nameSTD" readonly> </div> <div class="col-md-3"> <input type="text" class="form-control" name="roomSTD" placeholder="ระดับชั้น" id="roomSTD" readonly> </div> </div> <hr> <b>ตอนที่ 2 รายละเอียดใบงานที่สง</b> <div id="listChoie" style='font-size:16px' class="table"> </div> <hr> <div class="mb-2"> <label for="formGroupExampleInput" class="form-label">เลือกรายวิชา</label> <select class="form-control" id="nameSub" name="nameSub" oninput="searchSub()" required> <option value="" selected='selected'>เลือกรายวิชา</option>
</select> </div> <div> <div class="row g-1" > <div class="col-md-3"> <input type="text" class="form-control" name="subID" id="subID" readonly > </div> <div class="col-md-8"> <input type="text" class="form-control" name="subName" id="subName" readonly> </div> <div class="col-md-1 text-center"> <a type="text" href="" name="subFile" id="subFile" target="_blank" ><i class='bx bxs-folder-open bx-md'></i></a> </div> </div> </div> <div class="mb-6"> <label for="formGroupExampleInput2" class="form-label">แนบไฟลใบงาน</label> <input type="file" class="form-control" id="file" name="myFile" required > </div> <div class="col-12 text-center"> <button type="submit" class="btn btn-outline-primary">สงขอมูล</button> </div> </form> </div> </div>
</div> </div> <!-- // loginFormสรางฟอมรกรอกรหัส --> <script> function loginSTD(){ Swal.fire({ title: 'ใสเลขประจำตัวประชาชน', html: `<input type="text" id="login" class="swal2-input" placeholder="กรอกรหัสนักเรียน">`, confirmButtonText: 'Sign in', focusConfirm: false, preConfirm: () => { var login = Swal.getPopup().querySelector('#login').value if (!login) { Swal.showValidationMessage(`Please enter login and password`) }else{ loginData(login) } } }) } </script> <!-- // ดึงขอมูลนักเรียนในฐานขอมูล --> <script> var data2; $(document).ready(function(){ google.script.run.withSuccessHandler(function(datax){
data2 = datax }).getDataSheet('std') }) function loginData(login){ event.preventDefault() let datax = data2.filter(f=> f[1] == login) if(datax != ""){ $("#idSTD").val(datax[0][1]) $("#nameSTD").val(datax[0][2]) $("#roomSTD").val(datax[0][3]) $('#exampleModal').modal('show') }else{ Swal.fire( 'ไมพบขอมูล', ) } } </script> <!-- // ดึงรายชื่อรายวิชาที่สอน --> <script> google.script.run.withSuccessHandler(function(ar){ var listSelect = document.getElementById("nameSub"); ar.forEach(function(item) { let option = document.createElement("option"); option.text = item[0]; listSelect.appendChild(option);
}); }).getList(); </script> <!-- // ดึงขอมูลใบงานมาแสดงผล --> <script> var data; $(document).ready(function(){ google.script.run.withSuccessHandler(function(datax){ data = datax }).getDataSheet('list') }) function searchSub(){ event.preventDefault() var id = $("#nameSub").val() var dataArray = data.filter(f=> f[3] == id ) if(dataArray != ""){ $("#subID").val(dataArray[0][4]) $("#subName").val(dataArray[0][5]) $("#subFile").attr("href",dataArray[0][6]); } } </script> <!-- เก็บขอมูลไฟล ที่ นร.สง--> <script> function saveForm(e){ event.preventDefault()
JsLoadingOverlay.show(); google.script.run.withSuccessHandler((item)=>{ Swal.fire( 'บันทึกสงงานเรียบรอย', ) document.getElementById('myform').reset() $('#exampleModal').modal('hide') JsLoadingOverlay.hide(); }).saveDataSTD(e) } </script> index.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bootstrap </title> <?!=include('css')?> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.2.1/css/all.min.css"> <script src="https://code.jquery.com/jquery-1.10.2.js"></script> <link href='https://unpkg.com/[email protected]/css/boxicons.min.css' rel='stylesheet'>
</head> <body> <div class="container"> <div class="row justify-content-center mt-5"> <div class="col-lg-4 col-md-6 col-sm-6"> <div class="card shadow"> <div class="card-title text-center border-bottom p-2"> <h4>ระบบสงงานออนไลน</h4> <h6> Tactical Studies Section</h6> <h6>Army Non Commissioned Officer School </h6> </div> <div class="card-body"> <div class="flex-container"> <div class="content-container" id="btn1" onclick="loginSTD()"><img src="https://sv1.picz.in.th/images/2023/08/11/MIy4lV.png" >นักเรียนสงงาน</div> <!-- <div class="content-container" id="btn2"><img src="https://sv1.picz.in.th/images/2023/08/11/MIyXhQ.png" >คะแนนใบงาน</div> <div class="content-container" id="btn3" ><img src="https://encryptedtbn0.gstatic.com/images?q=tbn:ANd9GcSJT9KmLVHebVmB5MBSt1JTRty1P478YNQ8qwUKTV0&s" >รายละเอียด ใบงาน</div> --> <hr> <h6 class="text-center">Cadit: by:ร.ท.พิษณุ ปนชาติ แผนกยุทธวิธี กศ.รร.นส.ทบ.</h6> </div> </div> </div> </div> </div>
</div> <?!=include('JS')?> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js-loadingoverlay.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" ></script> </body> </html> css.html <style> @import url('https://fonts.googleapis.com/css2?family=Anuphan:wght@200;300&display=swap'); *{ font-family: 'Anuphan', sans-serif; } body{ width: 100%; height: 100vh; background: linear-gradient(45deg,#F17C58, #E94584, #24AADB , #27DBB1,#FFDC18, #FF3706); background-size: 600% 100%; animation: gradient 16s linear infinite; animation-direction: alternate; } @keyframes gradient { 0% {background-position: 0%} 100% {background-position: 100%}
} .flex-container { width: 100%; overflow: auto; display: flex; flex-wrap: wrap; overflow: hidden; } .content-container { height: 80px; background: #0066ff; line-height: 80px; padding-left:20px; /* text-align: center; */ color: white; font-size: 3vh; width: 100%; margin: 10px 0; border-radius: 8px; cursor:pointer; } @media (max-width: 600px) { .card-body" { max-width: 100%; } }
.content-container:hover { background: #2055a4; } img{ width:60px; height:60px; padding:5px; border-radius:50%; } #btn1{ background-image: linear-gradient(to right, #25aae1, #40e495, #30dd8a, #2bb673); box-shadow: 0 4px 15px 0 rgba(49, 196, 190, 0.75); } #btn2{ background-image: linear-gradient(to right, #667eea, #764ba2, #6B8DD6, #8E37D7); box-shadow: 0 4px 15px 0 rgba(116, 79, 168, 0.75); } #btn3{ background-image: linear-gradient(to right, #ed6ea0, #ec8c69, #f7186a , #FBB03B); box-shadow: 0 4px 15px 0 rgba(236, 116, 149, 0.75); } #btn4{ background-image: linear-gradient(to right, #25aae1, #4481eb, #04befe, #3f86ed); box-shadow: 0 4px 15px 0 rgba(65, 132, 234, 0.75); }
#btn5{ background-image: linear-gradient(to right, #f5ce62, #e43603, #fa7199, #e85a19); box-shadow: 0 4px 15px 0 rgba(229, 66, 10, 0.75); } .multi,.bx{ cursor:pointer; } </style>
Line Hackathon27 ระบบสงเสริมการศึกษาดวยตนเองพรอมแบบทดสอบ แสดงผลผาน line Hackathon27 Code
Code.gs var sname sname = 'kepala' var ss = SpreadsheetApp.getActive().getSheetByName(sname).getDataRange().getDisplayValues() var file = SpreadsheetApp.getActive().getSheetByName(sname).getRange('A15:D19').getDisplayValues() function doGet() { return HtmlService.createTemplateFromFile('index').evaluate() .addMetaTag('viewport', 'width=device-width, initial-scale=1') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL) .setTitle(ss[1][1]) index.html <!DOCTYPE html> <html> <head> <base target="_top"> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrapicons.css"> <link href="https://fonts.googleapis.com/css2?family=Niramit&display=swap" rel="stylesheet"> <style>
*{ font-family: 'Niramit', cursive; } body{ background-image:url('<?!=ss[6][1]?>'); background-repeat: no-repeat; background-attachment: fixed; background-position: center; background-size: cover; } </style> </head> <body> <div class="container"> <!-- =========================สวนของ NAV Bar=================== --> <nav class="navbar bg-body-tertiary"> <div class="container-fluid d-flex justify-content-between"> <a class="navbar-brand" href="<?!=ss[3][1]?>"> <img src="<?!=ss[2][1]?>" alt="Logo" height="50" class="d-inline-block align-text-middle"> <?!=ss[1][1]?> </a> <span><?!=ss[4][1]?></span> <span><?!=ss[5][1]?></span> </div> </nav>
<!-- =========================สิ้นสุดสวนของ NAV Bar================ --> <div class="row mt-3"> <!-- =========================เริ่มสวนการดสวนเนื้อหาดานซายมือ========= --> <div class="col-sm-8"> <div class="card" style="border:none;"> <div class="card-body text-center" style="padding:0px;"> <!-- =========================เริ่มการดสวนวีดีโอ================= --> <div class="card"> <div class="card-header"> <h5 class="card-title"><?!=ss[8][1]?></h5> </div> <div class="card-body"> <p class="card-text"> <iframe width="100%" height="350" src="https://www.youtube.com/embed/<?!=ss[9][1]?>" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encryptedmedia; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe> </p> <!-- <a class="btn btn-primary" id="btn_show" onclick="showDiscription()">แสดงรายละเอียด</a> <a class="btn btn-primary" id="btn_hid" onclick="hideDiscription()" style="display:none;">ซอน รายละเอียด</a> --> </div> </div> <!-- =========================สิ้นสุดการดสวนวีดีโอ================= --> <!-- =========================เริ่มการดสวนรายละเอียด================= --> <div class="card my-3" id="discription" style="display:none;"> <div class="card-header">
<?!=ss[10][1]?> </div> <div class="card-body"> <p class="card-text text-start"><?!=ss[11][1]?></p> </div> </div> <!-- =========================สิ้นสุดการดสวนรายละเอียด============== --> </div> </div> </div> <!-- =========================สิ้นสุดการดสวนเนื้อหาดานซายมือ======= --> <!-- =========================เริ่มการดสวนขวามือ================= --> <div class="col-sm-4"> <div class="card"> <div class="card-body"> <h5 class="card-title"><?!=ss[12][1]?></h5> <p class="card-text"><?!=ss[13][1]?></p> <ul class="list-group list-group-flush"> <? file.filter((str) => str[0] !== '').forEach(f=>{ ?> <li class="list-group-item"><a class="btn" href="<?!=f[1]?>" target="_blank"><?!=f[3]?> <?!=f[0]?></a></li> <? }); ?> </ul> </div> </div> </div>
<!-- =========================สิ้นสุดการดสวนขวามือ================= --> </div> <!-- =========================สิ้นสุดการดการแสดงผลทั้งหมด=========== --> <!-- =========================footer================= --> <div class="card my-3 bg-light text-secondary" id="bawah"> <!-- <div class="card-header"></div> --> <div class="card-body"> <p class="card-text text-center" id="notakaki">พัฒนาโดย: <?!=ss[20][1]?></p> </div> </div> <!-- =========================End footer============== --> <!-- </div> <script src="https://dun0077.github.io/script/vmediay1.js"></script> </body> </html> -->
Line Hackathon27 ระบบสงเสริมการศึกษาดวยตนเองพรอมแบบทดสอบ แสดงผลผาน line Hackathon27 Code
Code.gs function include(filename) { return HtmlService.createTemplateFromFile(filename).evaluate().getContent() } function getQuestions(){ var sheetName = "Database" var ws = SpreadsheetApp.getActive().getSheetByName(sheetName) var dataRange = ws.getDataRange() var values = dataRange.getValues() var questions = {} for (var i = 1; i < values.length; i ++){ var rowData = values[i] var key = rowData[0] var title = rowData[1] var option = rowData[2] var point = rowData[3] var correct = rowData[4] if (questions[key]){ questions[key].options.push(option) if (correct){ questions[key].corrects.push(option) } }else{ questions[key] = {
id: key, title: title, options: [option], point: point, corrects: correct ? [option]:[], selected: [], disabled: false, correct: true, } } } questions = Object.keys(questions).map(function(key){ return questions[key] }) Logger.log(questions) return questions } function getEmails(){ var sheetName = "Results" var ws = SpreadsheetApp.getActive().getSheetByName(sheetName) var values = ws.getDataRange().getValues() var emails = [] values.forEach(function(row, index){ if (index > 0){ var email = row[1].toString().toLowerCase().trim() if (emails.indexOf(email) === -1){
emails.push(email) } } }) return emails } function getData(){ var docProps = PropertiesService.getDocumentProperties() var count = docProps.getProperty("count") || 5 var time = docProps.getProperty("time") || 5 var questions = getQuestions() var emails = getEmails() data = { config: { count: count, time: time }, questions: questions, emails: emails } return data } function doGet() { return HtmlService.createTemplateFromFile('index').evaluate() .setTitle('แบบทดสอบ การเคลื่อนที่ หมู ปล.') .addMetaTag('viewport', 'width=device-width , initial-scale=1')
.setFaviconUrl('https://sv1.picz.in.th/images/2022/11/02/v5V9zI.png') .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL) } function loadConfiguration(){ var docProps = PropertiesService.getDocumentProperties() var count = docProps.getProperty("count") if (count){ count = parseInt(count) }else{ count = 5 docProps.setProperty("count", count) } var time = docProps.getProperty("time") if (time){ time = parseInt(time) }else{ time = 5 docProps.setProperty("time", time) } var config = {count: count, time: time} return config } function saveConfiguration(config){ var docProps = PropertiesService.getDocumentProperties() Object.keys(config).forEach(function(key){ docProps.setProperty(key, config[key])
}) } function saveData(result){ var sheetName = "Results" var ws = SpreadsheetApp.getActive().getSheetByName(sheetName) var rowContents = [new Date()].concat(result) var headers = ["Timestamp", "เลขที่กองพัน", "Score"] ws.getRange(1, 1, 1, headers.length).setValues([headers]) ws.appendRow(rowContents) } function showSidebar(){ var title = " แบบทดสอบออนไลน " var userInterface = HtmlService.createTemplateFromFile("sidebar").evaluate().setTitle(title) SpreadsheetApp.getUi().showSidebar(userInterface) } function openQuizSheetApp(){ var url = ScriptApp.getService().getUrl() var html = "<script>window.open('" + url + "');google.script.host.close();</script>" var userInterface = HtmlService.createTemplate(html).evaluate().setTitle("Opening...") SpreadsheetApp.getUi().showSidebar(userInterface) } function onOpen(){ SpreadsheetApp.getUi().createMenu("App") .addItem("Open quizz sheet app", "openQuizSheetApp") .addItem("Configuration", "showSidebar") .addToUi()
} index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <!-- <link rel="stylesheet" href="https://ssl.gstatic.com/docs/script/css/add-ons1.css"> --> <link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> <link rel="stylesheet" href="https://www.w3schools.com/lib/w3-theme-green.css"> <?!= include("css") ?> </head> <body> <div id="app" v-cloak> <header class="w3-card w3-theme"> <div class="w3-bar"> <p class="w3-bar-item w3-mobile"><b>{{title}}</b></p> <p class="w3-bar-item w3-tag w3-round w3-theme-l5 w3-margin-right w3-mobile"> <input class="w3-mobile w3-center" type="email"
style="border: none; background: transparent; outline: none; padding: 0px;" v-model="email" placeholder="เลขที่กองพัน 4 หลัก" :disabled="start" required > </p> <template v-if="!start"> <p class="w3-bar-item w3-button w3-round w3-theme-d4 w3-margin-right w3-mobile" @click="startQuiz" >เริ่มทำแบบทดสอบ</p> </template> <template v-else> <p class="w3-bar-item w3-button w3-round w3-theme-d4 w3-margin-right w3-mobile" @click="endQuiz" >สงคำตอบ</p> <p class="w3-bar-item w3-tag w3-round w3-theme-l4 w3-margin-right w3-mobile" >จำนวน {{config.count}} ขอ</p> <p class="w3-bar-item w3-tag w3-round w3-theme-l4 w3-margin-right w3- mobile">{{timer}}</p> </template> </div> </header> <main v-if="selectedQuestions"> <div class="w3-card w3-container w3-padding" v-for="(q, qIndex) in selectedQuestions" :key="q.id">
<label class="w3-block w3-mobile w3-container w3-padding w3-round" :class="q.correct ? 'w3- theme-l3': 'w3-pale-red'"> <span class="w3-tag w3-theme w3-round">{{qIndex + 1}} </span> <b>{{q.title}}</b> <span class="w3-tag w3-theme-l4 w3-round">{{q.point}}</span> <span v-if="q.corrects.length > 1" class="w3-tag w3-red w3-round">M</span> <span class="w3-tag w3-theme-l4 w3-round" v-else>S</span> </label> <template v-if="q.corrects.length > 1"> <template v-for="(option, i) in q.options"> <label class="w3-block w3-mobile"> <input class="w3-check" type="checkbox" v-model="q.selected" :name="q.id" :value="option" :disabled="q.disabled"> {{option}}</label> </template> </template> <template v-else> <template v-for="(option, i) in q.options"> <label class="w3-block w3-mobile"> <input class="w3-radio" type="radio" v-model="q.selected" :name="q.id" :value="option" :disabled="q.disabled"> {{option}}</label> </template> </template> </div> </main>
<footer v-if="selectedQuestions"> <div class="w3-container w3-theme"> <p class="w3-center w3-mobile">พัฒนา โดย ร.ท.พิษณุ ปนชาติ แผนกยุทธวิธี กองการศึกษา โรงเรียนนาย สิบทหารบก</p> </div> </footer> <div class="message" v-if="message"> <div class="w3-card"> <div class="w3-padding" :class="message.type=='Error' ? 'w3-red': 'w3-theme'"> {{message.type}} </div> <div class="w3-padding"> <p class="w3-small">{{message.message}}</p> <button class="w3-button w3-round" :class="message.type=='Error' ? 'w3-red': 'w3-theme'" @click="closeMessageBox">OK</button> </div> </div> </div> <div class="message loading" v-if="submitting"> </div> </div> <?!= include("js") ?> </body> </html>
JS.html <script> function randomSelectArray(arr, count){ if (count > arr.length){ count = arr.length } let data = arr.slice() let newArr = [] for (let i = 0; i < count; i ++) { let newItem = data.splice(Math.floor(Math.random() * data.length), 1) newArr = newArr.concat(newItem) } return newArr } function formatTime(seconds){ let h = Math.floor(seconds / 3600) if (h < 10){ h = "0" + h } let m = Math.floor((seconds % 3600) / 60) if (m < 10){ m = "0" + m } let s = (seconds % 3600) % 60 if (s < 10){
s = "0" + s } return [h, m, s].join(":") } let data = { message: null, submitting: false, start: false, title: "แบบทดสอบออนไลน การเคลื่อนที่ รูปขบวน หมู ปล.", countDown: null, counter: 0, email: "", config: {}, questions: null, emails: [], selectedQuestions: null } let computed = { timer: function(){ return formatTime(this.counter) } } let methods = { startQuiz: function(){ if (this.email === ""){ this.message = {
type: "Error", message: "กรุณากรอกเลขที่กองพัน" } }else if(this.emails.includes(this.email.toString().trim().toLowerCase())){ this.message = { type: "Error", message: `เลขที่ ${this.email} ทำแบบทดสอบไปแลว.` } }else{ this.start = true this.counter = this.config.time * 60 let selectedQuestions = randomSelectArray(this.questions, this.config.count) selectedQuestions.forEach(function(item){ item.disabled = false item.selected = [] item.correct = true }) this.selectedQuestions = selectedQuestions this.countDown = setInterval(function(){ this.counter -= 1 if (this.counter === 0){ clearInterval(this.countDown) this.endQuiz() } }.bind(this), 1000) }