鸿蒙教育机构管理系统 课程排期与学员管理【华为云根技术】
【摘要】 一 引言与技术背景教育机构的教务管理正从Excel/分散系统向移动化、智能化、跨设备协同升级。HarmonyOS 的分布式软总线、统一开发框架 ArkUI、原子化服务与本地化数据存储为排课冲突检测、学员全生命周期管理与多端一致体验提供了系统级能力支撑。行业痛点包括:课程排期效率低(教室/教师/时间冲突频发)、学员信息分散(报名/考勤/成绩割裂)、跨设备协同差(课表更新不同步)。鸿蒙的分布式与...
一 引言与技术背景
-
教育机构的教务管理正从Excel/分散系统向移动化、智能化、跨设备协同升级。HarmonyOS 的分布式软总线、统一开发框架 ArkUI、原子化服务与本地化数据存储为排课冲突检测、学员全生命周期管理与多端一致体验提供了系统级能力支撑。
-
行业痛点包括:课程排期效率低(教室/教师/时间冲突频发)、学员信息分散(报名/考勤/成绩割裂)、跨设备协同差(课表更新不同步)。鸿蒙的分布式与多端一致 UI 能有效缓解上述问题。
-
高校与头部教培机构已加速鸿蒙原生应用落地,覆盖课程安排、考勤门禁、成绩查询等高频场景,并推出元服务实现“即点即用”,验证了鸿蒙在教育场景的可行性与成熟度。
二 应用使用场景
-
课程排期管理(教师/教务端):在平板上拖拽式排课,系统自动检测教室/教师/时间冲突,排期完成后自动同步至学员手机端课表。
-
学员信息管理(管理员端):集中管理报名、班级、考勤、成绩,支持离线查询与按班级/课程筛选统计。
-
跨设备协同(学员/教师/智慧屏):教师在智慧屏展示课程大纲,学员用手机扫码加入互动;课表变更多端一致。
-
扩展:对接分布式数据服务实现多设备同步;将排期/学员查询拆分为原子化服务供按需调用。
三 核心特性与原理流程图
-
核心特性
-
冲突检测引擎:基于“教室+教师+时间”三维约束的重叠判断,保障排课合法性。
-
本地优先:使用Preferences持久化课程/学员数据,保障离线可用与快速启动。
-
多端一致:基于ArkUI声明式 UI,同一代码适配手机/平板/智慧屏。
-
可扩展分布式:可按需接入分布式数据服务与原子化服务,实现多设备同步与功能解耦。
-
-
原理流程图
[UI 操作:新增/修改课程或学员] | [冲突检测:教室/教师/时间重叠] | [通过?] ——否——> [提示冲突] | 是 | [本地持久化:Preferences 写入] | [可选:分布式数据同步至其他设备] | [UI 刷新与通知]
四 环境准备
-
开发工具:DevEco Studio NEXT(建议最新稳定版),选择ArkTS与Stage 模型。
-
目标设备:Phone/Tablet(建议 API ≥ 10),授予麦克风/网络/存储等必要权限(如需)。
-
工程结构建议:
entry/src/main/ets/ entryability/ pages/ ScheduleManage.ets StudentManage.ets model/ Course.ets Student.ets services/ ScheduleService.ets StudentService.ets common/ utils/ DateUtil.ets -
本地存储选型:优先使用@ohos.data.preferences进行轻量级结构化存储(课程/学员列表 JSON 序列化)。
五 不同场景的代码实现
-
场景一 课程排期管理(冲突检测 + 本地保存 + 列表展示)
-
数据模型 model/Course.ets
export class Course { id: string = ''; name: string = ''; teacher: string = ''; classroom: string = ''; startTime: string = ''; // HH:mm endTime: string = ''; // HH:mm dayOfWeek: number = 0; // 0=周一,6=周日 } export class Classroom { id: string = ''; name: string = ''; }-
工具类 common/utils/DateUtil.ets
// 将 HH:mm 转为分钟数 export function timeToMinutes(t: string): number { const [h, m] = t.split(':').map(Number); return h * 60 + m; } // 判断时间区间是否重叠 export function isTimeOverlap( s1: string, e1: string, s2: string, e2: string ): boolean { const start1 = timeToMinutes(s1); const end1 = timeToMinutes(e1); const start2 = timeToMinutes(s2); const end2 = timeToMinutes(e2); return !(end1 <= start2 || end2 <= start1); }-
排期服务 services/ScheduleService.ets
import preferences from '@ohos.data.preferences'; import { BusinessError } from '@ohos.base'; import { Course } from '../model/Course'; import { isTimeOverlap } from '../common/utils/DateUtil'; const STORE_KEY = 'courses'; export class ScheduleService { private context: Context; private storage: preferences.Preferences | null = null; constructor(context: Context) { this.context = context; } async init(): Promise<void> { try { this.storage = await preferences.getPreferences(this.context, 'course_data'); } catch (err) { console.error('Preferences init failed', err as BusinessError); } } async load(): Promise<Course[]> { if (!this.storage) await this.init(); try { const json = await this.storage!.get(STORE_KEY, '[]') as string; return JSON.parse(json) as Course[]; } catch (err) { console.error('Load courses failed', err as BusinessError); return []; } } async save(courses: Course[]): Promise<void> { if (!this.storage) await this.init(); try { await this.storage!.put(STORE_KEY, JSON.stringify(courses)); await this.storage!.flush(); } catch (err) { console.error('Save courses failed', err as BusinessError); } } checkConflict(newCourse: Course, existing: Course): boolean { if (newCourse.id === existing.id) return false; // 自身忽略 const overlap = isTimeOverlap( newCourse.startTime, newCourse.endTime, existing.startTime, existing.endTime ); const sameRoom = newCourse.classroom === existing.classroom; const sameTeacher = newCourse.teacher === existing.teacher; return (sameRoom && overlap) || (sameTeacher && overlap); } async add(course: Course): Promise<boolean> { const list = await this.load(); if (list.some(c => this.checkConflict(newCourse, c))) { return false; // 冲突 } course.id = Date.now().toString(); list.push(course); await this.save(list); return true; } async update(course: Course): Promise<boolean> { const list = await this.load(); const idx = list.findIndex(c => c.id === course.id); if (idx === -1) return false; // 冲突检测排除自身 const others = [...list]; others.splice(idx, 1); if (others.some(c => this.checkConflict(course, c))) { return false; } list[idx] = course; await this.save(list); return true; } async delete(id: string): Promise<void> { const list = await this.load(); const next = list.filter(c => c.id !== id); await this.save(next); } }-
排期页面 pages/ScheduleManage.ets
import { Course, Classroom } from '../model/Course'; import { ScheduleService } from '../services/ScheduleService'; import { timeToMinutes } from '../common/utils/DateUtil'; import preferences from '@ohos.data.preferences'; import { BusinessError } from '@ohos.base'; import router from '@ohos.router'; @Entry @Component struct ScheduleManage { @State courses: Course[] = []; @State classrooms: Classroom[] = [ { id: 'A101', name: '教室A101' }, { id: 'B202', name: '教室B202' } ]; @State teachers: string[] = ['张老师', '李老师', '王老师']; @State showForm: boolean = false; @State editCourse: Course = new Course(); @State dayOfWeekItems: string[] = ['周一','周二','周三','周四','周五','周六','周日']; private svc: ScheduleService = new ScheduleService(getContext(this) as common.UIAbilityContext); aboutToAppear() { this.loadCourses(); } private async loadCourses() { this.courses = await this.svc.load(); } private async onAdd() { this.editCourse = new Course(); this.editCourse.dayOfWeek = 0; this.editCourse.startTime = '09:00'; this.editCourse.endTime = '10:30'; this.showForm = true; } private async onEdit(c: Course) { this.editCourse = { ...c }; this.showForm = true; } private async onDelete(id: string) { await this.svc.delete(id); await this.loadCourses(); } private async onSave() { if (!this.editCourse.name || !this.editCourse.teacher || !this.editCourse.classroom) { // 简单校验 return; } let ok = false; if (this.editCourse.id) { ok = await this.svc.update(this.editCourse); } else { ok = await this.svc.add(this.editCourse); } if (ok) { this.showForm = false; await this.loadCourses(); } else { // 冲突提示 AlertDialog.show({ title: '冲突提示', message: '该教室或教师在此时间段已被占用,请调整!', confirm: { value: '确定', action: () => {} } }); } } private onCancel() { this.showForm = false; } build() { Column({ space: 12 }) { Row() { Text('课程排期管理') .fontSize(20) .fontWeight(FontWeight.Bold) .layoutWeight(1) Button('新增') .onClick(() => this.onAdd()) } .width('100%') .padding({ left: 12, right: 12, top: 8 }) List({ space: 8 }) { ForEach(this.courses, (item: Course) => { ListItem() { Row({ space: 8 }) { Column({ space: 4 }) { Text(item.name) .fontSize(16) .fontWeight(FontWeight.Medium) Text(`${item.teacher} | ${item.classroom}`) .fontSize(12) .fontColor('#666') } .alignItems(HorizontalAlign.Start) .layoutWeight(1) Text(this.dayOfWeekItems[item.dayOfWeek]) .fontSize(12) .backgroundColor('#EAF6FF') .padding({ left: 6, right: 6, top: 2, bottom: 2 }) .borderRadius(4) Text(`${item.startTime}-${item.endTime}`) .fontSize(12) .fontColor('#333') Row({ space: 4 }) { Button('编辑') .fontSize(12) .onClick(() => this.onEdit(item)) Button('删除') .fontSize(12) .backgroundColor('#FF6B6B') .onClick(() => this.onDelete(item.id)) } } .width('100%') .padding(8) .backgroundColor('#FFF') .borderRadius(6) } }, (item: Course) => item.id) } .layoutWeight(1) if (this.showForm) { Column({ space: 12 }) { Text(this.editCourse.id ? '编辑课程' : '新增课程') .fontSize(16) .fontWeight(FontWeight.Medium) TextInput({ placeholder: '课程名称' }) .onChange(v => this.editCourse.name = v) Select(this.teachers) .selected(this.teachers.indexOf(this.editCourse.teacher)) .onSelect((idx: number) => { this.editCourse.teacher = this.teachers[idx]; }) .width('100%') Select(this.classrooms.map(c => c.name)) .selected(this.classrooms.findIndex(c => c.id === this.editCourse.classroom)) .onSelect((idx: number) => { this.editCourse.classroom = this.classrooms[idx].id; }) .width('100%') Select(this.dayOfWeekItems) .selected(this.editCourse.dayOfWeek) .onSelect((idx: number) => { this.editCourse.dayOfWeek = idx; }) .width('100%') Row({ space: 8 }) { TextInput({ placeholder: '开始时间 HH:mm' }) .width('45%') .onChange(v => this.editCourse.startTime = v) TextInput({ placeholder: '结束时间 HH:mm' }) .width('45%') .onChange(v => this.editCourse.endTime = v) } Row({ space: 8 }) { Button('取消') .onClick(() => this.onCancel()) Button('保存') .onClick(() => this.onSave()) } } .width('100%') .padding(12) .backgroundColor('#F7F9FF') .borderRadius(8) } } .width('100%') .height('100%') .padding(12) } } -
-
场景二 学员信息管理(增删改查 + 按班级筛选)
-
数据模型 model/Student.ets
export class Student { id: string = ''; name: string = ''; age: number = 0; phone: string = ''; className: string = ''; // 班级 enrolledCourses: string[] = []; // 已报名课程ID }-
学员服务 services/StudentService.ets
import preferences from '@ohos.data.preferences'; import { BusinessError } from '@ohos.base'; import { Student } from '../model/Student'; const STORE_KEY = 'students'; export class StudentService { private context: Context; private storage: preferences.Preferences | null = null; constructor(context: Context) { this.context = context; } async init(): Promise<void> { try { this.storage = await preferences.getPreferences(this.context, 'student_data'); } catch (err) { console.error('Preferences init failed', err as BusinessError); } } async load(): Promise<Student[]> { if (!this.storage) await this.init(); try { const json = await this.storage!.get(STORE_KEY, '[]') as string; return JSON.parse(json) as Student[]; } catch (err) { console.error('Load students failed', err as BusinessError); return []; } } async save(list: Student[]): Promise<void> { if (!this.storage) await this.init(); try { await this.storage!.put(STORE_KEY, JSON.stringify(list)); await this.storage!.flush(); } catch (err) { console.error('Save students failed', err as BusinessError); } } async add(s: Student): Promise<void> { const list = await this.load(); s.id = Date.now().toString(); list.push(s); await this.save(list); } async update(s: Student): Promise<void> { const list = await this.load(); const idx = list.findIndex(x => x.id === s.id); if (idx !== -1) { list[idx] = s; await this.save(list); } } async delete(id: string): Promise<void> { const list = await this.load(); const next = list.filter(x => x.id !== id); await this.save(next); } }-
学员管理页面 pages/StudentManage.ets
import { Student } from '../model/Student'; import { StudentService } from '../services/StudentService'; import { router } from '@ohos.router'; @Entry @Component struct StudentManage { @State students: Student[] = []; @State filtered: Student[] = []; @State classes: string[] = ['全部']; @State selectedClass: string = '全部'; @State showForm: boolean = false; @State editStudent: Student = new Student(); private svc: StudentService = new StudentService(getContext(this) as common.UIAbilityContext); aboutToAppear() { this.loadStudents(); } private async loadStudents() { this.students = await this.svc.load(); this.buildClassOptions(); this.applyFilter(); } private buildClassOptions() { const set = new Set<string>(); this.students.forEach(s => { if (s.className) set.add(s.className); }); this.classes = ['全部', ...Array.from(set).sort()]; } private applyFilter() { if (this.selectedClass === '全部') { this.filtered = this.students; } else { this.filtered = this.students.filter(s => s.className === this.selectedClass); } } private async onAdd() { this.editStudent = new Student(); this.showForm = true; } private async onEdit(s: Student) { this.editStudent = { ...s }; this -
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)