课程排满课表:鸿蒙课程表种子数据与网格效果


实例:课程表管理(Course)|技术:14 门课程、坐标分布、色板分配
一、种子数据的设计目标
实例 15 的种子数据要撑起「课表网格 + 冲突检测 + 当天列表」,设计目标:
- 14 门课程:课表格子饱满——5 天有课、格子有内容;
- 坐标分布合理:覆盖周一~周六 6 天、不同节次——网格有「课表感」;
- 连堂示例:高等数学(周一 1-2 节)、大学英语(周一 3-4 节)、数据结构(周二 1-2 节)、操作系统(周三 3-4 节)、大学物理(周四 1-2 节)——连堂块可见;
- 色板覆盖:每门课不同颜色——色块区分课程;
- 周六有课:软件工程(周六第 1 节)——「周六也上课」的真实校园场景;
- 周日无课:休息日——验证空节次占位格。
二、14 门课程种子数据
| # | 课程 | 老师 | 教室 | 周几 | 节次 | 颜色 | 教学周 | 备注 |
|---|---|---|---|---|---|---|---|---|
| 1 | 高等数学 | 王教授 | A101 | 周一 | 第1节 | 蓝 #3B82F6 | 1-16 | 带教材 |
| 2 | 高等数学 | 王教授 | A101 | 周一 | 第2节 | 蓝 #3B82F6 | 1-16 | (连堂) |
| 3 | 大学英语 | 李老师 | B203 | 周一 | 第3节 | 绿 #10B981 | 1-16 | 听力练习 |
| 4 | 大学英语 | 李老师 | B203 | 周一 | 第4节 | 绿 #10B981 | 1-16 | (连堂) |
| 5 | 数据结构 | 陈教授 | C305 | 周二 | 第1节 | 紫 #8B5CF6 | 1-16 | 带电脑 |
| 6 | 数据结构 | 陈教授 | C305 | 周二 | 第2节 | 紫 #8B5CF6 | 1-16 | (连堂) |
| 7 | 体育 | 张教练 | 操场 | 周二 | 第5节 | 橙 #F59E0B | 1-16 | 穿运动服 |
| 8 | 操作系统 | 刘教授 | C401 | 周三 | 第3节 | 红 #EF4444 | 1-16 | 期中考试 |
| 9 | 操作系统 | 刘教授 | C401 | 周三 | 第4节 | 红 #EF4444 | 1-16 | (连堂) |
| 10 | 大学物理 | 赵教授 | A305 | 周四 | 第1节 | 青 #06B6D4 | 1-16 | 带计算器 |
| 11 | 大学物理 | 赵教授 | A305 | 周四 | 第2节 | 青 #06B6D4 | 1-16 | (连堂) |
| 12 | 马克思主义原理 | 周老师 | D102 | 周五 | 第3节 | 黄绿 #84CC16 | 1-16 | 大课 |
| 13 | 计算机网络 | 孙老师 | C208 | 周五 | 第5节 | 粉 #EC4899 | 1-12 | 实验课 |
| 14 | 软件工程 | 吴教授 | C109 | 周六 | 第1节 | 橙红 #F97316 | 1-16 | 小组项目 |
设计要点:
- 坐标分布:周一 4 门(2 节连堂 × 2)、周二 3 门(1 连堂 + 1 单节)、周三 2 门(1 连堂)、周四 2 门(1 连堂)、周五 2 门(单节 × 2)、周六 1 门、周日空——周一最忙、周末递减,符合真实课表;
- 连堂视觉:高等数学周一 1-2 节同色相邻——课表里并成「蓝色连堂块」;
- 色板 10 色覆盖:蓝/绿/紫/橙/红/青/黄绿/粉/橙红——每门课可区分;
- 教学周差异:计算机网络 ‘1-12’(前 12 周上,实验课)——与默认 ‘1-16’ 不同,展示 weeks 字段的意义;
- 周日空:切到周日 → 8 个格子全空(浅灰占位格)——验证空位渲染。
三、代码实现
const seed: CourseSeed[] = [ /* 14 门,见第二节表格 */ ];
for (const s of seed) {
const values: relationalStore.ValuesBucket = {
name: s.name, teacher: s.teacher, location: s.location,
weekday: s.weekday, section: s.section, color: s.color,
weeks: s.weeks, remark: s.remark,
};
await store.insert(CourseDao.TABLE, values);
}
hilog.info(DOMAIN, TAG, '已填充 14 门课程种子数据');
幂等保护:查 course COUNT,非空即返回——重复启动不重复填充。CourseSeed 接口:与 Course 一致(无 id)。
四、注入后的课表效果预测
| 区块 | 预期效果 |
|---|---|
| 标题栏 | 「共 14 门课程」 |
| 周一 | 第 1-2 节蓝色「高等数学 王教授 · A101」连堂块 + 第 3-4 节绿色「大学英语」连堂块,其余格空 |
| 周二 | 第 1-2 节紫色「数据结构」连堂 + 第 5 节橙色「体育」 |
| 周三 | 第 3-4 节红色「操作系统」连堂 |
| 周四 | 第 1-2 节青色「大学物理」连堂 |
| 周五 | 第 3 节黄绿「马克思主义原理」+ 第 5 节粉色「计算机网络」 |
| 周六 | 第 1 节橙红「软件工程」 |
| 周日 | 8 个浅灰空位格 |
| 当天列表 | 切周一 → 「周一 · 共 4 节课」+ 4 行明细(节次圆标 + 课程名 + 时间老师教室) |
演示脚本:指着课表说「我一周 14 门课,周一最忙——上午两节高数、两节英语,都是连堂」→ 切周二「数据结构连堂加下午体育」→ 切周日「周日没课,格子全空」→ 点周一的蓝色高数块 → 菜单「查看详情」→ 弹窗显示「王教授 · A101 / 周一 第1节 / 08:00-08:45 / 教学周:1-16」。
五、验证方法
- hilog 日志:搜
CourseDao,看到「已填充 14 门课程种子数据」; - 页面显示:标题栏「14 门」、周一 4 门、周日全空、当天列表正确;
- 数据库直查:
SELECT COUNT(*) FROM course; -- 14 SELECT weekday, COUNT(*) FROM course GROUP BY weekday ORDER BY weekday; -- 1:4 2:3 3:2 4:2 5:2 6:1 7:0 SELECT name, weekday, section FROM course WHERE weekday = 1 ORDER BY section; -- 高等数学 1,2 / 大学英语 3,4 SELECT * FROM course WHERE weekday = 1 AND section = 3; -- 大学英语(冲突检测命中) - 交互验证:切周日看空位格、点色块看详情菜单、删除课程后格子变空、添加课程冲突提示。
六、FAQ
Q1:为什么周一最忙(4 门)、周六只有 1 门?
A:真实课表「周一最忙、周末递减」——种子复现典型分布。周一上午两门连堂(高数 + 英语)是常见排课,周六 1 门(软件工程)展示「周六上课」场景。坐标分布模拟真实校园,不是平均撒数据。
Q2:连堂为什么是两条记录而不是「起止节次」字段?
A:两条记录让「格子填充」最简单——每节次查格子,有课就显示色块;相邻同色自然连成块。若用「起止节次」字段(section_start + section_end),查询要处理区间匹配(section BETWEEN start AND end),网格渲染更复杂。「逐格记录」换取「逐格渲染」的简单。
Q3:为什么周日不排课?
A:周日是休息日——8 个空位格验证「空节次占位渲染」(浅灰块)。种子要覆盖「有课」与「无课」两种状态,空位渲染是课表网格的重要视觉(否则无法区分「没课」与「加载失败」)。
Q4:计算机网络为什么教学周是 1-12?
A:真实教务里实验课只上部分周(前 12 周)——weeks: '1-12' 展示教学周字段的多样性。Demo 不解析(纯展示),进阶可在课程详情里「本周是否上课」判断(解析 ‘1-12’ 区间)。字段先存、解析后做。
Q5:为什么 5 门课带备注?
A:备注(带教材/听力练习/穿运动服/期中考试/带计算器/实验课/大课/小组项目)是真实课表的信息(提醒带什么、考试预警)。备注让课表「有人味」——不是干巴巴的课名。
Q6:色板 10 色只用了 9 色,够吗?
A:14 门课 9 种颜色(两门连堂同色)——每门课颜色可区分(同课连堂同色)。色板 10 色留 1 余量,新增课程有颜色可选。「色块区分课程」的前提是颜色不重复,连堂同色恰好利用了这个特性。
七、文章小结
本篇文章展示了实例 15 的种子数据:14 门课程(周一最忙 4 门 → 周六 1 门 → 周日空的坐标分布 + 5 组连堂 + 9 色覆盖 + 教学周差异 + 备注)。核心是「课表感的种子设计」——连堂相邻成块、周日空位验证占位渲染、计算机网络 1-12 周展示字段多样性。课表网格一开屏就格子饱满、色块分明。
下一篇(15-5)是实例 15 的收官文章,展示 CoursePage 全量代码与运行效果。
八、种子数据全量表:时间列补全与逐条核对
第二节的表格缺「时间段」列——课表格子显示节次序号,但详情弹窗要展示起止时间。按「单节 45 分钟、课间 10 分钟、午休 12:00-14:00」的校园作息补全:
| # | 课程 | 老师 | 教室 | 周几 | 节次 | 时间段 | 颜色 | 教学周 | 备注 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 高等数学 | 王教授 | A101 | 周一 | 第1节 | 08:00-08:45 | 蓝 #3B82F6 | 1-16 | 带教材 |
| 2 | 高等数学 | 王教授 | A101 | 周一 | 第2节 | 08:55-09:40 | 蓝 #3B82F6 | 1-16 | (连堂) |
| 3 | 大学英语 | 李老师 | B203 | 周一 | 第3节 | 10:00-10:45 | 绿 #10B981 | 1-16 | 听力练习 |
| 4 | 大学英语 | 李老师 | B203 | 周一 | 第4节 | 10:55-11:40 | 绿 #10B981 | 1-16 | (连堂) |
| 5 | 数据结构 | 陈教授 | C305 | 周二 | 第1节 | 08:00-08:45 | 紫 #8B5CF6 | 1-16 | 带电脑 |
| 6 | 数据结构 | 陈教授 | C305 | 周二 | 第2节 | 08:55-09:40 | 紫 #8B5CF6 | 1-16 | (连堂) |
| 7 | 体育 | 张教练 | 操场 | 周二 | 第5节 | 14:00-14:45 | 橙 #F59E0B | 1-16 | 穿运动服 |
| 8 | 操作系统 | 刘教授 | C401 | 周三 | 第3节 | 10:00-10:45 | 红 #EF4444 | 1-16 | 期中考试 |
| 9 | 操作系统 | 刘教授 | C401 | 周三 | 第4节 | 10:55-11:40 | 红 #EF4444 | 1-16 | (连堂) |
| 10 | 大学物理 | 赵教授 | A305 | 周四 | 第1节 | 08:00-08:45 | 青 #06B6D4 | 1-16 | 带计算器 |
| 11 | 大学物理 | 赵教授 | A305 | 周四 | 第2节 | 08:55-09:40 | 青 #06B6D4 | 1-16 | (连堂) |
| 12 | 马克思主义原理 | 周老师 | D102 | 周五 | 第3节 | 10:00-10:45 | 黄绿 #84CC16 | 1-16 | 大课 |
| 13 | 计算机网络 | 孙老师 | C208 | 周五 | 第5节 | 14:00-14:45 | 粉 #EC4899 | 1-12 | 实验课 |
| 14 | 软件工程 | 吴教授 | C109 | 周六 | 第1节 | 08:00-08:45 | 橙红 #F97316 | 1-16 | 小组项目 |
时间映射规则:第 1/3/5/7 节整点开始(08:00 / 10:00 / 14:00 / 16:00),单节 45 分钟、课间 10 分钟,第 5 节从 14:00 起(午休两小时)。种子只存「节次序号」,时间段由 sectionTime(section) 映射函数生成——作息规则一处定义全局生效,不冗余存时间字段。
九、种子设计复盘:三个「课表感」来源
1. 分布复盘:周一最忙 → 周日空
| 周几 | 课程数 | 占比 | 视觉 |
|---|---|---|---|
| 周一 | 4 | 28.6% | 上午两连堂,饱满 |
| 周二 | 3 | 21.4% | 连堂 + 下午体育 |
| 周三 | 2 | 14.3% | 一个连堂 |
| 周四 | 2 | 14.3% | 一个连堂 |
| 周五 | 2 | 14.3% | 两个单节 |
| 周六 | 1 | 7.1% | 单节点缀 |
| 周日 | 0 | 0% | 全空 |
课程数从周一 4 门单调递减到周日 0 门——真实课表「前紧后松」的曲线。为什么刻意这样分布?冲突检测、当天列表、空位渲染三个功能都需要「有课的日子 + 没课的日子」同时存在才能演示;若平均撒数据(每天 2 门),「周日全空」「周一最忙」的视觉差异就消失了,课表感大打折扣。
2. 连堂视觉复盘:同色相邻自然成块
高等数学两节同为蓝 #3B82F6、大学英语两节同为绿 #10B981——网格中两格同色相邻,人眼自动把「周一 1-2 节」合并成一块蓝色、「3-4 节」合并成一块绿色。连堂视觉靠「同课同色 + 坐标相邻」两个条件自然形成,零合并逻辑:color 相同且 section 相差 1 即视觉连堂,不需要额外的「连堂标记」字段——种子设计替渲染层省掉了合并算法。
3. 教学周差异复盘:‘1-16’ 与 ‘1-12’ 并存
14 门课中 13 门 weeks=‘1-16’(全学期),只有计算机网络 weeks=‘1-12’(实验课前 12 周)——字段多样性体现在同一字段的不同取值,而非新增字段。Demo 阶段 weeks 只存不解析,网格渲染不判断「本周是否上课」;进阶做周视图时再解析区间(parseWeeks('1-12') 判断当前周命中)。这是「先存数据、后做语义」的种子设计原则——数据层先把多样性存下来,语义留给后续功能演进。
十、initSeedData 完整实现
interface CourseSeed {
name: string; teacher: string; location: string;
weekday: number; section: number; color: string;
weeks: string; remark: string;
}
static async initSeedData(context: common.Context): Promise<void> {
const store = await CourseDao.getStore(context);
const count = await CourseDao.count(context); // 幂等保护:已有数据不重复填充
if (count > 0) {
hilog.info(DOMAIN, TAG, '已有 %{public}d 门课程,跳过种子填充', count);
return;
}
const seed: CourseSeed[] = [
{ name: '高等数学', teacher: '王教授', location: 'A101', weekday: 1, section: 1, color: '#3B82F6', weeks: '1-16', remark: '带教材' },
{ name: '高等数学', teacher: '王教授', location: 'A101', weekday: 1, section: 2, color: '#3B82F6', weeks: '1-16', remark: '(连堂)' },
// … 其余 12 条与第八节表格逐条对应,字段结构同上
];
for (const s of seed) {
const values: relationalStore.ValuesBucket = {
name: s.name, teacher: s.teacher, location: s.location,
weekday: s.weekday, section: s.section, color: s.color,
weeks: s.weeks, remark: s.remark,
};
await store.insert(CourseDao.TABLE, values);
}
hilog.info(DOMAIN, TAG, '已填充 14 门课程种子数据');
}
三个关键点:①count > 0 提前 return——页面重复进入、应用重启都不会产生重复课程,幂等是种子数据的底线;②CourseSeed 无 id 字段,主键交给数据库自增——种子结构与查询出的 Course 仅差 id 一列;③逐条 insert 而非批量——14 条量级毫秒完成、不需要事务,单条失败可凭 hilog 报错行单独定位。
十一、注入后的课表效果预测
| 视角 | 预测效果 |
|---|---|
| 网格整体 | 周一蓝绿两连堂、周二紫连堂 + 橙体育、周三红连堂、周四青连堂、周五黄绿 + 粉单节、周六橙红孤块、周日 8 个浅灰空位格 |
| 标题栏 | 「共 14 门课程」 |
| 当天列表 | 切周一 → 「周一 · 共 4 节课」+ 4 行明细;切周日 → 空态「今天没课」 |
| 冲突检测 | 新增「周一 第3节」→ 命中大学英语 → 弹「该时段已有课」 |
| 周视图(进阶) | 第 13 周起计算机网络格子变空(weeks=‘1-12’ 解析生效) |
十二、验证 SQL 全集
-- 1) 总数与课程去重
SELECT COUNT(*) FROM course; -- 14
SELECT COUNT(DISTINCT name) FROM course; -- 9(14 条记录去重后 9 门课)
-- 2) 每天课程数:验证周一最忙 → 周日空
SELECT weekday, COUNT(*) AS cnt FROM course
GROUP BY weekday ORDER BY weekday; -- 1:4 2:3 3:2 4:2 5:2 6:1 7:0
-- 3) 连堂校验:同课同天多条
SELECT name, weekday, MIN(section) AS startSection, MAX(section) AS endSection
FROM course GROUP BY name, weekday
HAVING COUNT(*) > 1; -- 5 组连堂
-- 4) 教学周差异
SELECT name, weeks FROM course WHERE weeks <> '1-16'; -- 计算机网络 1-12
-- 5) 冲突检测命中(模拟新增「周一 第3节」)
SELECT * FROM course WHERE weekday = 1 AND section = 3; -- 大学英语
解读:GROUP BY weekday 一行看出分布曲线(4→0 递减);HAVING COUNT(*) > 1 把连堂课程找出来(同课同天多条 = 连堂);weeks <> '1-16' 直接暴露教学周差异——三句话对应三个设计目标,验证种子没有「撒偏」。
十三、FAQ 补充
Q7:为什么时间不存字段,要由节次映射?
A:作息表是全局规则(第 1 节 08:00 全课表一致)——存节次序号,sectionTime(section) 一处定义、14 门课共享;若每行存时间字段,改一次作息要 UPDATE 14 行。全局规则抽成函数,不冗余进每行数据。
Q8:周日 0 门,当天列表会怎样?
A:切周日 → 当天列表显示空态「周日 · 共 0 节课」+ 空提示文案。种子特意留周日空——空态 UI 和空位格一样需要真实数据触发,不留空就无法演示「没课」的状态。
Q9:为什么逐条 insert 不用事务?
A:14 条全内存数据、insert 毫秒级,失败概率极低;事务用于「多表一致性」,单表种子不值得。若未来种子上百条,再包 beginTransaction() 批量提速。
Q10:计算机网络第 13 周会怎样?
A:Demo 阶段照样显示(weeks 只存不解析);进阶周视图解析 ‘1-12’,第 13 周起该格变空。这就是「字段先存、语义后做」的演进路径——种子数据为未来功能预留了验证样本。
更多推荐




所有评论(0)