教培管家第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. 生成结果:选择一个月的时间范围,点击保存,进入"排课管理"页面查看生成的记录是否准确对应周三的所有时段。




🌟 总结与预告

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

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

相关推荐
潆润千川科技4 小时前
技术视角下的产品拆解:中老年垂直社交小程序矩阵的架构共性
小程序·架构
OctShop大型商城源码4 小时前
商城小程序开源商用_OctShop免费开源可商用的商城小程序
小程序·开源·小程序商城·免费开源可商用的商城小程序
CHU7290355 小时前
宠物寄养小程序前端功能版块详解
小程序·宠物
qq_316837755 小时前
uniapp打包微信小程序使用插件
微信小程序·小程序·uni-app
小朱笼包5 小时前
小程序实现对接百度AI大模型,通过websocket连接进行百度实时语音识别,将返回的文字调用AI大模型API获得返回的消息内容进行文字转语音朗诵并操作
人工智能·websocket·百度·小程序·语音识别
CHU7290355 小时前
线上美容预约小程序:解锁高效变美新路径
小程序
万岳科技系统开发16 小时前
外卖配送系统开发中的核心模块拆解与技术选型思路
小程序·开源
低代码布道师1 天前
教培管家第11讲:班级管理——教务系统的“集成枢纽”
低代码·小程序·云开发
数字游民95271 天前
小程序上新,猜对了么更新110组素材
人工智能·ai·小程序·ai绘画·自媒体·数字游民9527