เว็บแอประบบ login กำหนดสิทธิ์ 4 ระดับ แยกหน้าชัดเจน

1. code.gs

     
function doGet(e) {
  const page = (e && e.parameter && e.parameter.page) ? e.parameter.page : 'index';
  let template;
 
  // หน้า HTML ที่อนุญาต
  const validPages = ['index', 'admin', 'editor', 'user', 'guest'];
  if (validPages.includes(page)) {
    template = HtmlService.createTemplateFromFile(page);
  } else {
    template = HtmlService.createTemplateFromFile('index')
  }
 
  return template.evaluate()
    .setTitle('ระบบล็อกอินตามบทบาท')
    .setFaviconUrl("https://semicon.github.io/img/logo2small.png")
    .addMetaTag('viewport', 'width=device-width , initial-scale=1')
    .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
    .setSandboxMode(HtmlService.SandboxMode.IFRAME);
}

function doLogin(username, password) {
  try {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName('Users');
    const data = sheet.getDataRange().getValues();
   
    for (let i = 1; i < data.length; i++) {
      if (data[i][0] === username && data[i][1] === password) {
        return {
          username: data[i][0],
          name: data[i][2],
          role: data[i][3]
        };
      }
    }
   
    throw new Error('ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง');
  } catch (error) {
    throw new Error(error.message);
  }
}

function checkSession(username) {
  try {
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const sheet = ss.getSheetByName('Users');
    const data = sheet.getDataRange().getValues();
   
    for (let i = 1; i < data.length; i++) {
      if (data[i][0] === username) {
        return true;
      }
    }
    return false;
  } catch (error) {
    return false;
  }
}


function include(file){
  return HtmlService.createHtmlOutputFromFile(file).getContent();
}

function getURL(){
  return ScriptApp.getService().getUrl();
}


2. index.html

     
<!DOCTYPE html>
<html lang="th">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ระบบล็อกอินตามบทบาท</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
    <style>
        body {
            background-color: #f8f9fa;
            height: 100vh;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .login-container {
            max-width: 400px;
            width: 100%;
            padding: 20px;
            background: white;
            border-radius: 10px;
            box-shadow: 0 0 10px rgba(0,0,0,0.1);
        }
    </style>
    <?!=include('style.css')?>
</head>
<body>

  <!-- Login Form -->
  <div class="login-container" id='loginform' style="display: none;">
    <h2 class="text-center mb-4">ล็อกอิน</h2>
    <div class="mb-3">
      <label for="username" class="form-label">ชื่อผู้ใช้</label>
      <input type="text" class="form-control" id="username" placeholder="กรอกชื่อผู้ใช้">
    </div>
    <div class="mb-3">
      <label for="password" class="form-label">รหัสผ่าน</label>
      <input type="password" class="form-control" id="password" placeholder="กรอกรหัสผ่าน">
    </div>
    <button class="btn btn-primary w-100" onclick="login()">ล็อกอิน</button>
  </div>
 
  <!-- Overlay -->
  <div id="overlay">
    <div class="loader">
      <canvas id="spiral" width="100" height="100"></canvas>
      <!-- เปลี่ยน src ให้เป็นโลโก้ของคุณ -->
      <img id = "logoloader" logo src="https://semicon.github.io/img/web/logoxxx.png" alt="logo">
    </div>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
   
  <?!=include('common.js')?>

  <script>
    window.addEventListener("load", () => {
      getUrl(() => {
        const user = JSON.parse(sessionStorage.getItem('user'));
        if (user) {
          google.script.run
          .withSuccessHandler((isValid) => {
            if (isValid) {
              redirectByRole(user.role);
            } else {
              sessionStorage.removeItem('user');
            }
          }).withFailureHandler(() => {
            sessionStorage.removeItem('user');
          }).checkSession(user.username);
        }
        document.getElementById('loginform').style.display = 'block';
      });
    });
 
    function login() {
      const username = document.getElementById('username').value.trim();
      const password = document.getElementById('password').value.trim();
     
      if (!username || !password) {
        Swal.fire({
          icon: 'error',
          title: 'ข้อผิดพลาด',
          text: 'กรุณากรอกชื่อผู้ใช้และรหัสผ่าน'
        });
        return;
      }
     
      if (!mainUrl) {
        getUrl(() => doLogin(username, password));
      } else {
        doLogin(username, password);
      }
    }
 
    function doLogin(username, password) {
      showOverlay();
      google.script.run
      .withSuccessHandler(onLoginSuccess)
      .withFailureHandler(onLoginFailure)
      .doLogin(username, password);
    }
     
    function onLoginSuccess(user) {
      document.getElementById('loginform').style.display = 'none';
      if (user) {
        user.mainUrl = mainUrl;
        sessionStorage.setItem('user', JSON.stringify(user));
        hideOverlay();
        Swal.fire({
          icon: 'success',
          title: 'ล็อกอินสำเร็จ',
          text: `ยินดีต้อนรับ ${user.name} (บทบาท: ${user.role})`,
          timerProgressBar: true,
          timer: 2500,
          showConfirmButton: false
        }).then(() => {
          redirectByRole(user.role);
          showOverlay();
        });
      }
    }
     
    function onLoginFailure(error) {
      hideOverlay()
      Swal.fire({
        icon: 'error',
        title: 'ล็อกอินล้มเหลว',
        text: error
      });
    }
  </script>
</body>
</html>


3. style.css

     
<style>
/* ----- Overlay เต็มจอ ----- */
#overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(255,255,255,0.8); /* พื้นหลังโปร่งแสง */
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 999;
  transition: opacity 0.5s ease;
}

/* Loader */
.loader {
  position: relative;
  width: 100px;
  height: 100px;
}
.loader canvas {
  position: absolute;
  top: 0;
  left: 0;
}
.loader img {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 35px;
  height: 35px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
}
  /* พื้นหลังโปร่งใสเฉพาะกล่องที่ใช้คลาสนี้ */
  .swal2-bg-transparent {
    background: transparent !important;
    box-shadow: none !important;
  }

  /* ให้ progress bar สีแดงเฉพาะกล่องนี้ */
  .swal2-bg-transparent .swal2-timer-progress-bar {
    background: red !important;
  }
</style>


4. common.js

     
<script>
const logourl = 'https://semicon.github.io/img/web/logoxxx.png';

// โหลด SweetAlert2 ถ้ายังไม่มีในหน้า
if (typeof Swal === "undefined") {
    const swalScript = document.createElement("script");
    swalScript.src = "https://cdn.jsdelivr.net/npm/sweetalert2@11";
    document.head.appendChild(swalScript);
}



let mainUrl = "";

// ฟังก์ชันดึง URL จาก server
function getUrl(callback) {
    google.script.run.withSuccessHandler(r => {
        mainUrl = r;
        if (typeof callback === "function") callback();
    }).getURL();
}

// ฟังก์ชัน redirect (ทำงานได้ทั้งใน iframe และนอก iframe)
function redirect(url) {
    if (window.top === window.self) {
        // ไม่อยู่ใน iframe
        window.location.href = url;
    } else {
        hideOverlay()
        // อยู่ใน iframe
        Swal.fire({
            icon: "",
            title: "",
            text: "ดำเนินการต่อ...",
            confirmButtonText: "ตกลง",
        }).then(() => {
            showOverlay();
            setTimeout(() => {
              window.open(url, "_top");
            }, 500);
        });
    }
}

// ฟังก์ชัน redirect ตาม role
function redirectByRole(role) {
    const url = new URL(mainUrl);
    url.searchParams.set("page", role.toLowerCase());
    redirect(url.toString());
}

// ฟังก์ชัน logout
function logout() {
  sessionStorage.removeItem("user");
  Swal.fire({
    icon: "",
    title: "",
    showConfirmButton: false,
    timerProgressBar: true,
    timer: 1500,
    customClass: {
      popup: 'swal2-bg-transparent'
    }
  }).then(() => {
    redirect(`${mainUrl}`);
  });
}

// ------loader spiral--------------------------------------------
const canvas = document.getElementById('spiral');
const ctx = canvas.getContext('2d');
const w = canvas.width;
const h = canvas.height;
const cx = w / 2;
const cy = h / 2;

let rotation = 0;

function drawSpiral(rot) {
  ctx.clearRect(0, 0, w, h);
  ctx.save();
  ctx.translate(cx, cy);
  ctx.rotate(rot);

  ctx.lineWidth = 2;
  const maxRadius = 45;
  const turns = 4.5;
  const steps = 1000;

  for (let i = 0; i<steps; i++) {
    const t1 = i / steps;
    const t2 = (i + 1) / steps;
    const theta1 = t1 * turns * Math.PI * 2;
    const theta2 = t2 * turns * Math.PI * 2;
    const radius1 = t1 * maxRadius;
    const radius2 = t2 * maxRadius;
    const x1 = radius1 * Math.cos(theta1);
    const y1 = radius1 * Math.sin(theta1);
    const x2 = radius2 * Math.cos(theta2);
    const y2 = radius2 * Math.sin(theta2);
    const hue = (t1 * 360) % 360;
    ctx.beginPath();
    ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
    ctx.moveTo(x1, y1);
    ctx.lineTo(x2, y2);
    ctx.stroke();
  }
  ctx.restore();
}

function animate() {
  rotation += 0.05;
  drawSpiral(rotation);
  requestAnimationFrame(animate);
}
animate();

/* ----- ปิด Overlay หลังโหลดเสร็จ ----- */
window.addEventListener('load', () => {
  setTimeout(() => {
    const overlay = document.getElementById('overlay');
    overlay.style.opacity = '0';
    setTimeout(() => overlay.style.display = 'none', 500);
  }, 3000); // แสดง 3 วินาที
});

function showOverlay(){
  document.getElementById('logoloader').src = logourl;
  const overlay = document.getElementById('overlay');
  overlay.style.display = 'block'
}

function hideOverlay(){
  const overlay = document.getElementById('overlay');
  overlay.style.display = 'none'
}

</script>


5. สร้างไฟล์ admin.html, user.html, editor.html, guest.html 

     
<!DOCTYPE html>
<html lang="th">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>หน้าผู้ดูแลระบบ</title>
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
  <link href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css" rel="stylesheet">
  <style>
    body {
      background-color: #f8f9fa;
      padding: 20px;
    }
  </style>

  <?!=include('style.css')?>

</head>

<body>
  <div class="container">
    <div id="contentArea" class="d-none">
      <div class=" text-end">
        <button class="btn btn-danger" onclick="logout()">ออกจากระบบ</button>
      </div>

      <!-- add Content -->
      <h2>ยินดีต้อนรับ ผู้ดูแลระบบ</h2>
      <p>นี่คือหน้าสำหรับผู้ดูแลระบบ (Admin) คุณสามารถจัดการผู้ใช้และข้อมูลทั้งหมดได้ที่นี่</p>
     


   
   
   
   
   
   
    </div>
  </div>
  <!-- Overlay -->
  <div id="overlay">
    <div class="loader">
      <canvas id="spiral" width="100" height="100"></canvas>
      <!-- เปลี่ยน src ให้เป็นโลโก้ของคุณ -->
      <img id = "logoloader" logo src="https://semicon.github.io/img/web/logoxxx.png" alt="logo">
    </div>
  </div>


  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
 
  <?!=include('common.js')?>
 
  <script>
    let user = null;

    window.addEventListener("load", () => {
      user = JSON.parse(sessionStorage.getItem("user"));
        getUrl(() => {
          checkAccess();
        });
    });

    function checkAccess() {
      if (!user || user.role.toLowerCase() !== "xxxx") { // xxxx แก้ไข ตาม role ไฟล์ => admin, user, editor, guest
        Swal.fire({
          icon: "error",
          title: "ไม่มีสิทธิการเข้าถึง",
          text: "คุณไม่มีสิทธิในการเข้าถึงหน้านี้",
          timer: 2000,
          showConfirmButton: false
        }).then(() => {
          sessionStorage.removeItem("user");
          redirect(`${mainUrl}`);
        });
        return;
      }

      google.script.run.withSuccessHandler((isValid) => {
        if (!isValid) {
          Swal.fire({
            icon: "error",
            title: "เซสชันไม่ถูกต้อง",
            text: "กรุณาล็อกอินใหม่",
            timer: 2000,
            showConfirmButton: false
          }).then(() => {
            sessionStorage.removeItem("user");
            redirect(`${mainUrl}`);
          });
        } else {
          document.getElementById("contentArea").classList.remove("d-none");
        }
      }).withFailureHandler(() => {
        sessionStorage.removeItem("user");
        redirect(`${mainUrl}`);
      }).checkSession(user.username);
    }

  </script>
</body>

</html>


6. Google Sheet

  • ชื่อชีต Users
  • ตาราง
UsernamePasswordNameRole
adminadmin123Admin UserAdmin
editoredit123Editor UserEditor
useruser123Norma UserUser
guestguest123Guest UserGuest


Download Sheets  DEMO






แสดงความคิดเห็น (0)
ใหม่กว่า เก่ากว่า