首页/ mobileweb/ 星河三班 · 班级主页移动端 H5/ 代码预览

💻 代码预览 · 星河三班 · 班级主页移动端 H5

mw_edu · 上传者 驰旭教育
← 返回详情
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 {"&":"&amp;","<":"&lt;",">":"&gt;"}[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