教培管家第13讲:课程排课——智能排课算法与自动化生成

目录

  • 前言
  • 第一步:智能批量排课逻辑实现
    • [1.1 搭建动态时段列表](#1.1 搭建动态时段列表)
    • [1.2 周期预览与保存区](#1.2 周期预览与保存区)
  • 第二步:核心交互逻辑
    • [2.1 计算总课时 (`calcTotalSessions`)](#2.1 计算总课时 (calcTotalSessions))
    • [2.2. 添加排课时段 (`addScheduleSlot`)](#2.2. 添加排课时段 (addScheduleSlot))
    • [2.3 更新时段属性 (`updateScheduleSlot`)](#2.3 更新时段属性 (updateScheduleSlot))
    • [2.4 删除时段(`deleteScheduleSlot`)](#2.4 删除时段(deleteScheduleSlot))
    • [2.5. 执行自动化排课 (`executeBatchScheduling`)](#2.5. 执行自动化排课 (executeBatchScheduling))
  • 第三步:设置组件交互
  • 第四步:功能验证
  • [🌟 总结与预告](#🌟 总结与预告)

前言

在本讲的上半部分,我们完成了排课模型的建立、弹窗视图的初始化以及"周卡片"的切换交互。本篇我们将攻克最核心的两个环节:动态时段配置自动化排课算法


第一步:智能批量排课逻辑实现

1.1 搭建动态时段列表

在用户点击某个"周卡片"后,中部区域需要展示该天已设定的所有时段。

先添加一个按钮,内容改为添加时段

继续添加循环展示组件

数据绑定 :数据源绑定为当前选中天的规则数组:
$w.page.dataset.state.scheduleRules[$w.page.dataset.state.currentDay] || []

内容设计:在循环项中放入"容器",并横向排列以下组件:

  • 时间选择器:绑定开始时间。
  • 时间选择器:绑定结束时间。
  • 下拉选择 :绑定执教老师(数据源关联 Employee)。
  • 下拉选择 :绑定上课教室(数据源关联 Classroom)。
  • 图标按钮:用于删除当前时段。

⚠️ 注意 :由于微搭的循环项中无法直接实现"双向绑定",我们需要通过 onChange 事件调用 JS 方法来同步数据。


1.2 周期预览与保存区

在弹窗底部,我们需要展示最终的统计信息并触发保存。

总课时预览 :添加文本组件,绑定公式计算整个周期内会生成的课节总数。

创建一个变量用来显示我们预期的排课总时长

然后给文本绑定表达式显示时长


第二步:核心交互逻辑

为了驱动复杂的排课交互,我们需要在"应用属性 -> 自定义方法"中编写以下核心逻辑。

2.1 计算总课时 (calcTotalSessions)

为了保证实时预览,我们需要一个通用的计算方法,在日期范围或排课规则变化时调用。

javascript 复制代码
/**
 * 根据日期范围和排课规则计算总课时
 */
export default async function({event, data}) {
  const { startDate, endDate, scheduleRules } = $w.page.dataset.state;
  if (!startDate || !endDate || !scheduleRules) {
    $w.page.dataset.state.totalSessions = 0;
    return;
  }
  
  let total = 0;
  let curr = new Date(startDate);
  const end = new Date(endDate);
  
  while (curr <= end) {
    const day = curr.getDay() === 0 ? 7 : curr.getDay();
    total += (scheduleRules[day]?.length || 0);
    curr.setDate(curr.getDate() + 1);
  }
  
  $w.page.dataset.state.totalSessions = total;
}

2.2. 添加排课时段 (addScheduleSlot)

点击"+ 添加时段"时,为当前选中的星期初始化数据并追加默认值。注意时间戳的处理:

javascript 复制代码
/**
 * 为当前选中的天新增一个排课时段
 */
export default function({event, data}) {
 const currentDay = $w.page.dataset.state.currentDay;
  const scheduleRules = $w.page.dataset.state.scheduleRules || {};
  
  if (!scheduleRules[currentDay]) {
    scheduleRules[currentDay] = [];
  }
  
  const { teacherId, classroomId,courseType } = $w.page.dataset.state.classInfo;
  console.log(teacherId,classroomId)
  const defaultStart = 9 * 60 * 60 * 1000; // 09:00
  const defaultEnd = 10.5 * 60 * 60 * 1000; // 10:30

  scheduleRules[currentDay].push({
    id: Date.now(),
    startTime: defaultStart,
    endTime: defaultEnd,
    teacherId: teacherId?._id||"",
    classroomId: classroomId?._id||"",
    courseType:courseType|| '2'
  });
  
  $w.page.dataset.state.scheduleRules = { ...scheduleRules };
}

2.3 更新时段属性 (updateScheduleSlot)

当用户通过时间选择器修改时间时,微搭组件会返回该日期的时间戳(Number),我们直接同步即可:

javascript 复制代码
/**
 * 更新指定时段的字段值(支持时间戳)
 */
export default function({event, data}) {
const { field, value, index } = data.target; 
  const currentDay = $w.page.dataset.state.currentDay;
  const rules = $w.page.dataset.state.scheduleRules;
  
  // 更新对应位置的属性
  rules[currentDay][index][field] = value;
  
  // 必须通过重新赋值触发状态变量的响应式更新
  $w.page.dataset.state.scheduleRules = { ...rules };
}

2.4 删除时段(deleteScheduleSlot

点击时段行末尾的删除图标时,移除当前选中的时段:

bash 复制代码
export default function({event, data}) {
const { index } = data.target;
  const currentDay = $w.page.dataset.state.currentDay;
  const rules = $w.page.dataset.state.scheduleRules;
  
  // 从数组中移除
  rules[currentDay].splice(index, 1);
  
  // 重新赋值触发 UI 刷新
  $w.page.dataset.state.scheduleRules = { ...rules };
  
  $w.utils.showToast({ title: '已移除该时段', icon: 'success' });
}

2.5. 执行自动化排课 (executeBatchScheduling)

在处理时间戳时,我们需要将"日期"的时间戳与"时段"的时间戳(提取时分秒)进行合并计算:

javascript 复制代码
export default async function ({ event, data }) {
  try {
    const scheduleRules = $w.page.dataset.state.scheduleRules;
    const startDateMs = $w.date1.value;   // 毫秒值,代表那天 00:00:00
    const endDateMs   = $w.date2.value;   // 毫秒值,代表那天 00:00:00
    const classInfo   = $w.page.dataset.state.classInfo;

    if (!startDateMs || !endDateMs) {
      throw new Error('请选择排课周期');
    }

    $w.utils.showLoading({ title: '正在生成课表...' });

    const sessions = [];
    let currentMs = startDateMs;

    // 建议:把 endDate 当天也包含进来(≤)
    while (currentMs <= endDateMs) {
      // 获取星期几(0=周日 → 7)
      const dateObj = new Date(currentMs);
      const dayOfWeek = dateObj.getDay() === 0 ? 7 : dateObj.getDay();

      const dayRules = scheduleRules[dayOfWeek];

      if (dayRules && Array.isArray(dayRules) && dayRules.length > 0) {
        for (const rule of dayRules) {
          // 直接使用 rule.startTime / endTime(一天内的毫秒偏移)
          const finalStart =  rule.startTime;
          const finalEnd   = rule.endTime;

          sessions.push({
            classId:    { _id: classInfo._id },
            date:       currentMs,           // 当天 00:00 的毫秒值(日期基准)
            startTime:  finalStart,          // 完整开始时间戳
            endTime:    finalEnd,            // 完整结束时间戳
            teacherId:  { _id: rule.teacherId },
            classroomId:{ _id: rule.classroomId },
            courseType: rule.courseType,
            status:     '1'
          });
        }
      }

      // +1 天(86400000 ms)
      currentMs += 86400000;
    }

    const result = await $w.cloud.callDataSource({
      dataSourceName: 'Schedule',
      methodName:    'wedaBatchCreateV2',
      params:        { data: sessions }
    });

    $w.utils.hideLoading();

    $w.utils.showModal({
      title:      '排课成功',
      content:    `已成功生成 ${result.idList?.length || 0} 节课。`,
      showCancel: false
    });

    $w.modal1.close({});
    $w.table1.refresh();

  } catch (e) {
    $w.utils.hideLoading();
    $w.utils.showToast({
      title: e.message || '生成课表失败',
      icon:  'error'
    });
  }
}

第三步:设置组件交互

方法定义好之后,就可以给组件配置事件了。

首先给添加时段配置点击事件,先调用添加方法,接着调用计算课时

然后给删除图标定义点击事件,调用删除方法,跟一个重新计算课时的方法

给表格里的每个组件配置值改变事件,调用我们的更新方法

给弹窗的确认按钮添加点击事件,调用我们的批量排课方法

第四步:功能验证

  1. 时段动态性:点击"周三",添加两个时段,然后切换到"周五"查看是否为空,再切回"周三"确认数据是否保留。
  2. 默认回填:确认添加新时段时,老师和教室是否自动回填为该班级的默认配置。
  3. 生成结果:选择一个月的时间范围,点击保存,进入"排课管理"页面查看生成的记录是否准确对应周三的所有时段。




🌟 总结与预告

通过这两篇的学习,我们实现了一个极具专业感的"智能排课向导"。这不仅是简单的增删改查,更是将**业务逻辑(排课规则)转化为生产数据(课节记录)**的典型案例。

下一讲: 《连接家校------家长端注册、登录与身份绑定》。我们将进入小程序的开发,学习如何通过手机号验证码实现家长的快速注册,并完成学员信息的关联绑定。

相关推荐
2501_915106321 小时前
app 上架过程,安装包准备、证书与描述文件管理、安装测试、上传
android·ios·小程序·https·uni-app·iphone·webview
2501_915106321 小时前
使用 Sniffmaster TCP 抓包和 Wireshark 网络分析
网络协议·tcp/ip·ios·小程序·uni-app·wireshark·iphone
HUIBUR科技2 小时前
低代码赋能供应商管理:打破管理壁垒,重塑供应链效能
低代码·数字化转型
guizhoumen2 小时前
2026国内外企业级cms建站系统的BI图表功能评测
低代码·cms·网站建设·建站系统·内容管理系统
豆豆2 小时前
企业级CMS和低代码平台标杆:PageAdmin新版的可视化BI和自定义表单功能体验
低代码·cms·可视化·bi·表单功能·工单功能·统一平台
宠友信息2 小时前
2025社交+IM及时通讯社区APP仿小红书小程序
java·spring boot·小程序·uni-app·web app
红迅低代码平台(redxun)3 小时前
构建企业“第二大脑“:AI低代码平台如何打造智能知识中枢?
人工智能·低代码·ai agent·ai开发平台·智能体开发平台·红迅软件
光影少年1 天前
AIGC + Taro / 小程序
小程序·aigc·taro
2501_915918411 天前
在 iOS 环境下查看 App 详细信息与文件目录
android·ios·小程序·https·uni-app·iphone·webview
2501_916007471 天前
没有 Mac 用户如何上架 App Store,IPA生成、证书与描述文件管理、跨平台上传
android·macos·ios·小程序·uni-app·iphone·webview