r100/app.js · 约 32423 字符
1/* 星河三班 · 班级主页 H5 — 单页多视图 / hash 路由 / 底部 Tab */2(function($){3 "use strict";45 /* ============ 数据源(演示) ============ */6 const CLS = {7 name:"星河三班", grade:"2023级 · 3班", motto:"聚是一团火,散是满天星",8 head:"李慕白", counsel:"王语嫣",9 intro:"星河三班是由 42 名同学组成的温暖大家庭。我们以「笃学、向善、共进」为班风,在学业与活动中彼此成就,让每一位同学都能发光。",10 committee:[["班长","张明"],["团支书","林清"],["学习委员","陈思"],["生活委员","赵磊"],["宣传委员","周婷"]]11 };12 const BANNERS=[13 {t:"2026 春季运动会",s:"蝉联团体总分第一 · 为班级荣耀而战"},14 {t:"星河三班 风采展",s:"记录我们在一起的每一个闪光瞬间"},15 {t:"期末表彰大会",s:"优秀之星揭晓,下一站更闪耀"}16 ];17 const HONORS=[18 {m:"🏆",t:"校级优秀班集体",s:"2025 学年"},19 {m:"🥇",t:"运动会团体第一",s:"连续两届"},20 {m:"🌟",t:"五四红旗团支部",s:"校级荣誉"},21 {m:"📜",t:"文明宿舍标兵",s:"1舍 / 3舍"}22 ];23 const NOTICES=[24 {id:"n1",cat:"行政",top:1,title:"关于下周升旗仪式着装要求的通知",time:"2026-07-20",read:40,total:42,25 body:"各同学:<br>下周一(7月27日)晨将举行全校升旗仪式,请全体同学统一穿着白色上衣、深色长裤,佩戴红领巾/团徽,7:40 前到操场集合。考勤将计入班级量化。<br><br>如遇雨天改为室内班会,另行通知。"},26 {id:"n2",cat:"教学",top:0,title:"期中考试安排及考场纪律",time:"2026-07-18",read:38,total:42,27 body:"期中考试定于 7 月 29 日—31 日进行。请同学们带好学生证、2B 铅笔与黑色签字笔,严禁携带电子设备入场。"},28 {id:"n3",cat:"活动",top:0,title:"班级春游报名开始啦 🚌",time:"2026-07-15",read:42,total:42,29 body:"西山营地一日游报名通道已开启,名额 40 人,先到先得!详情见「活动」板块。"},30 {id:"n4",cat:"放假",top:0,title:"暑期放假及安全须知",time:"2026-07-10",read:35,total:42,31 body:"暑期自 7 月 15 日起至 8 月 31 日。请同学们注意防溺水、防诈骗与交通安全,每日健康打卡别忘了。"}32 ];33 const HOMEWORK=[34 {id:"h1",course:"高等数学",title:"习题 3.1 — 3.5 全做",due:"2026-07-22",status:"待提交"},35 {id:"h2",course:"大学英语",title:"Unit 5 写作 Task 2",due:"2026-07-21",status:"已提交"},36 {id:"h3",course:"数据结构",title:"实验三:二叉树遍历",due:"2026-07-19",status:"已批改",score:"92"},37 {id:"h4",course:"线性代数",title:"矩阵运算专题练习",due:"2026-07-25",status:"待提交"}38 ];39 const MEMBERS=[40 {n:"李慕白",sid:"T001",role:"老师",grp:"班主任",av:"👨🏫",ph:"138****0001"},41 {n:"张明",sid:"20230101",role:"班委",grp:"1舍",av:"🧑💼",ph:"138****0101"},42 {n:"林清",sid:"20230102",role:"班委",grp:"1舍",av:"👩🎓",ph:"138****0102"},43 {n:"陈思",sid:"20230103",role:"班委",grp:"2组",av:"🧑🔬",ph:"138****0103"},44 {n:"赵磊",sid:"20230104",role:"班委",grp:"2组",av:"🧑🍳",ph:"138****0104"},45 {n:"王浩",sid:"20230105",role:"学生",grp:"1舍",av:"🧑",ph:"138****0105"},46 {n:"刘洋",sid:"20230106",role:"学生",grp:"3组",av:"🧑",ph:"138****0106"},47 {n:"孙悦",sid:"20230107",role:"学生",grp:"1舍",av:"👧",ph:"138****0107"}48 ];49 const GROUPS=[50 {t:"宿舍分组",items:["1舍 · 张明/林清/孙悦 等 6 人","2舍 · 刘洋/周婷 等 6 人","3舍 · 赵磊/陈思 等 6 人"]},51 {t:"学习小组",items:["高数攻坚组 · 8 人","英语晨读组 · 10 人","科创竞赛组 · 6 人"]},52 {t:"班委职能",items:["班委群 · 5 人","宣传小组 · 3 人","活动策划组 · 4 人"]}53 ];54 const FEED=[55 {id:"p1",nm:"张明",av:"🧑💼",tm:"2小时前",tx:"今天班会有奖问答太热闹了!大家准备的节目一个比一个精彩 🎉 为咱星河三班点赞!",56 imgs:["📸","🏆","🍿"],likes:23,cmts:[["林清","班长组织得太用心啦~"],["孙悦","下次我也要报名表演!"]]},57 {id:"p2",nm:"林清",av:"👩🎓",tm:"昨天",tx:"五四合唱我们班拿了一等奖!🥇 一个月的排练都值得了,爱这个集体。",58 imgs:["🎤","🌟"],likes:41,cmts:[["陈思","实至名归!"]]},59 {id:"p3",nm:"孙悦",av:"👧",tm:"3天前",tx:"图书馆打卡第 30 天 ✨ 一起卷起来,期末冲冲冲!",60 imgs:["📚","✏️","☕"],likes:18,cmts:[]},61 {id:"p4",nm:"陈思",av:"🧑🔬",tm:"4天前",tx:"高数复习笔记已共享到资源库啦,需要的同学自取~有疑问随时私信我。",62 imgs:["📒"],likes:30,cmts:[["王浩","太感谢了!"]]}63 ];64 const BLESS=[65 {n:"匿名",tx:"祝星河三班永远闪闪发光 🌟",an:1},66 {n:"王浩",tx:"毕业快乐,后会有期,常联系!",an:0},67 {n:"林清",tx:"愿我们都被世界温柔以待 💕",an:0},68 {n:"匿名",tx:"谢谢老师这一年对我们的包容与教导 🙏",an:1}69 ];70 const FOLDERS=[71 {ic:"📘",t:"课件资料",s:"高等数学 / 英语 / 数据结构 等 36 份"},72 {ic:"📝",t:"复习资料",s:"期中 / 期末 / 考研 冲刺包 21 份"},73 {ic:"📋",t:"班会材料",s:"班会 PPT 与记录 18 份"},74 {ic:"🖼️",t:"活动照片",s:"运动会 / 春游 / 联欢会 240 张"},75 {ic:"📊",t:"表格模板",s:"签到表 / 值日表 / 统计表 12 份"}76 ];77 const FILEPRE={78 name:"高数_期中复习提纲.pdf",meta:"2.4 MB · 上传于 2026-07-12 · 陈思",79 text:"【高等数学 期中复习提纲】\n一、极限与连续\n 1. 夹逼定理、单调有界定理\n 2. 无穷小比较与等价替换\n二、导数与微分\n 1. 复合函数求导、隐函数求导\n 2. 高阶导数、参数方程求导\n三、积分\n 1. 换元积分、分部积分\n 2. 定积分应用(面积/体积)\n四、常考题型与易错点(详见全文)……"80 };81 const ACTS=[82 {id:"a1",t:"春季户外素质拓展",time:"2026-07-28 09:00",place:"西山营地",limit:40,joined:32,desc:"一天一夜的团队挑战,攀岩、定向越野、篝火晚会,增进默契。"},83 {id:"a2",t:"班级元旦联欢会",time:"2026-12-30 19:00",place:"学校礼堂",limit:50,joined:48,desc:"才艺展示 + 抽奖 + 年度颁奖,一年一度的狂欢夜。"},84 {id:"a3",t:"图书馆共读计划",time:"每周六 14:00",place:"图书馆三楼",limit:20,joined:15,desc:"共读一本书,分享读后感,培养深度阅读习惯。"}85 ];86 const VOTES=[87 {id:"v1",t:"班服主色调投票",opts:["星空蓝","活力橙","薄荷绿","樱花粉"],anon:0,total:36},88 {id:"v2",t:"团建地点意向调研",opts:["海滩","古镇","主题乐园","户外营地"],anon:1,total:28}89 ];9091 /* ============ 工具 ============ */92 const esc=function(s){return String(s).replace(/[&<>]/g,function(c){return {"&":"&","<":"<",">":">"}[c];});};93 const statusPill=function(st){94 if(st==="待提交")return '<span class="pill r">待提交</span>';95 if(st==="已提交")return '<span class="pill o">已提交</span>';96 return '<span class="pill g">已批改</span>';97 };98 const catPill=function(c){99 const map={教学:["g","教学"],活动:["","活动"],行政:["o","行政"],放假:["r","放假"]};100 const m=map[c]||["",c]; return '<span class="pill '+m[0]+'">'+m[1]+'</span>';101 };102103 /* ============ 顶部栏 / 底部导航 ============ */104 const TOP=function(title,opt){105 opt=opt||{};106 const back=opt.back?'<div class="tb-back" onclick="go(\''+opt.back+'\')">‹</div>':'';107 const act=opt.act?'<div class="tb-act" onclick="'+opt.actFn+'">'+opt.act+'</div>':'';108 const cls=opt.plain?'topbar plain':'topbar';109 return '<div class="'+cls+'">'+back+'<div class="tb-title">'+title+'</div>'+act+'</div>';110 };111 const TABS=function(on){112 const t=[["home","🏠","首页"],["notice","📢","通知"],["community","💬","社区"],["files","📁","资源"],["profile","👤","我的"]];113 return '<div class="tabbar">'+t.map(function(x){114 return '<div class="tb '+(on===x[0]?'on':'')+'" onclick="go(\''+x[0]+'\')"><span class="e">'+x[1]+'</span>'+x[2]+'</div>';115 }).join('')+'</div>';116 };117118 /* ============ 屏幕渲染 ============ */119 const S={120 home:function(){121 let html=TOP("星河三班");122 html+='<div class="banner" id="bnr">';123 BANNERS.forEach(function(b,i){124 html+='<div class="slide'+(i===0?' on':'')+'" data-i="'+i+'"><h2>'+b.t+'</h2><p>'+b.s+'</p></div>';125 });126 html+='<div class="dots">'+BANNERS.map(function(_,i){return '<i class="'+(i===0?'on':'')+'"></i>';}).join('')+'</div></div>';127 // 班级信息128 html+='<div class="card"><div class="row"><div class="ic">🎓</div><div><div style="font-weight:700;font-size:16px">星河三班</div><div class="muted" style="font-size:12px">'+CLS.grade+'</div></div></div>'129 +'<div style="margin-top:10px;padding:10px 12px;background:#f6f8ff;border-radius:12px;color:#566;font-size:13px">「 '+CLS.motto+' 」</div>'130 +'<div class="row" style="margin-top:12px;gap:8px;flex-wrap:wrap"><div class="pill">班主任 · '+CLS.head+'</div><div class="pill">辅导员 · '+CLS.counsel+'</div></div>'131 +'<div style="margin-top:12px"><div style="font-size:13px;color:var(--mut);margin-bottom:6px">班委架构</div><div class="tags">'+CLS.committee.map(function(c){return '<span class="tg">'+c[0]+' '+c[1]+'</span>';}).join('')+'</div></div></div>';132 // 荣誉墙133 html+='<div class="card"><h3><span class="ic">🏆</span>集体荣誉墙</h3><div class="honor">'+HONORS.map(function(h){134 return '<div class="h"><div class="medal">'+h.m+'</div><div class="ht">'+esc(h.t)+'</div><div class="hs">'+esc(h.s)+'</div></div>';135 }).join('')+'</div></div>';136 // 快捷入口137 html+='<div class="grid">'138 +'<div class="gi" onclick="go(\'notice\')"><div class="e">📢</div><div class="t">通知作业</div></div>'139 +'<div class="gi" onclick="go(\'members\')"><div class="e">👥</div><div class="t">成员</div></div>'140 +'<div class="gi" onclick="go(\'community\')"><div class="e">💬</div><div class="t">动态圈</div></div>'141 +'<div class="gi" onclick="go(\'files\')"><div class="e">📁</div><div class="t">资源库</div></div>'142 +'<div class="gi" onclick="go(\'activity\')"><div class="e">🎉</div><div class="t">活动</div></div>'143 +'<div class="gi" onclick="go(\'vote\')"><div class="e">🗳️</div><div class="t">投票</div></div>'144 +'<div class="gi" onclick="go(\'blessing\')"><div class="e">💌</div><div class="t">祝福墙</div></div>'145 +'<div class="gi" onclick="go(\'admin\')"><div class="e">⚙️</div><div class="t">后台</div></div>'146 +'</div>';147 // 信息预览148 html+='<div class="card"><h3><span class="ic">🔔</span>最新公告</h3>'+NOTICES.slice(0,3).map(function(n){149 return '<div class="li" onclick="go(\'notice-detail\',{id:\''+n.id+'\'})"><div class="bd"><div class="t">'+esc(n.title)+'</div><div class="s">'+n.time+' · '+n.cat+'</div></div><div class="rt">›</div></div>';150 }).join('')+'</div>';151 html+='<div class="card"><h3><span class="ic">📸</span>近期活动</h3>'+ACTS.slice(0,2).map(function(a){152 return '<div class="li" onclick="go(\'activity-detail\',{id:\''+a.id+'\'})"><div class="av">🎉</div><div class="bd"><div class="t">'+esc(a.t)+'</div><div class="s">'+a.time+' · '+a.place+'</div></div><div class="rt">'+a.joined+'/'+a.limit+'</div></div>';153 }).join('')+'</div>';154 html+=TABS("home");155 return html;156 },157158 notice:function(){159 let html=TOP("通知公告",{act:"发布",actFn:"go('publish','{kind:notice}')"});160 const cats=["全部","教学","活动","行政","放假"];161 html+='<div class="card" style="padding:10px 12px"><div class="seg" id="nseg">'+cats.map(function(c,i){return '<div class="s'+(i===0?' on':'')+'" data-c="'+c+'">'+c+'</div>';}).join('')+'</div></div>';162 html+='<div id="nlist">'+NOTICES.map(function(n){163 let top=n.top?'<span class="pill r" style="margin-right:6px">置顶</span>':'';164 return '<div class="card" style="margin:10px" onclick="go(\'notice-detail\',{id:\''+n.id+'\'})"><div class="row" style="margin-bottom:6px">'+catPill(n.cat)+top+'<span class="muted" style="font-size:12px;margin-left:auto">'+n.time+'</span></div><div style="font-weight:600">'+esc(n.title)+'</div><div class="muted" style="font-size:12px;margin-top:6px">已读 '+n.read+'/'+n.total+' 人</div></div>';165 }).join('')+'</div>';166 html+=TABS("notice");167 return html;168 },169170 "notice-detail":function(p){171 const n=NOTICES.find(function(x){return x.id===p.id;})||NOTICES[0];172 let html=TOP(esc(n.title),{back:"notice",act:"提醒",actFn:"alert('已向未读同学发送二次提醒 ✓')"});173 html+='<div class="card" style="margin-top:12px"><div class="row" style="margin-bottom:10px">'+catPill(n.cat)+(n.top?'<span class="pill r" style="margin-left:6px">置顶</span>':'')+'<span class="muted" style="font-size:12px;margin-left:auto">'+n.time+'</span></div>';174 html+='<div class="article" style="padding:0">'+n.body+'</div>';175 html+='<div class="between" style="border-top:1px solid var(--line);padding-top:12px;margin-top:6px"><span class="muted" style="font-size:12px">已读追踪:'+n.read+' / '+n.total+' 人</span><span class="pill g">阅读率 '+Math.round(n.read/n.total*100)+'%</span></div>';176 html+='<div style="margin-top:12px"><button class="btn s" onclick="alert(\'未读名单:王浩、刘洋 等 '+(n.total-n.read)+' 人\')">查看未读名单</button></div></div>';177 const others=NOTICES.filter(function(x){return x.id!==n.id;}).slice(0,2);178 html+='<div class="card"><h3><span class="ic">📑</span>相关通知</h3>'+others.map(function(o){return '<div class="li" onclick="go(\'notice-detail\',{id:\''+o.id+'\'})"><div class="bd"><div class="t">'+esc(o.title)+'</div><div class="s">'+o.time+'</div></div><div class="rt">›</div></div>';}).join('')+'</div>';179 return html;180 },181182 homework:function(){183 let html=TOP("作业管理",{act:"发布",actFn:"alert('打开作业发布表单')"});184 html+='<div class="card" style="margin-top:12px"><div class="row" style="margin-bottom:4px"><div style="font-weight:700">本周作业</div><span class="pill r">2 待提交</span></div></div>';185 html+='<div style="margin:0 12px">'+HOMEWORK.map(function(h){186 return '<div class="card" style="margin:10px 0"><div class="between"><div style="font-weight:600">'+esc(h.title)+'</div>'+statusPill(h.status)+'</div>'187 +'<div class="muted" style="font-size:12px;margin-top:6px">'+h.course+' · 截止 '+h.due+(h.score?' · 得分 '+h.score:'')+'</div>'188 +'<div style="margin-top:10px;display:flex;gap:8px">'+(h.status==="待提交"189 ?'<button class="btn s" onclick="alert(\'作业已提交 ✓\')">去提交</button>'190 :'<button class="btn s ghost" onclick="alert(\'查看批改反馈\')">查看反馈</button>')+'</div></div>';191 }).join('')+'</div>';192 html+=TABS("notice");193 return html;194 },195196 members:function(){197 let html=TOP("班级成员",{act:"分组",actFn:"go('groups')"});198 const roleColor={老师:"var(--gold)",班委:"var(--p)",学生:"var(--mut)"};199 html+='<div class="card" style="margin-top:12px"><div class="between"><div style="font-weight:700">全员花名册</div><span class="pill">42 人</span></div></div>';200 html+='<div style="margin:0 12px">'+MEMBERS.map(function(m){201 return '<div class="li"><div class="av">'+m.av+'</div><div class="bd"><div class="t">'+esc(m.n)+' <span style="font-size:11px;color:'+roleColor[m.role]+';font-weight:600">'+m.role+'</span></div><div class="s">学号 '+m.sid+' · '+m.grp+'</div></div><div class="rt"><button class="btn s ghost" onclick="alert(\'拨号 '+m.ph+'\')">呼叫</button></div></div>';202 }).join('')+'</div>';203 html+=TABS("notice");204 return html;205 },206207 groups:function(){208 let html=TOP("分组管理",{back:"members"});209 html+='<div style="margin:12px">'+GROUPS.map(function(g){210 return '<div class="card"><h3><span class="ic">🗂️</span>'+esc(g.t)+'</h3>'+g.items.map(function(it){return '<div class="li"><div class="av">👥</div><div class="bd"><div class="t">'+esc(it)+'</div></div></div>';}).join('')+'</div>';211 }).join('')+'</div>';212 return html;213 },214215 community:function(){216 let html=TOP("班级动态圈",{act:"发布",actFn:"go('publish')"});217 html+='<div class="feed" id="feed">'+FEED.map(function(p){218 return S._post(p);219 }).join('')+'</div>';220 html+=TABS("community");221 return html;222 },223 _post:function(p){224 return '<div class="post"><div class="ph"><div class="av">'+p.av+'</div><div><div class="nm">'+esc(p.nm)+'</div><div class="tm">'+p.tm+'</div></div></div>'225 +'<div class="tx">'+esc(p.tx)+'</div>'226 +'<div class="imgs">'+p.imgs.map(function(im){return '<div class="im">'+im+'</div>';}).join('')+'</div>'227 +'<div class="acts"><div class="a" onclick="alert(\'已点赞 ❤\')">❤ '+p.likes+'</div><div class="a" onclick="go(\'post-detail\',{id:\''+p.id+'\'})">💬 '+p.cmts.length+'</div><div class="a" onclick="alert(\'已转发到班级群\')">↪ 分享</div></div></div>';228 },229230 "post-detail":function(p){231 const post=FEED.find(function(x){return x.id===p.id;})||FEED[0];232 let html=TOP("动态详情",{back:"community"});233 html+='<div class="feed" style="margin-top:12px">'+S._post(post)+'</div>';234 html+='<div class="card"><h3><span class="ic">💬</span>评论 '+post.cmts.length+'</h3>'+post.cmts.map(function(c){235 return '<div class="cmt"><div class="av">'+c[0].charAt(0)+'</div><div class="bd"><div class="nm">'+esc(c[0])+'</div><div class="tx">'+esc(c[1])+'</div></div></div>';236 }).join('')+'</div>';237 html+='<div class="card"><div class="field" style="margin:0"><label>写下你的评论</label><div class="row"><input placeholder="说点什么…"><button class="btn s" style="width:auto;margin-left:8px" onclick="alert(\'评论已发布 ✓\')">发送</button></div></div></div>';238 return html;239 },240241 publish:function(p){242 const kind=(p&&p.kind)==="notice"?"通知公告":"班级动态";243 let html=TOP("发布"+kind,{back:(p&&p.kind)==="notice"?"notice":"community"});244 html+='<div class="card" style="margin-top:12px">';245 if((p&&p.kind)==="notice"){246 html+='<div class="field"><label>通知分类</label><div class="seg"><div class="s on">教学</div><div class="s">活动</div><div class="s">行政</div><div class="s">放假</div></div></div>';247 html+='<div class="field"><label><input type="checkbox" checked> 置顶发布</label></div>';248 }249 html+='<div class="field"><label>标题</label><input placeholder="'+(kind==="通知公告"?"通知标题":"这一刻的想法…")+'"></div>';250 html+='<div class="field"><label>内容</label><textarea placeholder="分享班级点滴,支持图文…"></textarea></div>';251 html+='<div class="field"><label>添加图片</label><div class="row"><div class="imgs" style="display:flex;gap:8px">'+["📷","🖼️","😊"].map(function(e){return '<div class="im" style="width:56px;height:56px;border-radius:12px;background:var(--chip);display:flex;align-items:center;justify-content:center;font-size:22px">'+e+'</div>';}).join('')+'</div></div></div>';252 html+='<button class="btn" style="margin:6px 16px 16px;width:calc(100% - 32px)" onclick="alert(\''+kind+'发布成功 ✓\')">立即发布</button></div>';253 return html;254 },255256 blessing:function(){257 let html=TOP("留言祝福墙",{act:"写祝福",actFn:"alert('打开祝福留言框(支持匿名)')"});258 html+='<div style="margin:12px">'+BLESS.map(function(b){259 return '<div class="card"><div class="row"><div class="av" style="width:38px;height:38px;border-radius:50%;background:var(--chip);display:flex;align-items:center;justify-content:center;font-size:18px">'+(b.an?'🕶️':'💖')+'</div><div><div class="nm" style="font-weight:700">'+esc(b.n)+(b.an?' <span class="pill" style="background:#eee;color:#999">匿名</span>':'')+'</div></div></div><div style="margin-top:10px;font-size:14px">'+esc(b.tx)+'</div></div>';260 }).join('')+'</div>';261 html+=TABS("community");262 return html;263 },264265 files:function(){266 let html=TOP("资源共享库",{act:"上传",actFn:"alert('打开文件上传(老师/班委可上传)')"});267 html+='<div class="card" style="margin-top:12px"><div class="row"><input placeholder="🔍 搜索文件 / 资料" style="border:1.5px solid var(--line);border-radius:12px;padding:10px;width:100%;background:#fafbff"></div></div>';268 html+='<div>'+FOLDERS.map(function(f,i){269 return '<div class="folder" onclick="go(\'file-preview\')"><div class="fi">'+f.ic+'</div><div class="fb"><div class="ft">'+esc(f.t)+'</div><div class="fs">'+esc(f.s)+'</div></div><div style="color:var(--mut)">›</div></div>';270 }).join('')+'</div>';271 html+=TABS("files");272 return html;273 },274275 "file-preview":function(){276 let html=TOP(esc(FILEPRE.name),{back:"files",act:"下载",actFn:"alert('开始下载 ✓')"});277 html+='<div class="card" style="margin-top:12px"><div class="muted" style="font-size:12px">'+esc(FILEPRE.meta)+'</div>'278 +'<div class="article" style="padding:14px 0;white-space:pre-wrap;font-family:monospace;font-size:13px;background:#fafbff;border-radius:12px;padding:14px">'+esc(FILEPRE.text)+'</div>'279 +'<button class="btn a" style="margin-top:6px" onclick="alert(\'文档已加入下载队列\')">⬇ 下载文件</button></div>';280 return html;281 },282283 activity:function(){284 let html=TOP("班级活动",{act:"发布",actFn:"alert('发布新活动')"});285 html+='<div style="margin:12px">'+ACTS.map(function(a){286 const pct=Math.round(a.joined/a.limit*100);287 return '<div class="card" onclick="go(\'activity-detail\',{id:\''+a.id+'\'})"><div class="row" style="margin-bottom:8px"><div style="font-size:26px">🎉</div><div style="font-weight:700;font-size:15px">'+esc(a.t)+'</div></div>'288 +'<div class="muted" style="font-size:12px">🕒 '+a.time+' · 📍 '+a.place+'</div>'289 +'<div style="margin:10px 0 4px" class="between"><span class="muted" style="font-size:12px">报名 '+a.joined+'/'+a.limit+'</span><span style="font-size:12px;color:var(--p)">'+pct+'%</span></div>'290 +'<div class="pr"><i style="width:'+pct+'%"></i></div></div>';291 }).join('')+'</div>';292 html+=TABS("files");293 return html;294 },295296 "activity-detail":function(p){297 const a=ACTS.find(function(x){return x.id===p.id;})||ACTS[0];298 let html=TOP(esc(a.t),{back:"activity"});299 html+='<div class="cover" style="margin:12px"><div class="ct">🎉 '+esc(a.t)+'</div><div class="cs">'+a.time+' · '+a.place+'</div></div>';300 html+='<div class="card" style="margin-top:-6px"><div class="row" style="margin-bottom:6px"><span class="pill g">报名中</span><span class="muted" style="font-size:12px;margin-left:auto">已报 '+a.joined+'/'+a.limit+' 人</span></div><div class="pr"><i style="width:'+Math.round(a.joined/a.limit*100)+'%"></i></div><div class="article" style="padding:12px 0">'+esc(a.desc)+'</div>'301 +'<button class="btn" onclick="alert(\'报名成功,已生成签到码 ✓\')">立即报名</button>'302 +'<button class="btn ghost" style="margin-top:8px" onclick="alert(\'签到核销:出示此码给工作人员 ✅\')">现场签到</button></div>';303 return html;304 },305306 vote:function(){307 let html=TOP("投票问卷",{act:"发起",actFn:"alert('发起新投票/问卷')"});308 html+='<div style="margin:12px">'+VOTES.map(function(v){309 return '<div class="card" onclick="go(\'vote\')"><div class="row" style="margin-bottom:8px"><div style="font-weight:700">'+esc(v.t)+'</div>'+(v.anon?'<span class="pill" style="background:#eee;color:#999">匿名</span>':'')+'</div>'310 +'<div style="display:flex;flex-direction:column;gap:8px">'+v.opts.map(function(o,i){const wp=Math.round((40-i*7));return '<div class="row" style="gap:8px"><div style="flex:1"><div class="between" style="font-size:13px"><span>'+esc(o)+'</span><span class="muted">'+wp+'%</span></div><div class="pr"><i style="width:'+wp+'%"></i></div></div></div>';}).join('')+'</div>'311 +'<div class="muted" style="font-size:12px;margin-top:8px">已收集 '+v.total+' 份'+(v.anon?' · 匿名投票':'')+'</div></div>';312 }).join('')+'</div>';313 return html;314 },315316 profile:function(){317 let html=TOP("个人中心");318 html+='<div class="class-head" style="border-radius:0"><div class="row"><div style="width:56px;height:56px;border-radius:50%;background:rgba(255,255,255,.25);display:flex;align-items:center;justify-content:center;font-size:28px">🧑</div><div><div style="font-size:18px;font-weight:800">王浩</div><div style="font-size:12px;opacity:.9">学号 20230105 · 学生 · 1舍</div></div></div></div>';319 html+='<div class="card" style="margin-top:-14px;position:relative"><div class="row" style="text-align:center"><div style="flex:1"><div style="font-weight:700;font-size:18px">2</div><div class="muted" style="font-size:12px">未读通知</div></div><div style="flex:1;border-left:1px solid var(--line);border-right:1px solid var(--line)"><div style="font-weight:700;font-size:18px;color:var(--red)">1</div><div class="muted" style="font-size:12px">待交作业</div></div><div style="flex:1"><div style="font-weight:700;font-size:18px">1</div><div class="muted" style="font-size:12px">待参与</div></div></div></div>';320 const items=[["📝","我的作业","查看待提交与已批改"],["💬","我的动态","我发布的图文动态"],["📁","我的文件","我上传的班级资料"],["🎉","我的活动","我报名的班级活动"],["🔔","消息提醒","未读通知聚合"],["⚙️","隐私设置","信息可见范围管理"]];321 html+='<div style="margin:12px">'+items.map(function(it){return '<div class="li" onclick="alert(\''+it[1]+'\')"><div class="av">'+it[0]+'</div><div class="bd"><div class="t">'+it[1]+'</div><div class="s">'+it[2]+'</div></div><div class="rt">›</div></div>';}).join('')+'</div>';322 html+='<div style="margin:0 12px 12px"><button class="btn ghost" onclick="alert(\'已退出登录\')">退出登录</button></div>';323 html+=TABS("profile");324 return html;325 },326327 admin:function(){328 let html=TOP("后台管理",{back:"home",act:"数据",actFn:"go('admin-content')"});329 html+='<div class="cover" style="margin:12px"><div class="ct">📊 班级数据看板</div><div class="cs">实时掌握班级运行脉搏</div></div>';330 const stats=[["1,280","主页访问量"],["92%","通知阅读率"],["88%","作业提交率"],["76%","活动参与率"]];331 html+='<div class="stats">'+stats.map(function(s){return '<div class="st"><div class="v">'+s[0]+'</div><div class="l">'+s[1]+'</div></div>';}).join('')+'</div>';332 const bars=[["通知发布",96],["作业提交",88],["动态互动",74],["资源下载",63]];333 html+='<div class="card"><h3><span class="ic">📈</span>各模块活跃度</h3>'+bars.map(function(b){return '<div style="margin:10px 0"><div class="between" style="font-size:13px;margin-bottom:4px"><span>'+b[0]+'</span><span class="muted">'+b[1]+'%</span></div><div class="pr"><i style="width:'+b[1]+'%"></i></div></div>';}).join('')+'</div>';334 html+='<div class="card"><div class="li" onclick="go(\'admin-content\')"><div class="av">🗂️</div><div class="bd"><div class="t">内容管理</div><div class="s">通知 / 动态 / 资源 / 活动 审核</div></div><div class="rt">›</div></div><div class="li" onclick="go(\'members\')"><div class="av">👥</div><div class="bd"><div class="t">人员管理</div><div class="s">角色分配 / 分组调整</div></div><div class="rt">›</div></div><div class="li" onclick="go(\'admin-content\')"><div class="av">🎨</div><div class="bd"><div class="t">系统配置</div><div class="s">班级 Logo / 主题 / 功能开关</div></div><div class="rt">›</div></div></div>';335 return html;336 },337338 "admin-content":function(){339 let html=TOP("系统配置",{back:"admin"});340 const sw=[["通知公告模块",1],["作业管理模块",1],["社区动态圈",1],["资源共享库",1],["活动投票模块",1],["家长视角(K12)",0],["班费公示",0],["毕业纪念册",0]];341 html+='<div class="card" style="margin-top:12px"><h3><span class="ic">🔧</span>功能开关</h3>'+sw.map(function(s){342 return '<div class="li" style="cursor:pointer" onclick="toggleSw(this)"><div class="bd"><div class="t">'+s[0]+'</div></div><div class="sw'+(s[1]?' on':'')+'"><i></i></div></div>';343 }).join('')+'</div>';344 html+='<div class="card"><h3><span class="ic">🎨</span>主题与外观</h3><div class="field" style="margin:0"><label>主题色</label><div class="seg"><div class="s on">星空蓝</div><div class="s">活力橙</div><div class="s">薄荷绿</div><div class="s">樱花粉</div></div></div><div class="field"><label>班级 Logo / 名称</label><input value="星河三班"></div></div>';345 html+='<div class="card"><h3><span class="ic">🗂️</span>内容审核队列</h3>'+["张明 发布的动态待审核","孙悦 上传的资料待审核"].map(function(t){return '<div class="li"><div class="av">⏳</div><div class="bd"><div class="t">'+t+'</div></div><div class="rt"><button class="btn s ghost" onclick="alert(\'已通过\')">通过</button></div></div>';}).join('')+'</div>';346 return html;347 }348 };349350 /* ============ 路由 ============ */351 const DEFAULTS={home:1,notice:1,community:1,files:1,profile:1};352 function render(){353 const h=location.hash.replace(/^#/,'')||'home';354 const parts=h.split('?');355 const key=parts[0];356 const params={};357 if(parts[1])parts[1].split('&').forEach(function(kv){const a=kv.split('=');params[decodeURIComponent(a[0])]=a[1]?decodeURIComponent(a[1]):'';});358 const fn=S[key]||S.home;359 const html=fn(params);360 $("#app").html(html);361 window.scrollTo(0,0);362 if(key==="home")startBanner();363 if(key==="notice")bindNoticeSeg();364 }365 function go(k,p){366 let h='#'+k;367 if(p){const q=Object.keys(p).map(function(kk){return encodeURIComponent(kk)+'='+encodeURIComponent(p[kk]);}).join('&');h+='?'+q;}368 if(location.hash===h){render();}else{location.hash=h;}369 }370 window.go=go;371372 /* banner 轮播 */373 let bnTimer=null;374 function startBanner(){375 clearInterval(bnTimer);376 let i=0;const slides=$("#bnr .slide"),dots=$("#bnr .dots i");377 if(!slides.length)return;378 bnTimer=setInterval(function(){379 slides.eq(i).removeClass('on');dots.eq(i).removeClass('on');380 i=(i+1)%slides.length;381 slides.eq(i).addClass('on');dots.eq(i).addClass('on');382 },2600);383 }384 /* 通知分类筛选 */385 function bindNoticeSeg(){386 $("#nseg .s").on('click',function(){387 const c=$(this).data('c');388 $("#nseg .s").removeClass('on');$(this).addClass('on');389 const list=NOTICES.filter(function(n){return c==="全部"||n.cat===c;});390 $("#nlist").html(list.map(function(n){391 let top=n.top?'<span class="pill r" style="margin-right:6px">置顶</span>':'';392 return '<div class="card" style="margin:10px" onclick="go(\'notice-detail\',{id:\''+n.id+'\'})"><div class="row" style="margin-bottom:6px">'+catPill(n.cat)+top+'<span class="muted" style="font-size:12px;margin-left:auto">'+n.time+'</span></div><div style="font-weight:600">'+esc(n.title)+'</div><div class="muted" style="font-size:12px;margin-top:6px">已读 '+n.read+'/'+n.total+' 人</div></div>';393 }).join('')||'<div class="empty">该分类暂无通知</div>');394 });395 }396 /* 功能开关 */397 window.toggleSw=function(el){$(el).find('.sw').toggleClass('on');};398399 /* 启动 */400 $(function(){401 if(!location.hash)location.hash='#home';402 $(window).on('hashchange',render);403 render();404 });405})(jQuery);406