📢 Chào mừng các bạn đến với Rcom Dăm Yi blog - Kho tài liệu và giải pháp công nghệ bổ ích! Hệ thống liên tục cập nhật dữ liệu học tập mới.
Hệ thống Quản lý Chuyên môn - THPT Phan Chu Trinh

Hết hạn dùng thử!

Phiên bản Dùng thử đã vượt quá 15 ngày. Vui lòng nhập mã kích hoạt để tiếp tục sử dụng hệ thống.

Bảng điều khiển chung

Thống kê Tuần này

Khu vực này hiển thị các biểu đồ tổng quan, số tiết đã dạy, số tiết chưa dạy, và các chỉ số thi đua của nhà trường.

120

Tiết học đã ghi nhận

45

Lịch báo giảng đã nộp

Lịch Báo Giảng Của Tôi

Nơi giáo viên thao tác Thêm/Sửa/Xóa lịch dạy hàng tuần của cá nhân.

Giao diện Lịch báo giảng sẽ được render tại đây.

Sổ Đầu Bài Điện Tử

Hệ thống cho phép nhập và theo dõi Sổ đầu bài trực tiếp từ lớp học.

Giao diện Sổ đầu bài sẽ được render tại đây.

Thiết lập Phân Công Chuyên Môn

Khu vực dành riêng cho Quản trị viên/Tổ trưởng sắp xếp giáo viên phụ trách môn và lớp.

Giao diện Phân công sẽ được render tại đây.
Bài 20 (Phần 5) - Tích hợp Chuyên môn & Xuất Báo cáo

Thời gian dùng thử đã hết!

Hệ thống iTeach đã vượt quá 15 ngày dùng thử. Vui lòng nhập License Key.

Bài 20. Quản lý sổ đầu bài điện tử (Phần 5)
Tích hợp Lịch báo giảng & Phân công chuyên môn

Cấu trúc Cơ sở dữ liệu (Database Schema): Để hệ thống chặt chẽ, ta cần 3 Sheet tương tác với nhau:

  • Sheet `PhanCong`: (Lớp, Môn, Giáo viên). Quy định ai dạy lớp nào.
  • Sheet `LichBaoGiang`: (Tuần, Thứ, Tiết, Lớp, Môn, Bài dạy, Giáo viên). Được giáo viên nhập lên vào cuối tuần trước dựa vào PhanCong.
  • Sheet `SoDauBai`: (Ngày, Lớp, Tiết, Môn, Bài dạy, Xếp loại, Giáo viên). Khớp với thực tế giảng dạy.

1. Mã nguồn Back-end (Code.gs)

Viết các hàm truy xuất dữ liệu riêng biệt để chuẩn bị cho việc xuất file Excel từ Client.

// 1. Hàm lấy Lịch Báo Giảng theo Giáo viên
function layLichBaoGiangTheoGV(tenGV) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("LichBaoGiang");
  let data = sheet.getDataRange().getValues();
  
  // Bỏ dòng tiêu đề và lọc theo tên Giáo viên (Giả sử cột G - index 6 là tên GV)
  let ketQua = data.slice(1).filter(row => row[6] === tenGV);
  return ketQua;
}

// 2. Hàm lấy Sổ Đầu Bài theo Lớp
function laySoDauBaiTheoLop(tenLop) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SoDauBai");
  let data = sheet.getDataRange().getValues();
  
  // Bỏ dòng tiêu đề và lọc theo Lớp (Giả sử cột C - index 2 là Lớp)
  let ketQua = data.slice(1).filter(row => row[2] === tenLop);
  return ketQua;
}

2. Giao diện Tích hợp & Xuất Báo Cáo

NgàyLớpTiếtMôn & Bài dạyXLGV
TuầnThứTiếtLớpMôn & Bài dạy

Bảng Phân Công Chuyên Môn (Master Data)

Dữ liệu này là gốc rễ để giới hạn Giáo viên chỉ được lên lịch báo giảng và nhập sổ đầu bài đúng lớp, đúng môn được phân công.

Tổ Chuyên MônGiáo viênMôn dạyLớp phụ trách
Bài 20. Sổ Đầu Bài (Phần 4) - Xuất Báo Cáo & In Ấn

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key).

Bài 20. Sổ Đầu Bài: Xuất Excel & In Báo Cáo PDF

Có 2 cách tiếp cận để xuất báo cáo:

  1. Xuất Excel (Back-end): Google Sheets hỗ trợ một đường link bí mật giúp tải file tự động. Chỉ cần thay /edit bằng /export?format=xlsx trong đường dẫn của file Sheets, hệ thống sẽ trả về một file Excel.
  2. In PDF (Front-end): Thay vì dùng Apps Script tạo PDF rất phức tạp, ta dùng tính năng window.print() của trình duyệt kết hợp với CSS @media print. Kỹ thuật này sẽ "phù phép" trang web, ẩn đi các nút bấm, menu và biến bảng dữ liệu thành một trang A4 hoàn hảo.

1. Mã nguồn Back-end (Code.gs)

Chúng ta sẽ viết một hàm để lấy tự động ID của file Google Sheets hiện tại và ghép thành đường link tải Excel.

// Hàm lấy Link tải file Excel trực tiếp từ Google Sheets
function layLinkXuatExcel() {
  let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  let fileId = spreadsheet.getId();
  
  // Cấu trúc link tải trực tiếp của Google
  let exportUrl = "https://docs.google.com/spreadsheets/d/" + fileId + "/export?format=xlsx";
  
  return exportUrl;
}
💡 Mẹo nhỏ: Nếu bạn muốn xuất ra file PDF từ Google Sheets, chỉ cần đổi format=xlsx thành format=pdf. Tuy nhiên, xuất PDF theo cách này sẽ lấy toàn bộ trang tính gốc (chưa được format đẹp mắt). Do đó, ở phần Front-end dưới đây, ta sẽ dùng CSS để tạo bản in PDF xịn xò hơn.

2. Giao diện & Kỹ thuật Xử lý (Front-end)

Báo cáo Sổ đầu bài

STT Ngày Lớp Tiết Môn Nội dung bài dạy XL Giáo viên
Bài 19. Sổ Đầu Bài (Phần 3) - Xóa & Thống kê

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền.

Bài 19. Sổ Đầu Bài: Xóa Dữ Liệu & Báo Cáo Thống Kê

Trọng tâm bài học:
1. Thuật toán Xóa (Delete): Cần xác định chính xác số thứ tự dòng (Row Index) trên Google Sheets để xóa đúng đối tượng. Bắt buộc phải có hộp thoại xác nhận (Confirm) để tránh vô tình click nhầm.
2. Xử lý mảng (Array processing): Ứng dụng kỹ thuật đếm phần tử trong mảng (tương tự vòng lặp trong Python) bằng hàm filter() của JavaScript để tạo Bảng điều khiển (Dashboard) theo dõi thi đua trực quan.

1. Mã nguồn Back-end (Code.gs)

Hàm xóa dữ liệu trên Google Sheets rất đơn giản nhờ phương thức deleteRow(). Tuy nhiên, sự nguy hiểm là nếu xóa sai dòng, dữ liệu sẽ mất vĩnh viễn.

// Hàm Xóa một tiết học khỏi Sổ Đầu Bài
function xoaTietHoc(rowIndex) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SoDauBai");
  
  // Xóa dòng tại vị trí rowIndex
  sheet.deleteRow(rowIndex);
  
  return "Đã xóa dữ liệu thành công!";
}
💡 Lưu ý quan trọng: Khác với Cập nhật (Update) dùng setValue(), khi sử dụng deleteRow(), toàn bộ các dòng bên dưới sẽ bị đẩy lên trên. Do đó, thao tác xóa nên được thực hiện cẩn thận, và ngay sau khi xóa thành công trên Server, Frontend phải lập tức gọi lại hàm traCuuSoDauBai() (đã học ở Bài 18) để cập nhật lại danh sách, đảm bảo các rowIndex của các dòng còn lại không bị sai lệch.

2. Thuật toán Thống kê (Front-end JS)

Thay vì bắt Server (Google Script) phải đếm số lượng rồi mới trả về, ta tận dụng luôn mảng dữ liệu (Array) đã tải xuống trình duyệt để thống kê. Việc này giúp ứng dụng chạy nhanh hơn và giảm tải cho Server.

// Trích xuất code trong hàm vẽ bảng (JS)
function capNhatThongKe(data) {
  // data là mảng 2 chiều chứa danh sách các tiết học
  let tongSo = data.length;
  
  // Lọc và đếm số tiết đạt loại A (cột thứ 6 trong mảng, index = 6)
  let soLoaiA = data.filter(row => row[6] === "A").length;
  let soLoaiB = data.filter(row => row[6] === "B").length;
  let soLoaiC = data.filter(row => row[6] === "C").length;

  // Đổ dữ liệu ra Giao diện HTML
  document.getElementById("valTotal").innerText = tongSo;
  document.getElementById("valA").innerText = soLoaiA;
  // ...
}

3. Giao diện Tổng hợp Báo cáo & Quản lý

Bảng Điều Khiển Ban Giám Hiệu (Dashboard)

Tổng số tiết đã dạy
0
Tiết học loại A (Tốt)
0
Tiết học loại B (Khá)
0
Tiết học loại C (TB)
0
Ngày Lớp Tiết Môn & Bài dạy XL Quản trị
Bài 18. Sổ Đầu Bài Điện Tử (Phần 2) - Tra cứu & Chỉnh sửa

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền để tiếp tục sử dụng hệ thống.

Bài 18. Sổ Đầu Bài: Tra cứu, Lọc dữ liệu & Chỉnh sửa

Mục tiêu: Sau khi Sổ đầu bài đã có dữ liệu, bài toán tiếp theo của người quản trị mạng là cung cấp công cụ để:
1. Giám thị có thể chọn một Lớp cụ thể và một Tuần/Ngày cụ thể để kiểm tra.
2. Nếu Giáo viên nhập nhầm tên bài dạy (VD: Nhập nhầm bài "Hàm số" thành "Đạo hàm" môn Toán), họ có quyền click vào dòng đó để Cập nhật (Update) lại dữ liệu trên Sheets thay vì tạo dòng mới.

1. Mã nguồn Back-end (Code.gs)

Để tìm kiếm dữ liệu hiệu quả, chúng ta sử dụng hàm filter() của JavaScript để lọc mảng 2 chiều lấy ra các dòng khớp với tiêu chí "Lớp" và "Ngày".

// 1. Hàm Tra cứu (Filter) Sổ đầu bài theo Lớp và Ngày
function traCuuSoDauBai(lopCanTim, ngayCanTim) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SoDauBai");
  let data = sheet.getDataRange().getValues(); // Lấy toàn bộ bảng
  
  // Bỏ dòng tiêu đề bằng slice(1)
  let ketQua = [];
  
  for (let i = 1; i < data.length; i++) {
    let row = data[i];
    let ngayDay = row[1]; // Cột B: Ngày dạy (chuỗi dd/MM/yyyy)
    let tenLop = row[2];  // Cột C: Tên lớp
    
    // Nếu khớp tiêu chí lọc (hoặc người dùng để trống tiêu chí)
    if ((lopCanTim === "" || tenLop === lopCanTim) && 
        (ngayCanTim === "" || ngayDay === ngayCanTim)) {
        
        // Đẩy thêm rowIndex vào mảng để phục vụ tính năng Update về sau
        row.push(i + 1); 
        ketQua.push(row);
    }
  }
  return ketQua;
}

// 2. Hàm Cập nhật (Update) một tiết học bị sai
function capNhatTietHoc(rowIndex, baiDayMoi, xepLoaiMoi) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SoDauBai");
  
  // Ghi đè vào Cột F (cột 6 - Bài dạy) và Cột G (cột 7 - Xếp loại)
  sheet.getRange(rowIndex, 6).setValue(baiDayMoi);
  sheet.getRange(rowIndex, 7).setValue(xepLoaiMoi);
  
  return "Cập nhật thành công!";
}
💡 Giải thích Kỹ thuật:
- Tại hàm traCuuSoDauBai, lệnh row.push(i + 1) là một "thủ thuật" rất quan trọng. Mảng dữ liệu ban đầu chỉ có từ Cột A đến Cột H. Ta chủ động nhét thêm số thứ tự dòng (Index của Google Sheets, bắt đầu từ 1) vào cuối mảng. Mục đích là khi hiển thị lên giao diện HTML, ta biết chính xác dòng dữ liệu này nằm ở Hàng số mấy trên Google Sheets, từ đó mới truyền cái RowIndex này cho hàm capNhatTietHoc thực hiện ghi đè.

2. Giao diện Người dùng (Front-end SPA)

Thực hành Mô phỏng: Tra cứu & Quản lý Sổ Đầu Bài

(Trường THPT Phan Chu Trinh - Ayun Pa, Gia Lai. Dữ liệu chạy mô phỏng không cần tải lại trang).

Ngày Lớp Tiết Môn & Bài dạy XL Hành động
Bài 17. Dự án Thực tế: Hệ thống Sổ Đầu Bài Điện Tử

Thời gian dùng thử đã hết!

Phần mềm đã vượt quá 15 ngày dùng thử miễn phí. Vui lòng nhập mã bản quyền (License Key) để tiếp tục sử dụng Hệ thống iTeach.

Bài 17. Dự án: Hệ thống Sổ Đầu Bài Điện Tử

Mục tiêu dự án: Xây dựng một ứng dụng Web (Web App) thay thế hoàn toàn sổ đầu bài giấy. Giáo viên lên lớp dùng smartphone/laptop để nhập liệu. Hiệu trưởng và giám thị có thể xem tình hình các lớp theo thời gian thực (Real-time).

1. Thiết lập Cấu trúc Google Sheets (Database)

Tạo một file Google Sheets và đổi tên các trang tính (Sheet) như sau:

  • Sheet 1: DM_Lop (Danh mục Lớp). Cột A: Tên lớp (VD: 10A1, 10A2, 11B1...).
  • Sheet 2: SoDauBai. Gồm các cột: A (Thời gian ghi), B (Ngày dạy), C (Lớp), D (Tiết), E (Môn học), F (Tên bài dạy), G (Xếp loại), H (Giáo viên).

2. Viết mã Back-end (Code.gs)

Trong môi trường Apps Script, chúng ta cần 3 hàm chính: Lấy danh sách lớp (cho Dropdown), Lấy dữ liệu của ngày hôm nay (cho Bảng), và Ghi dữ liệu mới vào Sheet.

// 1. Hàm lấy danh sách lớp học để đổ vào thẻ <select>
function layDanhSachLop() {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DM_Lop");
  return sheet.getRange(2, 1, sheet.getLastRow() - 1, 1).getValues();
}

// 2. Hàm lưu Tiết học mới vào Sổ đầu bài
function luuTietHoc(formObj) {
  let sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("SoDauBai");
  let timeStamp = new Date(); // Thời gian bấm nút lưu
  
  // Định dạng ngày (dd/mm/yyyy) để dễ lọc dữ liệu
  let ngayDay = Utilities.formatDate(timeStamp, Session.getScriptTimeZone(), "dd/MM/yyyy");
  
  let rowData = [
    timeStamp, ngayDay, formObj.lop, formObj.tiet, 
    formObj.mon, formObj.baiDay, formObj.xepLoai, formObj.giaoVien
  ];
  
  sheet.appendRow(rowData);
  return "Đã lưu thành công!";
}
💡 Giải thích chi tiết: Ở hàm luuTietHoc, ta tạo ra 2 cột thời gian. timeStamp (Cột A) lưu cả ngày giờ phút giây chính xác để làm bằng chứng giáo viên đã nhập sổ lúc mấy giờ. Còn ngayDay (Cột B) chỉ lưu ngày/tháng/năm dưới dạng chuỗi (String) để thuật toán tìm kiếm và lọc dữ liệu (hiển thị theo ngày) hoạt động dễ dàng và nhẹ nhàng hơn.

3. Giao diện và Xử lý Front-end (Index.html)

Thực hành Giao diện Mô phỏng: Sổ Đầu Bài Điện Tử

(Giao diện dưới đây minh họa cách Web App thực tế hoạt động. Dữ liệu sẽ tự động làm mới ngay sau khi bấm Lưu).

Nhập Sổ Đầu Bài

Tiết dạy hôm nay

Mã nguồn JavaScript xử lý tương tác UI

<script>
  // 1. Hàm chạy ngay khi vừa mở ứng dụng
  window.onload = function() {
    // Gọi Server tải danh sách lớp vào Select
    google.script.run.withSuccessHandler(doDuLieuLop).layDanhSachLop();
    
    // Gọi Server tải danh sách tiết học hôm nay vào Bảng
    taiDuLieuBang(); 
  };

  // 2. Xử lý Form Submit (Cơ chế SPA)
  function submitFormSDB(formObj) {
    // Hiệu ứng Loading (Code ẩn hiện DOM bỏ qua cho gọn)
    google.script.run
      .withSuccessHandler(function() {
         document.getElementById("formSoDauBai").reset();
         taiDuLieuBang(true); // TẢI LẠI BẢNG (Kèm cờ true để làm hiệu ứng Highlight)
      })
      .luuTietHoc(formObj);
  }
</script>
💡 Nhấn mạnh: Chìa khóa để ứng dụng không bị tải lại trang (chớp màn hình) là gọi lại hàm taiDuLieuBang() bên trong withSuccessHandler. Khi Apps Script ghi xong vào Sheet, nó phản hồi về Client, lúc này Client ra lệnh "Xóa form" và "Kéo data mới nhất về vẽ lại bảng". Toàn bộ thao tác diễn ra ngầm.