logo
0
0
WeChat Login

Persistent Group Presentation Management System

一个用于课程小组展示顺序管理的轻量系统,支持一次性锁定抽签结果、学生按学号+姓名查询、签到持久化、看板追踪与导出课表。

功能特性

  • 一次性锁定分配:上传后立即随机分组顺序并写入状态文件,不会在学生查询时再次随机。
  • 学生抽签页:学生输入 SNO + Name 后触发揭晓动画,显示已预分配的展示序号与日期。
  • 持久化签到:首次查询后自动标记 checkedIncheckedInBycheckInTime
  • 实时 Dashboard:查看全部组别进度、签到状态,并支持 15 秒自动刷新。
  • 导出 Excel:一键导出当前课表与签到结果。

技术栈

  • Backend: Node.js + Express
  • View: EJS
  • Styling: Tailwind CSS(cdnjs)+ 自定义 CSS
  • Upload: multer
  • CSV Parse: csv-parser
  • Export: exceljs
  • Time: dayjs
  • Storage: data/courses/ (多个独立 JSON 文件)

目录结构

. ├── data/ │ ├── courses/ │ │ ├── Course1.json │ │ ├── Course2.json │ │ └── ... │ └── state.json (已弃用) ├── public/ │ └── css/ │ └── app.css ├── src/ │ ├── app.js │ ├── routes.js │ ├── controllers/ │ │ ├── adminController.js │ │ ├── dashboardController.js │ │ └── drawController.js │ ├── models/ │ │ └── stateStore.js │ └── utils/ │ └── csv.js ├── views/ │ ├── admin.ejs │ ├── dashboard.ejs │ └── draw.ejs └── README.md

快速开始

1. 安装依赖

npm install

2. 启动服务

npm start

开发模式(Node watch):

npm run dev

默认端口:3000

页面与路由

  • GET /admin:管理端(上传课程、组表、日期表)
  • POST /admin/upload:执行一次性锁定分配并为该课程创建独立 JSON 文件
  • GET /draw/:course:学生抽签页
  • POST /draw/:course/checkin:学生查询并登记签到
  • GET /dashboard:实时看板
  • GET /dashboard/export:导出 XLSX

数据流程

  1. 管理员在 Admin 页面选择课程名,上传 Groups CSVDates CSV
  2. 服务端解析 CSV,执行 Fisher-Yates 洗牌。
  3. 按随机结果分配 order,并根据 Dates CSV 映射 presentationDate
  4. 为每个课程创建独立 JSON 文件,写入 data/courses/课程名.json
  5. Dashboard 扫描 courses/ 目录并聚合所有课程的进度。
  6. 学生查询时只读取对应课程的锁定结果,不重新随机。

CSV 格式说明

Groups CSV(必需)

推荐格式(多列成员架构):

组长,小组成员1,小组成员2,小组成员3,小组成员4 杨瑞,邹尚林,周庆宁,王睿, 陈培松,徐誉,黄岩圃,谢文博, ,李四,张三,,

解析规则:

  • 从整行所有非空字段提取有效成员(不限列名)。
  • 自动过滤"组""order""序号"等元数据列。
  • 每个组可有 0-1 个组长 + 0-4 个成员,任意字段可为空。
  • 空值、null、空字符串都会被安全过滤。
  • 成员文本支持:
    • 学号-姓名(推荐,如 20260001-王睿
    • 学号:姓名学号 姓名
    • 仅姓名(如 王睿,无学号)

推荐格式:

order,date 1,30th March 2,6th April

也支持仅日期单列(系统会按行号自动补 order=1..n)。

数据存储架构

系统使用课程独立文件方案:每个课程存储为独立 JSON 文件,位于 data/courses/ 目录。

data/ ├── courses/ │ ├── Investment Simulation 2026.json │ ├── Course 2.json │ └── AnotherCourse.json └── state.json (已弃用)

每个课程 JSON 结构示例:

{ "createdAt": "2026-03-23 18:03:27", "groups": [ { "id": "G001", "members": ["杨瑞", "邹尚林"], "memberDetails": [ { "sno": "", "name": "杨瑞" }, { "sno": "", "name": "邹尚林" } ], "order": 1, "presentationDate": "30th March", "checkedIn": true, "checkedInBy": "杨瑞", "checkInTime": "2026-03-23 18:03:27" } ] }

优势

  • 每个课程独立管理,互不干扰
  • Dashboard 自动扫描并聚合所有课程进度
  • 易于备份、导出或删除单个课程

学生认证规则

  • 查询字段:SNO + Name
  • 匹配逻辑:
    • 优先在 memberDetails 中匹配同名成员;
    • 若输入了学号,则在有学号数据时要求学号一致;
    • 若成员无学号记录,允许仅凭姓名匹配。
  • 注意:组长需在"小组成员"列中出现才会被识别为展示人员;仅在"组长"列出现的人名不会被纳入学生认证。
  • Group ID
  • Members
  • Checked In
  • Checked In By
  • Check In Time

常见问题

1. 抽签页面提示找不到课程

请确认访问地址中的课程名完全一致(包括空格与大小写),且该课程已在 Admin 页面上传。查看 data/courses/ 目录确认文件是否存在。

2. 学生匹配失败

  • 检查 Groups CSV 成员格式是否规范(建议 学号-姓名)。
  • 检查是否输入了错误学号或姓名。
  • 同名不同学号时建议必须带学号。

3. 上传后结果不符合预期

锁定分配是一次性写入。若要重排,请重新上传 CSV 覆盖状态。

脚本

  • npm start:启动服务
  • npm run dev:watch 模式
  • npm test:占位脚本(当前无自动化测试)

About

课程汇报顺序抽签app

Language
JavaScript54.9%
CSS6%
Others39.1%