点此查看 所有教程、项目、源码导航
文章目录
- [1. 本篇任务说明](#1. 本篇任务说明)
- [2. 接口约定](#2. 接口约定)
- [3. HTML 修改](#3. HTML 修改)
- [4. 编写 JS 逻辑](#4. 编写 JS 逻辑)
- [5. 测试流程](#5. 测试流程)
- [6. 效果查看](#6. 效果查看)
1. 本篇任务说明
毛哥:副队,活动的增删改查我们都写完啦,现在是不是该做报名名单了?
副队:没错。一个活动发布出去之后,学生可以报名,管理员需要点开活动,查看这条活动下面所有报名人的信息。这一节我们就实现查看报名名单功能。
毛哥:那这个接口怎么设计?也是 POST 对吧?
副队:对,咱们项目约定全部使用 POST。调用这个接口的时候,把活动 id 传给后端,后端根据活动 id,去报名表里查出所有关联的报名记录,最后用统一格式返回:
{code, msg, data}。毛哥:又是这个返回格式!我现在越来越熟悉了,成功的时候 code 为 200,data 里面放报名数组;失败的时候 code 不是 200,msg 告诉我们失败原因。
副队:理解到位。报名名单我们单独用一个弹窗展示,不和之前新增、编辑活动的弹窗混在一起,逻辑会更清爽。
2. 接口约定
副队:先把接口信息整理成表格,方便后面写代码对照。
| 项目 | 内容 |
|---|---|
| 请求方式 | POST |
| 请求地址 | /activity/getSignList |
| 请求参数 | activityId:活动编号 |
| 返回格式 | {code, msg, data} |
| data | 报名对象数组,每个报名对象包含:报名 id、活动 id、活动名称、学生姓名、学号、联系方式、报名时间 |
示例返回 JSON:
js
{
"code": 200,
"msg": "查询报名名单成功",
"data": [
{
"id": 1,
"activityId": 10,
"activityName": "春日户外拓展活动",
"studentName": "张三",
"studentNo": "2025001001",
"phone": "13800138000",
"signTime": "2026-11-06 16:20:10"
},
{
"id": 2,
"activityId": 10,
"activityName": "春日户外拓展活动",
"studentName": "李四",
"studentNo": "2025001002",
"phone": "13900139000",
"signTime": "2026-11-06 17:05:33"
}
]
}
毛哥:如果这个活动还没有人报名呢?
副队:后端会正常返回 code=200,data 就是一个空数组,前端拿到之后渲染一个提示:暂无报名人员,这样就不用单独处理异常。
副队:当然,现在咱们还没开发学生报名的页面,我临时在数据库里面给你放一些数据方便你测试就行。
3. HTML 修改
副队:我们先改
activity-manage.html,两件事情:第一,在表格每一行新增一个【查看报名】按钮;第二,新增一个弹窗,用来展示报名名单。
找到getActivityList函数里面,生成操作按钮区域,确认已经有查看报名的按钮:

在页面弹窗区域,新增报名名单弹窗:
html
<!-- 查看报名名单弹窗 -->
<div class="mask" id="listMask">
<div class="dialog">
<h3>报名名单</h3>
<table class="common-table">
<thead>
<tr>
<th>报名编号</th>
<th>活动编号</th>
<th>活动名称</th>
<th>姓名</th>
<th>学号</th>
<th>手机号</th>
<th>报名时间</th>
</tr>
</thead>
<tbody id="signTableBody">
<!-- JS 动态渲染报名数据 -->
</tbody>
</table>
<div id="signEmptyTip" style="text-align:center; padding:20px; display:none;">暂无报名人员</div>
<div class="dialog-footer">
<button class="close" onclick="closeSignMask()">关闭</button>
</div>
</div>
</div>
毛哥:这个弹窗和编辑弹窗结构很像,公共样式是不是可以直接复用?
副队:没错,弹窗、表格、按钮的样式都写在公共 CSS,这里只需要新增少量独立样式,如果后面需要微调这个弹窗独有的效果,再写到
activity-manage.css。
4. 编写 JS 逻辑
副队:通用
postRequest我们之前已经封装好了,直接拿来调用接口。我们需要这几个函数:打开报名弹窗、关闭弹窗、加载报名列表、渲染表格。
在 activity-manage.js 追加下面代码:
js
/**
* 打开报名名单弹窗
* @param {number} activityId 活动id
*/
function viewNameList(activityId) {
// 保存当前查看的活动 id
window.currentSignActivityId = activityId;
// 清空旧数据
document.getElementById("signTableBody").innerHTML = "";
document.getElementById("signEmptyTip").style.display = "none";
// 请求报名列表
postRequest("/activity/getSignList", {
activityId: activityId
}, function (res) {
if (res.code === 200) {
renderSignList(res.data);
} else {
alert(res.msg);
}
});
// 显示弹窗
document.getElementById("listMask").classList.add('show');
}
/**
* 关闭报名名单弹窗
*/
function closeSignMask() {
document.getElementById("listMask").classList.remove('show');
}
/**
* 渲染报名名单表格
* @param {Array} list 报名数组
*/
function renderSignList(list) {
const tbody = document.getElementById("signTableBody");
const emptyTip = document.getElementById("signEmptyTip");
if (list.length === 0) {
emptyTip.style.display = "block";
return;
}
emptyTip.style.display = "none";
let html = "";
list.forEach(function (item) {
html += `
<tr>
<td>${item.id}</td>
<td>${item.activityId}</td>
<td>${item.activityName}</td>
<td>${item.studentName}</td>
<td>${item.studentNo}</td>
<td>${item.phone}</td>
<td>${item.signTime}</td>
</tr>
`;
});
tbody.innerHTML = html;
}
毛哥:副队,我看懂了!点击按钮先拿到活动 id,调用通用 postRequest,后端返回数据,如果成功就交给渲染函数;数组为空就展示提示文字。
副队:是的,而且我们把弹窗显示隐藏,和数据加载分开,逻辑清晰。如果以后想要增加导出报名名单,也是在这个基础上继续扩展。
毛哥,我还有一个疑问,为啥viewNameList函数传递的参数是activityId,而在之前的活动编辑时,我们传递的是id。
副队:观察的很细心嘛,这问题首先要说明一点,具体传什么是前后端约定好的,此处实际上如果后端实现采用id的话,也可以传id;那为啥使用activityId更好呢,因为现在是报名这个数据领域,这个领域的id应该是报名的序号,活动id的话是指向活动这个概念的。哎呀,总之这个问题还是偏后端一点啦,你现在记住就是按约定好的去传参数就OK了。
5. 测试流程
副队:写完代码之后,我们按这个顺序测试一遍。
- 打开活动管理页面,加载活动列表;
- 挑选一条已经有报名的活动,点击【查看报名】;
- 弹窗弹出,表格展示所有报名学生;
- 挑选一条没有报名的活动,点击按钮,出现"暂无报名人员";
- 如果后端报错,弹出提示信息。
毛哥:太棒啦!管理员现在就可以看到谁报名了活动。
6. 效果查看
此时点击报名名单,显示当前活动的报名人员:

弹窗宽度有点小了,调整css如下:
css
.dialog {
width: 420px; /* 弹窗内容盒子固定宽度,调整为720px */
background: #fff; /* 弹窗白色背景 */
padding: 20px; /* 弹窗内部边距 */
border-radius: 6px; /* 弹窗圆角 */
}
在此打开,效果如下:

至此,活动管理页面功能全部完成。