<div id=”tnm-app”>
<style>
#tnm-app{font-family:Arial,Helvetica,sans-serif;color:#172033;background:#f5f7fb;min-height:100vh}
#tnm-app *{box-sizing:border-box}
.tnm-sidebar{position:fixed;left:0;top:0;bottom:0;width:245px;background:#111827;color:#dbe3ef;padding:20px 14px;z-index:9999}
.tnm-brand{font-size:20px;font-weight:800;color:#fff;padding:10px 12px 25px}
.tnm-brand span{color:#38bdf8}
.tnm-nav{padding:11px 12px;margin:5px 0;border-radius:9px;cursor:pointer}
.tnm-nav:hover,.tnm-nav.active{background:#243044;color:#fff}
.tnm-main{margin-left:245px;padding:25px 30px;min-height:100vh}
.tnm-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:25px}
.tnm-top h1{margin:0;font-size:26px}
.tnm-user{background:#fff;padding:10px 15px;border-radius:10px;box-shadow:0 2px 10px #0001}
.tnm-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.tnm-card{background:#fff;border-radius:14px;padding:20px;box-shadow:0 3px 15px #0000000b}
.tnm-label{font-size:13px;color:#667085}
.tnm-number{font-size:30px;font-weight:800;margin-top:8px}
.tnm-section{margin-top:24px}
.tnm-section h2{font-size:18px}
.tnm-toolbar{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:14px}
#tnm-app input,#tnm-app select,#tnm-app button{
border:1px solid #d8dee9;border-radius:9px;padding:10px 12px;font-size:14px
}
#tnm-app button{background:#172033;color:#fff;border:0;cursor:pointer}
#tnm-app button:hover{opacity:.9}
.tnm-secondary{background:#fff!important;color:#172033!important;border:1px solid #d8dee9!important}
.tnm-table{background:#fff;border-radius:14px;overflow:auto;box-shadow:0 3px 15px #0000000b}
.tnm-table table{width:100%;border-collapse:collapse;min-width:900px}
.tnm-table th,.tnm-table td{padding:13px 15px;border-bottom:1px solid #edf0f5;text-align:left;font-size:14px}
.tnm-table th{background:#fafbfc;color:#667085;font-size:12px}
.tnm-badge{display:inline-block;padding:5px 9px;border-radius:999px;background:#eef6ff;color:#2463a6;font-size:12px}
.tnm-ok{background:#eaf8ef;color:#18824b}
.tnm-warn{background:#fff5df;color:#9a6500}
.tnm-hidden{display:none!important}
/* LOGIN */
.tnm-login{
position:fixed;inset:0;background:#f5f7fb;display:flex;
align-items:center;justify-content:center;z-index:100000
}
.tnm-login-box{
width:390px;background:#fff;padding:32px;border-radius:18px;
box-shadow:0 10px 40px #0002
}
.tnm-login-box h2{margin-top:0}
.tnm-login-box input{width:100%;margin:7px 0}
.tnm-login-box button{width:100%;margin-top:10px}
/* CALENDAR */
.tnm-calendar{
display:grid;
grid-template-columns:75px repeat(7,1fr);
background:#fff;border-radius:14px;overflow:auto;
box-shadow:0 3px 15px #0001
}
.tnm-calendar>div{
border-right:1px solid #edf0f5;
border-bottom:1px solid #edf0f5;
min-height:65px;padding:8px;font-size:12px
}
.tnm-day{
font-weight:bold;
text-align:center;
background:#fafbfc;
min-height:auto!important
}
.tnm-lesson{
background:#eaf3ff;
border-left:3px solid #3182ce;
border-radius:7px;
margin:2px;
padding:7px!important;
min-height:52px!important
}
/* MODAL */
.tnm-modal{
position:fixed;inset:0;background:#0007;
display:flex;align-items:center;justify-content:center;
z-index:100001
}
.tnm-modal-box{
background:#fff;border-radius:16px;padding:25px;
width:min(650px,94vw);max-height:90vh;overflow:auto
}
.tnm-form{
display:grid;
grid-template-columns:1fr 1fr;
gap:10px
}
.tnm-form input,.tnm-form select{width:100%}
.tnm-actions{
display:flex;
justify-content:flex-end;
gap:8px;
margin-top:18px
}
@media(max-width:900px){
.tnm-sidebar{width:70px}
.tnm-brand{font-size:0}
.tnm-brand span{font-size:18px}
.tnm-nav{font-size:0}
.tnm-nav::first-letter{font-size:18px}
.tnm-main{margin-left:70px;padding:18px}
.tnm-grid{grid-template-columns:repeat(2,1fr)}
}
@media(max-width:600px){
.tnm-grid{grid-template-columns:1fr 1fr}
.tnm-top h1{font-size:20px}
.tnm-user{font-size:12px}
.tnm-form{grid-template-columns:1fr}
}
</style>
<div id=”tnm-login” class=”tnm-login”>
<div class=”tnm-login-box”>
<h2>🎵 Thành Nam Music</h2>
<p style=”color:#667085″>
Hệ thống quản lý học viên
</p>
<input id=”tnm-login-user”
placeholder=”Tên đăng nhập”
value=”admin”>
<input id=”tnm-login-pass”
type=”password”
placeholder=”Mật khẩu”
value=”123456″>
<button onclick=”TNM.login()”>
Đăng nhập
</button>
<p style=”font-size:12px;color:#98a2b3″>
Demo: admin / 123456
</p>
</div>
</div>
<div id=”tnm-system” class=”tnm-hidden”>
<div class=”tnm-sidebar”>
<div class=”tnm-brand”>
THÀNH NAM <span>MUSIC</span>
</div>
<div class=”tnm-nav active” data-page=”dashboard”>
🏠 Tổng quan
</div>
<div class=”tnm-nav” data-page=”students”>
👨🎓 Học viên
</div>
<div class=”tnm-nav” data-page=”teachers”>
👨🏫 Giáo viên
</div>
<div class=”tnm-nav” data-page=”classes”>
🎼 Lớp học
</div>
<div class=”tnm-nav” data-page=”schedule”>
🗓️ Thời khóa biểu
</div>
<div class=”tnm-nav” data-page=”attendance”>
✅ Điểm danh
</div>
<div class=”tnm-nav” data-page=”branches”>
🏢 Cơ sở
</div>
<div class=”tnm-nav” data-page=”users”>
🔐 Tài khoản & quyền
</div>
<div class=”tnm-nav” onclick=”TNM.logout()”>
↪ Đăng xuất
</div>
</div>
<div class=”tnm-main”>
<div class=”tnm-top”>
<h1 id=”tnm-title”>
Tổng quan
</h1>
<div class=”tnm-user”>
👤 Quản lý
<span class=”tnm-badge”>ADMIN</span>
</div>
</div>
<section id=”tnm-dashboard”>
<div class=”tnm-grid”>
<div class=”tnm-card”>
<div class=”tnm-label”>Học viên đang học</div>
<div class=”tnm-number” id=”tnm-student-count”>128</div>
</div>
<div class=”tnm-card”>
<div class=”tnm-label”>Giáo viên</div>
<div class=”tnm-number”>18</div>
</div>
<div class=”tnm-card”>
<div class=”tnm-label”>Lớp hôm nay</div>
<div class=”tnm-number”>36</div>
</div>
<div class=”tnm-card”>
<div class=”tnm-label”>Có mặt hôm nay</div>
<div class=”tnm-number”>94%</div>
</div>
</div>
<div class=”tnm-section”>
<h2>Lịch học hôm nay</h2>
<div class=”tnm-table”>
<table>
<thead>
<tr>
<th>Giờ</th>
<th>Học viên / Lớp</th>
<th>Giáo viên</th>
<th>Cơ sở</th>
<th>Ca học</th>
<th>Trạng thái</th>
</tr>
</thead>
<tbody id=”tnm-today”></tbody>
</table>
</div>
</div>
</section>
<section id=”tnm-students” class=”tnm-hidden”>
<div class=”tnm-toolbar”>
<input
id=”tnm-search”
placeholder=”🔎 Tìm tên / SĐT…”
oninput=”TNM.renderStudents()”>
<select id=”tnm-branch-filter”
onchange=”TNM.renderStudents()”>
<option value=””>Tất cả cơ sở</option>
<option>Cơ sở 1</option>
<option>Cơ sở 2</option>
<option>Cơ sở 3</option>
<option>Cơ sở 4</option>
<option>Cơ sở 5</option>
</select>
<button onclick=”TNM.openStudent()”>
+ Thêm học viên
</button>
</div>
<div class=”tnm-table”>
<table>
<thead>
<tr>
<th>Học viên</th>
<th>SĐT HV / PH</th>
<th>Môn học</th>
<th>Loại lớp</th>
<th>Giáo viên</th>
<th>SĐT GV</th>
<th>Cơ sở</th>
<th>Thời lượng</th>
</tr>
</thead>
<tbody id=”tnm-student-rows”></tbody>
</table>
</div>
</section>
<section id=”tnm-teachers” class=”tnm-hidden”>
<div class=”tnm-toolbar”>
<button onclick=”alert(‘Chức năng thêm giáo viên sẽ được kết nối database ở phiên bản chính.’)”>
+ Thêm giáo viên
</button>
</div>
<div class=”tnm-table”>
<table>
<thead>
<tr>
<th>Giáo viên</th>
<th>SĐT</th>
<th>Chuyên môn</th>
<th>Cơ sở</th>
<th>Lịch đang dạy</th>
</tr>
</thead>
<tbody>
<tr>
<td><b>Nguyễn Minh Anh</b></td>
<td>0901 222 333</td>
<td>Piano</td>
<td>Cơ sở 1</td>
<td>14 ca / tuần</td>
</tr>
<tr>
<td><b>Trần Quốc Huy</b></td>
<td>0912 444 555</td>
<td>Guitar</td>
<td>Cơ sở 2</td>
<td>18 ca / tuần</td>
</tr>
<tr>
<td><b>Lê Thu Hà</b></td>
<td>0988 666 777</td>
<td>Thanh nhạc</td>
<td>Cơ sở 1, 3</td>
<td>16 ca / tuần</td>
</tr>
</tbody>
</table>
</div>
</section>
<section id=”tnm-classes” class=”tnm-hidden”>
<div class=”tnm-toolbar”>
<select>
<option>Tất cả loại lớp</option>
<option>Cá nhân 1:1</option>
<option>Tập thể 3–5</option>
</select>
<select>
<option>Tất cả thời lượng</option>
<option>15 phút – Học thử</option>
<option>30 phút</option>
<option>45 phút</option>
<option>60 phút</option>
</select>
<button onclick=”alert(‘Tạo lớp mới’)”>
+ Tạo lớp
</button>
</div>
<div class=”tnm-table”>
<table>
<thead>
<tr>
<th>Mã lớp</th>
<th>Loại lớp</th>
<th>Môn</th>
<th>Giáo viên</th>
<th>Học viên</th>
<th>Thời lượng</th>
<th>Trợ giảng</th>
<th>Cơ sở</th>
</tr>
</thead>
<tbody>
<tr>
<td>PI-001</td>
<td><span class=”tnm-badge”>Cá nhân 1:1</span></td>
<td>Piano</td>
<td>Nguyễn Minh Anh</td>
<td>Nguyễn Minh Khôi</td>
<td>60 phút</td>
<td>—</td>
<td>Cơ sở 1</td>
</tr>
<tr>
<td>GT-012</td>
<td><span class=”tnm-badge”>Tập thể 3–5</span></td>
<td>Guitar</td>
<td>Trần Quốc Huy</td>
<td>4 học viên</td>
<td>45 phút</td>
<td>Có</td>
<td>Cơ sở 2</td>
</tr>
</tbody>
</table>
</div>
</section>
<section id=”tnm-schedule” class=”tnm-hidden”>
<div class=”tnm-toolbar”>
<button class=”tnm-secondary”>‹ Tuần trước</button>
<button class=”tnm-secondary”>
Tuần này
</button>
<button class=”tnm-secondary”>
Tuần sau ›
</button>
<select>
<option>Tất cả cơ sở</option>
<option>Cơ sở 1</option>
<option>Cơ sở 2</option>
<option>Cơ sở 3</option>
<option>Cơ sở 4</option>
<option>Cơ sở 5</option>
</select>
</div>
<div class=”tnm-calendar”>
<div></div>
<div class=”tnm-day”>T2</div>
<div class=”tnm-day”>T3</div>
<div class=”tnm-day”>T4</div>
<div class=”tnm-day”>T5</div>
<div class=”tnm-day”>T6</div>
<div class=”tnm-day”>T7</div>
<div class=”tnm-day”>CN</div>
<div>08:00</div>
<div class=”tnm-lesson”>
08:00<br>
Piano<br>
<b>Minh Anh</b>
</div>
<div></div>
<div class=”tnm-lesson”>
08:00<br>
Guitar<br>
<b>Quốc Huy</b>
</div>
<div></div>
<div class=”tnm-lesson”>
08:00<br>
Piano
</div>
<div></div>
<div></div>
<div>09:00</div>
<div></div>
<div class=”tnm-lesson”>
09:00<br>
Thanh nhạc
</div>
<div></div>
<div class=”tnm-lesson”>
09:00<br>
Guitar nhóm
</div>
<div></div>
<div class=”tnm-lesson”>
09:00<br>
Piano nhóm
</div>
<div></div>
<div>10:00</div>
<div class=”tnm-lesson”>
10:00<br>
Piano 1:1
</div>
<div></div>
<div class=”tnm-lesson”>
10:00<br>
Guitar 1:1
</div>
<div></div>
<div></div>
<div class=”tnm-lesson”>
10:00<br>
Thanh nhạc
</div>
<div></div>
<div>14:00</div>
<div></div>
<div class=”tnm-lesson”>
14:00<br>
Piano 1:1
</div>
<div></div>
<div class=”tnm-lesson”>
14:00<br>
Piano 1:1
</div>
<div></div>
<div class=”tnm-lesson”>
14:00<br>
Guitar nhóm
</div>
<div></div>
<div>18:00</div>
<div class=”tnm-lesson”>18:00<br>Piano 1:1</div>
<div class=”tnm-lesson”>18:00<br>Guitar nhóm</div>
<div class=”tnm-lesson”>18:00<br>Piano 1:1</div>
<div class=”tnm-lesson”>18:00<br>Thanh nhạc</div>
<div class=”tnm-lesson”>18:00<br>Guitar nhóm</div>
<div class=”tnm-lesson”>18:00<br>Piano nhóm</div>
<div></div>
</div>
</section>
<section id=”tnm-attendance” class=”tnm-hidden”>
<div class=”tnm-toolbar”>
<input type=”date” id=”tnm-date”>
<select>
<option>Tất cả cơ sở</option>
<option>Cơ sở 1</option>
<option>Cơ sở 2</option>
<option>Cơ sở 3</option>
</select>
<button onclick=”TNM.quickAttendance()”>
Điểm danh nhanh
</button>
</div>
<div class=”tnm-table”>
<table>
<thead>
<tr>
<th>Giờ</th>
<th>Học viên</th>
<th>Loại lớp</th>
<th>Giáo viên</th>
<th>Trạng thái</th>
<th>Ghi chú</th>
</tr>
</thead>
<tbody id=”tnm-attendance”></tbody>
</table>
</div>
</section>
<section id=”tnm-branches” class=”tnm-hidden”>
<div class=”tnm-grid”>
<div class=”tnm-card”>
<b>Cơ sở 1</b>
<p>7 phòng học</p>
<span class=”tnm-badge tnm-ok”>Đang hoạt động</span>
</div>
<div class=”tnm-card”>
<b>Cơ sở 2</b>
<p>5 phòng học</p>
<span class=”tnm-badge tnm-ok”>Đang hoạt động</span>
</div>
<div class=”tnm-card”>
<b>Cơ sở 3</b>
<p>4 phòng học</p>
<span class=”tnm-badge tnm-ok”>Đang hoạt động</span>
</div>
<div class=”tnm-card”>
<b>Cơ sở 4</b>
<p>3 phòng học</p>
<span class=”tnm-badge tnm-ok”>Đang hoạt động</span>
</div>
<div class=”tnm-card”>
<b>Cơ sở 5</b>
<p>Đang thiết lập</p>
<span class=”tnm-badge tnm-warn”>Chưa kích hoạt</span>
</div>
</div>
</section>
<section id=”tnm-users” class=”tnm-hidden”>
<div class=”tnm-card”>
<h2>Phân quyền hệ thống</h2>
<p>
<b>Super Admin</b><br>
Toàn quyền hệ thống.
</p>
<p>
<b>Quản lý cơ sở</b><br>
Quản lý học viên, giáo viên, lịch và điểm danh tại cơ sở được phân quyền.
</p>
<p>
<b>Giáo viên</b><br>
Xem lịch, lớp phụ trách, điểm danh và nhận xét học viên.
</p>
<p>
<b>Lễ tân</b><br>
Quản lý học viên, lịch và điểm danh.
</p>
<p>
<b>Trợ giảng</b><br>
Xem lớp được phân công và hỗ trợ điểm danh.
</p>
</div>
</section>
</div>
</div>
<div id=”tnm-modal” class=”tnm-modal tnm-hidden”>
<div class=”tnm-modal-box”>
<h2>Thêm học viên</h2>
<div class=”tnm-form”>
<input id=”tnm-name” placeholder=”Họ và tên *”>
<input id=”tnm-phone” placeholder=”SĐT học viên / phụ huynh *”>
<input id=”tnm-subject” placeholder=”Môn học” value=”Piano”>
<select id=”tnm-new-branch”>
<option>Cơ sở 1</option>
<option>Cơ sở 2</option>
<option>Cơ sở 3</option>
<option>Cơ sở 4</option>
<option>Cơ sở 5</option>
</select>
<select id=”tnm-type”>
<option>Cá nhân 1:1</option>
<option>Tập thể 3–5</option>
</select>
<select id=”tnm-duration”>
<option>15 phút – Học thử</option>
<option>30 phút</option>
<option>45 phút</option>
<option selected>60 phút</option>
</select>
<input id=”tnm-teacher” placeholder=”Giáo viên”>
<input id=”tnm-teacher-phone” placeholder=”SĐT giáo viên”>
</div>
<div class=”tnm-actions”>
<button
class=”tnm-secondary”
onclick=”TNM.closeStudent()”>
Hủy
</button>
<button onclick=”TNM.addStudent()”>
Lưu học viên
</button>
</div>
</div>
</div>
<script>
(function(){
let students=[
{
name:”Nguyễn Minh Khôi”,
phone:”0912 345 678″,
subject:”Piano”,
type:”Cá nhân 1:1″,
teacher:”Nguyễn Minh Anh”,
tphone:”0901 222 333″,
branch:”Cơ sở 1″,
duration:”60 phút”
},
{
name:”Trần Gia Hân”,
phone:”0987 123 456″,
subject:”Guitar”,
type:”Tập thể 3–5″,
teacher:”Trần Quốc Huy”,
tphone:”0912 444 555″,
branch:”Cơ sở 2″,
duration:”45 phút”
},
{
name:”Phạm Hoàng Nam”,
phone:”0909 555 222″,
subject:”Thanh nhạc”,
type:”Cá nhân 1:1″,
teacher:”Lê Thu Hà”,
tphone:”0988 666 777″,
branch:”Cơ sở 1″,
duration:”30 phút”
}
];
const lessons=[
[“08:00″,”Nguyễn Minh Khôi”,”Nguyễn Minh Anh”,”Cơ sở 1″,”60 phút”,”Có mặt”],
[“09:00″,”Trần Gia Hân + 3 HV”,”Trần Quốc Huy”,”Cơ sở 2″,”45 phút”,”Đã điểm danh”],
[“10:00″,”Phạm Hoàng Nam”,”Lê Thu Hà”,”Cơ sở 1″,”30 phút”,”Chờ điểm danh”],
[“14:00″,”Nguyễn Minh Khôi”,”Nguyễn Minh Anh”,”Cơ sở 1″,”60 phút”,”Có mặt”]
];
window.TNM={
login:function(){
document.getElementById(“tnm-login”).classList.add(“tnm-hidden”);
document.getElementById(“tnm-system”).classList.remove(“tnm-hidden”);
this.renderStudents();
this.renderToday();
this.renderAttendance();
},
logout:function(){
document.getElementById(“tnm-system”).classList.add(“tnm-hidden”);
document.getElementById(“tnm-login”).classList.remove(“tnm-hidden”);
},
show:function(page,nav){
document.querySelectorAll(“#tnm-system section”)
.forEach(function(x){
x.classList.add(“tnm-hidden”);
});
document.getElementById(“tnm-“+page)
.classList.remove(“tnm-hidden”);
document.querySelectorAll(“.tnm-nav”)
.forEach(function(x){
x.classList.remove(“active”);
});
if(nav) nav.classList.add(“active”);
let titles={
dashboard:”Tổng quan”,
students:”Quản lý học viên”,
teachers:”Quản lý giáo viên”,
classes:”Quản lý lớp học”,
schedule:”Thời khóa biểu”,
attendance:”Điểm danh”,
branches:”Quản lý cơ sở”,
users:”Tài khoản & phân quyền”
};
document.getElementById(“tnm-title”).textContent=titles[page];
},
renderStudents:function(){
let q=(document.getElementById(“tnm-search”).value||””).toLowerCase();
let branch=document.getElementById(“tnm-branch-filter”).value;
let rows=students.filter(function(s){
return (!q ||
(s.name+s.phone+s.subject).toLowerCase().includes(q))
&&
(!branch || s.branch===branch);
});
document.getElementById(“tnm-student-rows”).innerHTML=
rows.map(function(s){
return `
<tr>
<td><b>${s.name}</b></td>
<td>${s.phone}</td>
<td>${s.subject}</td>
<td>${s.type}</td>
<td>${s.teacher}</td>
<td>${s.tphone}</td>
<td>${s.branch}</td>
<td>
<span class=”tnm-badge”>
${s.duration}
</span>
</td>
</tr>
`;
}).join(“”);
document.getElementById(“tnm-student-count”)
.textContent=125+students.length;
},
renderToday:function(){
document.getElementById(“tnm-today”).innerHTML=
lessons.map(function(x){
return `
<tr>
<td>${x[0]}</td>
<td><b>${x[1]}</b></td>
<td>${x[2]}</td>
<td>${x[3]}</td>
<td>${x[4]}</td>
<td>
<span class=”tnm-badge ${
x[5].includes(“Chờ”)?”tnm-warn”:”tnm-ok”
}”>
${x[5]}
</span>
</td>
</tr>
`;
}).join(“”);
},
renderAttendance:function(){
document.getElementById(“tnm-attendance”).innerHTML=
lessons.map(function(x,i){
return `
<tr>
<td>${x[0]}</td>
<td><b>${x[1]}</b></td>
<td>${i===1?”Tập thể 3–5″:”Cá nhân 1:1″}</td>
<td>${x[2]}</td>
<td>
<select>
<option>Có mặt</option>
<option>Vắng</option>
<option>Đi muộn</option>
<option>Nghỉ có phép</option>
<option>Học bù</option>
</select>
</td>
<td>
<input placeholder=”Ghi chú…”>
</td>
</tr>
`;
}).join(“”);
},
openStudent:function(){
document.getElementById(“tnm-modal”)
.classList.remove(“tnm-hidden”);
},
closeStudent:function(){
document.getElementById(“tnm-modal”)
.classList.add(“tnm-hidden”);
},
addStudent:function(){
let name=document.getElementById(“tnm-name”).value;
let phone=document.getElementById(“tnm-phone”).value;
if(!name || !phone){
alert(“Vui lòng nhập họ tên và SĐT.”);
return;
}
students.push({
name:name,
phone:phone,
subject:document.getElementById(“tnm-subject”).value,
type:document.getElementById(“tnm-type”).value,
teacher:document.getElementById(“tnm-teacher”).value || “Chưa phân công”,
tphone:document.getElementById(“tnm-teacher-phone”).value || “—”,
branch:document.getElementById(“tnm-new-branch”).value,
duration:document.getElementById(“tnm-duration”).value
});
this.closeStudent();
this.renderStudents();
alert(“Đã thêm học viên.”);
},
quickAttendance:function(){
alert(
“Đã mở chế độ điểm danh nhanh.\n\n”+
“Có mặt\n”+
“Vắng\n”+
“Đi muộn\n”+
“Nghỉ có phép\n”+
“Học bù”
);
}
};
document.querySelectorAll(“#tnm-system .tnm-nav[data-page]”)
.forEach(function(nav){
nav.addEventListener(“click”,function(){
TNM.show(this.dataset.page,this);
});
});
document.getElementById(“tnm-date”).value=
new Date().toISOString().slice(0,10);
})();
</script>
</div>
