目录
- 前情回顾
- 本节目标
- 第一步:数据准备
-
- [1.1 数据源确认](#1.1 数据源确认)
- [1.2 页面变量创建](#1.2 页面变量创建)
- 第二步:顶部日历切换
-
- [2.1 日历数据生成](#2.1 日历数据生成)
- [2.2 日历UI搭建](#2.2 日历UI搭建)
- [2.3 最终效果](#2.3 最终效果)
- 第三步:课表卡片搭建
-
- [3.1 课表列表UI搭建](#3.1 课表列表UI搭建)
- [3.2 单个课表卡片设计](#3.2 单个课表卡片设计)
- 第四步:签到功能实现
-
- [4.1 签到按钮显示逻辑](#4.1 签到按钮显示逻辑)
- [4.2 签到方法实现](#4.2 签到方法实现)
- 最终效果
- 总结
前情回顾
在上一讲中,我们完成了后台订单管理与预约确认功能,建立了以 Attendances(签到/课消记录表)为核心的教务架构。当管理员确认预约后,系统会自动将排课信息写入学员课表。
本节我们将转战小程序端,为家长和学员展示课表信息,并实现签到功能。

本节目标
- 日历切换组件:实现横向滚动的日期选择器,支持未来15天的日期切换
- 课表卡片展示:根据选中日期动态查询并展示该学员的排课信息
- 签到功能实现:体验课学员可自主签到,更新签到状态
第一步:数据准备
1.1 数据源确认
确保以下数据表已创建并包含必要字段:
Attendances(学员课表)
| 字段名称 | 字段标识 | 类型 | 说明 |
|---|---|---|---|
| 关联学员 | child_id | 关联关系 | 关联 Children 表 |
| 关联排课 | schedule_id | 关联关系 | 关联 Schedule 表 |
| 关联订单 | booking_id | 关联关系 | 关联 Bookings 表 |
| 课程类型 | type | 枚举 | 1: 体验课, 2: 正课 |
| 上课日期 | lesson_date | 日期 | 冗余字段,方便快速查询 |
| 开始时间 | start_time | 文本 | 从排课表同步 |
| 状态 | status | 枚举 | 1: 待签到, 2: 到课, 3: 请假, 4: 旷课 |
| 预计消耗 | cost_count | 数字 | 体验课0,正课1 |
| 执教老师 | teacher_id | 关联关系 | 从排课表同步 |
1.2 页面变量创建
点击创建页面的图标,创建我的课表页面

我的课表作为一级导航页面,我们需要搭建一个底部导航布局。点击布局设计,选择tab栏导航布局,修改导航菜单

先配置首页,页面选择首页

将第二个菜单改为课表,图标改为日历图标

切换回页面设计,选中页面组件,页面布局改为tab栏导航布局

在页面中创建第一个变量用来保存我们选中的日期

继续创建变量,用来存储我们最近15天的日期数据

第二步:顶部日历切换
2.1 日历数据生成
在代码区创建自定义方法 initCalendar,用于生成未来15天的日历数据:
javascript
export default function ({ event, data }) {
const days = [];
const weekMap = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
for (let i = 0; i < 15; i++) {
const d = new Date();
d.setDate(d.getDate() + i);
d.setHours(0, 0, 0, 0);
const month = d.getMonth() + 1;
const date = d.getDate();
const dateStr = `${d.getFullYear()}-${String(month).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
days.push({
id: i,
date: dateStr,
label: `${month}/${date}`,
weekDay: weekMap[d.getDay()],
isToday: i === 0,
isWeekend: d.getDay() === 0 || d.getDay() === 6
});
}
$w.page.dataset.state.calendarList = days;
// 默认选中今天
if (!$w.page.dataset.state.selectedDate) {
$w.page.dataset.state.selectedDate = dateStr;
}
}
选中页面组件,在页面显示的时候调用我们的方法

2.2 日历UI搭建
拖入一个滚动容器,基础属性设置允许横向滚动

设置宽为375px,高为80px

滚动容器里添加普通容器,里边添加循环展示组件

设置普通容器的布局为横向排列

循环展示的数据绑定我们刚才定义的日期列表变量

循环展示里的普通容器添加两个文本组件,第一个文本组件绑定为我们的星期字段

第二个文本组件设置为日期字段

调整组件样式,设置普通容器的宽度和高度为合适的尺寸,这里需要注意需要设置文本组件的宽度才可以把卡片撑开
设置普通容器的样式绑定,选中变成蓝色
javascript
$w.item_repeater1.value == $w.page.dataset.state.selectedDate ? {
background: '#2563EB'
} : {}
设置文本组件的样式绑定,选中变成白色
bash
$w.item_repeater1.value == $w.page.dataset.state.selectedDate ? {
color: '#fff'
} : {}
给日期卡片添加点击事件 ,将选中日期变量赋值为当前循环变量的具体值

2.3 最终效果
- 日历横向滚动,展示未来15天
- 点击日期切换选中状态
- 选中日期蓝色高亮显示

第三步:课表卡片搭建
3.1 课表列表UI搭建
在第二行的列里添加普通容器,里边添加两个文本组件,设置普通容器的布局为横向排列,两端对齐

第一个文本组件绑定为我们的选中日期

在第三行的列里添加数据列表组件,数据模型选择学员课表

然后第二个文本组件绑定为共有几课,数量我们取列表的总数据条数

3.2 单个课表卡片设计

我们的卡片整体分为三行,每一行我们都用一个普通容器表达

第一行是一个左右结构,设置布局为两端对齐就可以

按这种思路搭建每一行绑定具体的字段就可以

然后给数据列表配置筛选条件,配置为上课日期等于我们的选中日期

第四步:签到功能实现
4.1 签到按钮显示逻辑
按钮的条件展示设置:
javascript
$w.item_listView1.type=="1"&&$w.item_listView1.status=="1"
说明:只有状态为"待签到"且课程类型为"体验课"时才显示签到按钮。
4.2 签到方法实现
创建自定义方法 handleCheckIn:
javascript
export default async function ({ event, data }) {
const attendance = data.target; // 获取当前课表记录
try {
$w.utils.showLoading({ title: '签到中...' });
// 1. 更新签到状态
await $w.cloud.callDataSource({
dataSourceName: 'Attendances',
methodName: 'wedaUpdateV2',
params: {
data: {
status: '2', // 已签到/到课
confirm_time: Date.now() // 签到时间
},
filter: {
where: {
_id: { $eq: attendance._id }
}
}
}
});
// 2. 刷新课表列表
$w.listView1.refresh();
$w.utils.showToast({ title: '签到成功!', icon: 'success' });
} catch (e) {
console.error('签到失败', e);
$w.utils.showToast({ title: '签到失败,请重试', icon: 'error' });
} finally {
$w.utils.hideLoading();
}
}
然后给按钮配置点击事件,调用我们的方法,传入列表所在行数据

最终效果
- 日历切换:顶部横向滚动日历,点击切换日期
- 课表展示:根据选中日期展示该学员的所有课程
- 签到功能:体验课学员点击签到按钮完成签到
- 状态展示:不同状态显示不同颜色标签

总结
本节完成了学员端课表展示的核心功能:
- 日历组件:通过自定义方法生成日历数据,循环展示实现横向滚动选择
- 课表列表:根据日期动态查询,展示课程详情和状态
- 签到逻辑:更新 Attendances 表的状态字段,实现签到闭环
下一节我们将实现机构介绍功能,向家长展示机构的师资力量、教学环境及特色课程。