index.html · 约 17083 字符
1<!DOCTYPE html>
2<html lang="zh-CN">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
6<title>教师点评</title>
7<script src="../_vendor/jquery.min.js"></script>
8<style>
9 * { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
10 :root{
11 --blue:#2563eb; --blue2:#1d4ed8; --cyan:#06b6d4; --amber:#f59e0b;
12 --red:#ef4444; --green:#22c55e; --bg:#f4f6fb; --card:#ffffff;
13 --text:#1f2937; --mute:#8a93a6; --line:#eef1f6;
14 }
15 body{ font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
16 background:#dfe4ee; color:var(--text); }
17 .app{ max-width:430px; margin:0 auto; min-height:100vh; background:var(--bg);
18 position:relative; padding-bottom:64px; box-shadow:0 0 28px rgba(0,0,0,.08); }
19 .topbar{ background:linear-gradient(120deg,var(--blue),var(--cyan)); color:#fff;
20 padding:18px 18px 16px; }
21 .topbar .brand{ font-size:21px; font-weight:800; letter-spacing:.5px; }
22 .topbar .sub{ font-size:12.5px; opacity:.9; margin-top:4px; }
23 .views{ padding:14px; }
24 .view{ display:none; }
25 .view.active{ display:block; animation:fade .25s ease; }
26 @keyframes fade{ from{opacity:0;transform:translateY(6px)} to{opacity:1;transform:none} }
27 .card{ background:var(--card); border-radius:16px; padding:15px; margin-bottom:13px;
28 box-shadow:0 4px 16px rgba(31,41,55,.05); }
29 .card h3{ font-size:15px; margin-bottom:12px; display:flex; align-items:center; gap:7px; }
30 .card h3 .ic{ font-size:17px; }
31 .hint{ font-size:12px; color:var(--mute); margin:-6px 0 12px; }
32 /* 选老师 */
33 .chips{ display:flex; gap:9px; overflow-x:auto; padding-bottom:4px; }
34 .chips::-webkit-scrollbar{ display:none; }
35 .tchip{ flex:0 0 auto; padding:9px 13px; border-radius:999px; background:#f0f3f9;
36 border:1.5px solid transparent; font-size:13.5px; font-weight:600; color:#475069; white-space:nowrap; }
37 .tchip.on{ background:#e8f0ff; border-color:var(--blue); color:var(--blue2); }
38 /* 维度打分 */
39 .dim{ display:flex; align-items:center; justify-content:space-between; padding:9px 0; border-bottom:1px solid var(--line); }
40 .dim:last-child{ border-bottom:none; }
41 .dim .name{ font-size:14px; font-weight:600; }
42 .stars{ display:flex; gap:5px; }
43 .star{ font-size:23px; color:#d8dee9; cursor:pointer; transition:.12s; line-height:1; }
44 .star.on{ color:var(--amber); transform:scale(1.06); }
45 textarea{ width:100%; margin-top:10px; border:1.5px solid var(--line); border-radius:12px;
46 padding:11px; font-size:13.5px; resize:none; height:74px; font-family:inherit; color:var(--text); }
47 textarea:focus{ outline:none; border-color:var(--blue); }
48 .btn{ width:100%; margin-top:13px; padding:13px; border:none; border-radius:13px;
49 background:linear-gradient(120deg,var(--blue),var(--cyan)); color:#fff; font-size:15.5px;
50 font-weight:800; cursor:pointer; letter-spacing:1px; }
51 .btn:active{ transform:scale(.99); }
52 /* 榜单 */
53 .lead{ font-size:12.5px; color:var(--mute); margin-bottom:10px; }
54 .trow{ display:flex; align-items:center; gap:12px; padding:12px 4px; border-bottom:1px solid var(--line); cursor:pointer; }
55 .trow:active{ background:#fafbff; }
56 .rank{ width:26px; text-align:center; font-weight:800; font-size:16px; color:var(--mute); }
57 .rank.g{ color:var(--amber); }
58 .ava{ width:42px; height:42px; border-radius:12px; background:#eef2ff; display:flex; align-items:center;
59 justify-content:center; font-size:23px; flex:0 0 auto; }
60 .tinfo{ flex:1; min-width:0; }
61 .tinfo .nm{ font-size:15px; font-weight:700; }
62 .tinfo .sb{ font-size:12px; color:var(--mute); margin-top:2px; }
63 .tscore{ text-align:right; flex:0 0 auto; }
64 .tscore .v{ font-size:19px; font-weight:800; color:var(--blue2); }
65 .tscore .c{ font-size:11.5px; color:var(--mute); margin-top:2px; }
66 .bar{ height:6px; border-radius:6px; background:#eef1f6; margin-top:7px; overflow:hidden; }
67 .bar > i{ display:block; height:100%; border-radius:6px; background:linear-gradient(90deg,var(--blue),var(--cyan)); }
68 /* 公示 */
69 .fault{ border-left:4px solid var(--red); background:#fff5f5; border-radius:0 12px 12px 0; padding:12px 14px; margin-bottom:11px; }
70 .fault .ft{ display:flex; align-items:center; justify-content:space-between; margin-bottom:6px; }
71 .fault .ft .tn{ font-size:14.5px; font-weight:800; }
72 .tag{ font-size:11px; font-weight:700; padding:3px 9px; border-radius:999px; }
73 .tag.red{ background:#ffe1e1; color:#d62727; }
74 .tag.amber{ background:#fff0d6; color:#b9740a; }
75 .tag.green{ background:#ddfbe6; color:#15803d; }
76 .fault .ty{ font-size:13px; font-weight:700; color:#b91c1c; margin-bottom:3px; }
77 .fault .ds{ font-size:12.5px; color:#6b7280; line-height:1.55; }
78 .fault .dt{ font-size:11px; color:#9ca3af; margin-top:6px; }
79 /* 我的 */
80 .empty{ text-align:center; color:var(--mute); padding:50px 20px; font-size:13.5px; }
81 .empty .e{ font-size:40px; margin-bottom:12px; }
82 .rev{ border:1px solid var(--line); border-radius:13px; padding:13px; margin-bottom:11px; }
83 .rev .rh{ display:flex; justify-content:space-between; align-items:center; margin-bottom:8px; }
84 .rev .rh .tn{ font-weight:700; font-size:14.5px; }
85 .rev .rh .tm{ font-size:11px; color:var(--mute); }
86 .rev .rs{ font-size:12px; color:var(--mute); margin-bottom:7px; }
87 .rev .rs b{ color:var(--blue2); }
88 .rev .rt{ font-size:13px; color:#4b5563; line-height:1.55; background:#f7f9fc; border-radius:9px; padding:8px 10px; }
89 /* tabbar */
90 .tabbar{ position:fixed; bottom:0; left:50%; transform:translateX(-50%); width:100%; max-width:430px;
91 height:60px; background:#fff; border-top:1px solid var(--line); display:flex; }
92 .tabbar button{ flex:1; border:none; background:none; font-size:11.5px; color:var(--mute);
93 display:flex; flex-direction:column; align-items:center; justify-content:center; gap:3px; cursor:pointer; }
94 .tabbar button .ti{ font-size:20px; }
95 .tabbar button.on{ color:var(--blue); font-weight:700; }
96 /* sheet */
97 .mask{ position:fixed; inset:0; background:rgba(15,23,42,.45); opacity:0; pointer-events:none;
98 transition:.25s; z-index:30; }
99 .mask.show{ opacity:1; pointer-events:auto; }
100 .sheet{ position:fixed; left:50%; bottom:0; transform:translate(-50%,100%); width:100%; max-width:430px;
101 background:#fff; border-radius:20px 20px 0 0; padding:20px 18px 28px; transition:.3s; z-index:31; }
102 .sheet.show{ transform:translate(-50%,0); }
103 .sheet .sh{ display:flex; align-items:center; gap:12px; margin-bottom:16px; }
104 .sheet .sh .ava{ width:52px; height:52px; font-size:28px; }
105 .sheet .sh .nm{ font-size:18px; font-weight:800; }
106 .sheet .sh .sb{ font-size:12.5px; color:var(--mute); margin-top:3px; }
107 .sheet .close{ margin-left:auto; font-size:22px; color:var(--mute); cursor:pointer; }
108 .dist{ display:flex; align-items:center; gap:10px; margin:10px 0; }
109 .dist .dn{ width:74px; font-size:13px; color:#475069; flex:0 0 auto; }
110 .dist .db{ flex:1; height:9px; background:#eef1f6; border-radius:9px; overflow:hidden; }
111 .dist .db > i{ display:block; height:100%; background:linear-gradient(90deg,var(--amber),#fb923c); border-radius:9px; }
112 .dist .dv{ width:30px; text-align:right; font-size:12.5px; font-weight:700; color:var(--amber); }
113 /* toast */
114 .toast{ position:fixed; left:50%; top:42%; transform:translate(-50%,-50%) scale(.9); z-index:50;
115 background:rgba(17,24,39,.9); color:#fff; padding:13px 22px; border-radius:12px; font-size:14px;
116 font-weight:700; opacity:0; pointer-events:none; transition:.2s; }
117 .toast.show{ opacity:1; transform:translate(-50%,-50%) scale(1); }
118</style>
119</head>
120<body>
121<div class="app">
122 <header class="topbar">
123 <div class="brand">📝 教师点评</div>
124 <div class="sub">多维度评分 · 公开榜单 · 教师过错公示</div>
125 </header>
126
127 <main class="views">
128 <!-- 点评打分 -->
129 <section class="view active" id="view-pingfen">
130 <div class="card">
131 <h3><span class="ic">🎯</span>选择要评价的教师</h3>
132 <div class="chips" id="teacherChips"></div>
133 </div>
134 <div class="card">
135 <h3><span class="ic">⭐</span>多维度打分</h3>
136 <p class="hint">点击星星为每个维度评分(1~5 星)</p>
137 <div id="dimList"></div>
138 <textarea id="reviewText" placeholder="写下你对老师的具体评价或建议…"></textarea>
139 <button class="btn" id="submitBtn">提交点评</button>
140 </div>
141 </section>
142
143 <!-- 榜单 -->
144 <section class="view" id="view-bangdan">
145 <div class="card">
146 <h3><span class="ic">🏆</span>教师好评榜</h3>
147 <p class="lead">按学生综合评分排序,点击查看维度分布</p>
148 <div id="rankList"></div>
149 </div>
150 </section>
151
152 <!-- 过错公示 -->
153 <section class="view" id="view-gongshi">
154 <div class="card">
155 <h3><span class="ic">📢</span>教师过错公示</h3>
156 <p class="lead">教学失职、违纪行为公开通报,接受监督</p>
157 <div id="faultList"></div>
158 </div>
159 </section>
160
161 <!-- 我的 -->
162 <section class="view" id="view-mine">
163 <div class="card">
164 <h3><span class="ic">👤</span>我的点评</h3>
165 <div id="myList"></div>
166 </div>
167 </section>
168 </main>
169
170 <nav class="tabbar">
171 <button data-v="pingfen" class="on"><span class="ti">📝</span>点评</button>
172 <button data-v="bangdan"><span class="ti">🏆</span>榜单</button>
173 <button data-v="gongshi"><span class="ti">📢</span>公示</button>
174 <button data-v="mine"><span class="ti">👤</span>我的</button>
175 </nav>
176</div>
177
178<div class="mask" id="mask"></div>
179<div class="sheet" id="sheet">
180 <div class="sh">
181 <div class="ava" id="shAva">👩🏫</div>
182 <div>
183 <div class="nm" id="shName">教师</div>
184 <div class="sb" id="shSub">科目</div>
185 </div>
186 <div class="close" id="shClose">✕</div>
187 </div>
188 <div id="shDist"></div>
189</div>
190<div class="toast" id="toast"></div>
191
192<script>
193var DIMS = ["教学态度","专业水平","课堂互动","作业批改","责任心","答疑及时"];
194var TEACHERS = [
195 {id:1,name:"王敏",emoji:"👩🏫",sub:"高中语文",score:4.8,cnt:326,dims:[5,5,4,5,5,4]},
196 {id:2,name:"李建国",emoji:"👨🏫",sub:"初中数学",score:4.6,cnt:288,dims:[5,4,4,5,4,5]},
197 {id:3,name:"张雪",emoji:"👩🏫",sub:"小学英语",score:4.9,cnt:412,dims:[5,5,5,5,5,4]},
198 {id:4,name:"陈涛",emoji:"👨🏫",sub:"高中物理",score:4.3,cnt:201,dims:[4,5,3,4,4,4]},
199 {id:5,name:"刘洋",emoji:"🧑🏫",sub:"初中化学",score:4.5,cnt:243,dims:[4,5,4,4,4,5]},
200 {id:6,name:"赵琳",emoji:"👩🏫",sub:"小学音乐",score:4.7,cnt:176,dims:[5,4,5,4,5,4]}
201];
202var FAULTS = [
203 {t:"陈涛",type:"上课迟到",desc:"9月12日第3节课迟到8分钟,影响正常教学秩序。",status:"已通报",tag:"red",date:"09-12"},
204 {t:"李建国",type:"作业批改不及时",desc:"连续两周未批改单元测验,家长多次反映后补批。",status:"处理中",tag:"amber",date:"09-18"},
205 {t:"王敏",type:"课堂言论不当",desc:"授课中使用不恰当比喻,已约谈并责令书面检查。",status:"已整改",tag:"green",date:"09-05"},
206 {t:"刘洋",type:"实验安全管理疏漏",desc:"化学实验课未按要求清点器材,存在安全隐患。",status:"已通报",tag:"red",date:"09-20"},
207 {t:"赵琳",type:"擅自调课",desc:"未报备私自与其他教师调换课程,造成学生空堂。",status:"处理中",tag:"amber",date:"09-15"}
208];
209
210var sel = { tid:null, scores:{} };
211
212function toast(msg){ var t=$("#toast"); t.text(msg).addClass("show"); setTimeout(function(){ t.removeClass("show"); },1400); }
213
214function renderChips(){
215 var h = TEACHERS.map(function(t){
216 return '<div class="tchip" data-tid="'+t.id+'">'+t.emoji+' '+t.name+'</div>';
217 }).join("");
218 $("#teacherChips").html(h);
219 $("#teacherChips .tchip").on("click", function(){
220 $("#teacherChips .tchip").removeClass("on");
221 $(this).addClass("on");
222 sel.tid = parseInt($(this).data("tid"));
223 });
224}
225function renderDims(){
226 var h = DIMS.map(function(d){
227 return '<div class="dim" data-dim="'+d+'"><span class="name">'+d+'</span>'+
228 '<div class="stars">'+'<span class="star" data-v="1">★</span><span class="star" data-v="2">★</span>'+
229 '<span class="star" data-v="3">★</span><span class="star" data-v="4">★</span><span class="star" data-v="5">★</span>'+
230 '</div></div>';
231 }).join("");
232 $("#dimList").html(h);
233 $("#dimList .dim").each(function(){
234 var dim = $(this).data("dim");
235 $(this).find(".star").on("click", function(){
236 var v = parseInt($(this).data("v"));
237 sel.scores[dim] = v;
238 $(this).parent().find(".star").removeClass("on");
239 $(this).prevAll(".star").addBack().addClass("on");
240 });
241 });
242}
243function renderRank(){
244 var sorted = TEACHERS.slice().sort(function(a,b){ return b.score-a.score; });
245 var h = sorted.map(function(t,i){
246 var medal = i===0?"🥇":i===1?"🥈":i===2?"🥉":(i+1);
247 var g = i<3?" g":"";
248 return '<div class="trow" data-tid="'+t.id+'"><div class="rank'+g+'">'+medal+'</div>'+
249 '<div class="ava">'+t.emoji+'</div>'+
250 '<div class="tinfo"><div class="nm">'+t.name+'</div><div class="sb">'+t.sub+'</div>'+
251 '<div class="bar"><i style="width:'+(t.score/5*100)+'%"></i></div></div>'+
252 '<div class="tscore"><div class="v">'+t.score.toFixed(1)+'</div><div class="c">'+t.cnt+' 评</div></div></div>';
253 }).join("");
254 $("#rankList").html(h);
255 $("#rankList .trow").on("click", function(){ openSheet(parseInt($(this).data("tid"))); });
256}
257function renderFaults(){
258 var h = FAULTS.map(function(f){
259 return '<div class="fault"><div class="ft"><span class="tn">'+f.t+'</span>'+
260 '<span class="tag '+f.tag+'">'+f.status+'</span></div>'+
261 '<div class="ty">⚠ '+f.type+'</div><div class="ds">'+f.desc+'</div>'+
262 '<div class="dt">公示日期:'+f.date+'</div></div>';
263 }).join("");
264 $("#faultList").html(h);
265}
266function renderMine(){
267 var raw = localStorage.getItem("teacher_reviews");
268 var list = raw? JSON.parse(raw): [];
269 if(!list.length){ $("#myList").html('<div class="empty"><div class="e">🗒️</div>还没有点评记录<br>去「点评」给老师打分吧</div>'); return; }
270 var h = list.slice().reverse().map(function(r){
271 var avg = (r.scores.reduce(function(a,b){return a+b;},0)/r.scores.length).toFixed(1);
272 var dims = DIMS.map(function(d,i){ return d+" "+r.scores[i]+"★"; }).join(" · ");
273 return '<div class="rev"><div class="rh"><span class="tn">'+r.tname+'</span><span class="tm">'+r.time+'</span></div>'+
274 '<div class="rs">综合 <b>'+avg+'</b> 星 | '+dims+'</div>'+
275 (r.text?'<div class="rt">'+r.text+'</div>':'')+'</div>';
276 }).join("");
277 $("#myList").html(h);
278}
279function openSheet(tid){
280 var t = TEACHERS.filter(function(x){return x.id===tid;})[0]; if(!t) return;
281 $("#shAva").text(t.emoji); $("#shName").text(t.name); $("#shSub").text(t.sub+" · 综合 "+t.score.toFixed(1)+" 星");
282 var d = $("#shDist").empty();
283 DIMS.forEach(function(name,i){
284 d.append('<div class="dist"><span class="dn">'+name+'</span><div class="db"><i style="width:'+(t.dims[i]/5*100)+'%"></i></div><span class="dv">'+t.dims[i]+'</span></div>');
285 });
286 $("#mask").addClass("show"); $("#sheet").addClass("show");
287}
288function closeSheet(){ $("#mask").removeClass("show"); $("#sheet").removeClass("show"); }
289
290$(function(){
291 renderChips(); renderDims(); renderRank(); renderFaults(); renderMine();
292 $(".tabbar button").on("click", function(){
293 $(".tabbar button").removeClass("on"); $(this).addClass("on");
294 $(".view").removeClass("active"); $("#view-"+$(this).data("v")).addClass("active");
295 if($(this).data("v")==="mine") renderMine();
296 });
297 $("#shClose").on("click", closeSheet); $("#mask").on("click", closeSheet);
298 $("#submitBtn").on("click", function(){
299 if(!sel.tid){ toast("请先选择教师"); return; }
300 for(var i=0;i<DIMS.length;i++){ if(!sel.scores[DIMS[i]]){ toast("请完成全部维度评分"); return; } }
301 var t = TEACHERS.filter(function(x){return x.id===sel.tid;})[0];
302 var rec = { tid:sel.tid, tname:t.name, scores:DIMS.map(function(d){return sel.scores[d];}),
303 text:$("#reviewText").val().trim(), time:new Date().toLocaleString("zh-CN",{hour12:false}) };
304 var raw = localStorage.getItem("teacher_reviews"); var list = raw?JSON.parse(raw):[];
305 list.push(rec); localStorage.setItem("teacher_reviews", JSON.stringify(list));
306 toast("点评提交成功 ✓");
307 sel = { tid:null, scores:{} }; $("#teacherChips .tchip").removeClass("on");
308 $("#dimList .star").removeClass("on"); $("#reviewText").val("");
309 });
310});
311</script>
312</body>
313</html>