请选择 进入手机版 | 继续访问电脑版
帖子
帖子
用户
博客
课程

AVM课程表功能的实现

YonBuilder移动开发 2022-6-23 13:40 621人浏览 0人回复
原作者: 川哥哥 收藏 邀请
摘要

一、效果图展示 二、功能实现的思路 本项目基于avm框架编写,因此需要想办法去构造特定数据、然后再改变数据,本项目核心业务就是课程数据的处理,难点就是课程的添加。 项目主要针对大学课表进行设计, ...



一、效果图展示


[attach]127182[/attach]
[attach]127183[/attach]

二、功能实现的思路
本项目基于avm框架编写,因此需要想办法去构造特定数据、然后再改变数据,本项目核心业务就是课程数据的处理,难点就是课程的添加。


[attach]127184[/attach]



项目主要针对大学课表进行设计,课程很多地方存在不确定性,比如课程周次数可能连续的也可能不连续的、上课时间可能是1-2节也可能一整天、上课教室也可能不相同,因此课程的数据结构可以参照下图。


[attach]127185[/attach]

后端需要提供当前周、当前课表名称、当前周所有课程数据、添加课程等接口,当然课程数据查询是比较复杂的,这里就不讲。前端主要是将课表信息显示在指定位置,数据比较简单。


1、课程列表页面
① 当前周课程原始数据结构
[attach]127186[/attach]

这个数据需要前端再次重构才能使用,因为需要将课程摆放到指定位置,必须知道课程距离顶部的高度以及自身高度。可以通过上课时间jie这个参数获取height,top。转换后的数据结构如下
  1. let data = [{
  2.             'name': '大数据可视化技术',
  3.             'room': '机房C414',
  4.             'weekday': '3',
  5.             'bg': '2',
  6.             'jie': '3-4',
  7.             'top': '140px',
  8.             'height': '140px'
  9.         }]
复制代码
[attach]127187[/attach]

横向分为8份,每份宽度12.5%,高度70px,默认可以显示13节课。课程背景默认有7种样式,星期对应的是left参数也有7种样式,具体css如下:
  1. .bg-1 { background: linear-gradient(#facea8, #fe8979)}
  2. .bg-2 { background: linear-gradient(#dfc3fe, #90c5fb)}
  3. .bg-3 { background: linear-gradient(#9deef5, #68e1b5)}
  4. .bg-4 { background: linear-gradient(#eeba93, #dd65c7)}
  5. .bg-5 { background: linear-gradient(#e6f6c9, #68e1b5)}
  6. .bg-6 { background: linear-gradient(#dfc3fe, #dd65c7)}
  7. .bg-7 { background: linear-gradient(#c8e65f, #7abafb)}

  8. .week-1 {left: 12.5%;}
  9. .week-2 {left: 25%;}
  10. .week-3 {left: 37.5%;}
  11. .week-4 {left: 50%;}
  12. .week-5 {left: 62.5%;}
  13. .week-6 {left: 75%;}
  14. .week-0 {left: 87.5%;}
复制代码


每一门课程都使用绝对定位,宽度相同,根据上课时间决定高度、位置。源代码如下

  1. <view class="course_list">
  2. <view v-for="(rs,key) in course_data" :key="key" :class="'course week-'+rs.weekday+' bg-'+rs.bg" :style="'height:'+rs.height+';top:'+rs.top">
  3. <text class=" course-name">{{rs.name}}</text>
  4.                <text class="course-room">{{rs.room}}</text>
  5. </view>
  6. </view>
复制代码


② 当前周日期的展示以及数据结构
[attach]127197[/attach]

[attach]127188[/attach]

获取当前周的日期setDate()源代码如下
  1. this.setDate(new Date());
  2.         setDate(date) {
  3.             let arr = [];
  4.             let week = date.getDay() - 1;
  5.             date = this.addDate(date, week * -1);
  6.             this.currentFirstDate = new Date(date);
  7.             for (var i = 0; i < 7; i++) {
  8.                 arr[i] = this.formatDate(i == 0 ? date : this.addDate(date, 1))
  9.             }
  10.             this.week_data = arr
  11.             this.currentWeek()
  12.         },
  13.         addDate(date, n) {
  14.             date.setDate(date.getDate() + n);
  15.             return date;
  16.         },
  17.         formatDate(date) {
  18.             let year = date.getFullYear();
  19.             let month = (date.getMonth() + 1);
  20.             let day = date.getDate();
  21.             let week = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()];
  22.             this.currentMonth = month;
  23.             if (month < 10) { month = '0' + month; }
  24.             if (day < 10) { day = '0' + day; }
  25.             return { "week": week, "date": month + '/' + day, "active": false };
  26.         },
  27.         //当前星期
  28.         currentWeek() {
  29.             let date = new Date();
  30.             let weekday = date.getDay();
  31.             if (weekday == 1) {
  32.                 this.week_data[0].active = true
  33.             } else if (weekday == 2) {
  34.                 this.week_data[1].active = true
  35.             } else if (weekday == 3) {
  36.                 this.week_data[2].active = true
  37.             } else if (weekday == 4) {
  38.                 this.week_data[3].active = true
  39.             } else if (weekday == 5) {
  40.                 this.week_data[4].active = true
  41.             } else if (weekday == 6) {
  42.                 this.week_data[5].active = true
  43.             } else if (weekday == 0) {
  44.                 this.week_data[6].active = true
  45.             }
  46.         }
复制代码


上一周以及下一周相应代码

  1. last() {
  2.             if (this.week > 1) {
  3.                 this.week = this.week - 1
  4.                 this.setDate(this.addDate(this.currentFirstDate, -7));
  5.             }
  6.         },
  7.         next() {
  8.             if (this.week < 20) {
  9.                 this.week = this.week + 1
  10.                 this.setDate(this.addDate(this.currentFirstDate, 7));
  11.             }
  12.         }
复制代码




2、课程添加页面

本项目主要针对大学课程进行设计,由于上课时间地点可能不规律,因此需要考虑周次、节次、星期、上课地点等几个因素。为了方便用户快速添加课程,同一门课程可支持添加多个上课时间。课程添加的业务逻辑只有周次选择、时间选择两个地方有点复杂因此将其拆分为两个组件<class-week></class-week> <class-time></class-time>


[attach]127203[/attach]

课程的主要字段如下
  1. name: '大学计算机',       //课程名称
  2. room: '机房C411',        //上课教室
  3. teacher: '李国海',       //任课教师
  4. weekday: '0',            //星期
  5. weeks: '1-9,11-20',      //上课周数
  6. jie: '5-9',              //上课节次
  7. bg:'1',                  //课程颜色,系统提供7种颜色
复制代码
大学的课程上课时间可能不规律上课周数也不一定是20周,周数大致分为单双周以及其他,周数的格式如下:
不规律的周次格式:1-9,11,13,15-20
1-20周单周的格式:1,3,5,7,9,11,13,15,17,19
1-20周双周的格式:2,4,6,8,10,12,14,16,18,20
1-20周的格式:1-20
但是这种数据格式对后端数据查询很不友好。



页面初始数据,默认1-24周全部选中。
[attach]127204[/attach]


① 单周choose(1),双周choose(2),全选choose(0)具体业务处理源代码如下
  1. choose(n) {
  2.             for (let i in this.weeks) {
  3.                 this.weeks[i].on = false
  4.             }
  5.             if (n == 1) {
  6.                 if (this.choose == 1) {
  7.                     this.choose = 3
  8.                 } else {
  9.                     this.choose = 1
  10.                     for (let i = 0; i < this.weeks.length; i++) {
  11.                         if (this.weeks[i].week % 2 != 0) {
  12.                             this.weeks[i].on = true
  13.                         }
  14.                     }
  15.                 }

  16.             } else if (n == 2) {
  17.                 if (this.choose == 2) {
  18.                     this.choose = 3
  19.                 } else {
  20.                     this.choose = 2
  21.                     for (let i = 0; i < this.weeks.length; i++) {
  22.                         if (this.weeks[i].week % 2 == 0) {
  23.                             this.weeks[i].on = true
  24.                         }
  25.                     }
  26.                 }
  27.             } else if (n == 0) {
  28.                 if (this.choose == 0) {
  29.                     this.choose = 3
  30.                 } else {
  31.                     this.choose = 0
  32.                     for (let i in this.weeks) {
  33.                         this.weeks[i].on = true
  34.                     }
  35.                 }
  36.             }
  37.         }
复制代码


② 选择某一周的函数set_week(i) 源代码如下
  1. set_week(i) {
  2.             if (this.weeks[i].on == true) {
  3.                 this.weeks[i].on = false
  4.             } else {
  5.                 this.weeks[i].on = true
  6.             }
  7.         }
复制代码


③ 确定按钮get_weeks()源代码如下
  1. get_weeks() {
  2.             this.mask = false //影藏组件
  3.             let arr = [];
  4.             for (let i = 0; i < this.weeks.length; i++) {
  5.                 let on = this.weeks[i].on;
  6.                 if (on == true) {
  7.                     arr.push(this.weeks[i].week);
  8.                 }
  9.             }

  10.             let result = [];
  11.             let tmp;
  12.             while (tmp = arr.shift()) {
  13.                 if (result.length == 0) {
  14.                     result.push([tmp]);
  15.                     continue;
  16.                 }
  17.                 let e = result[result.length - 1];
  18.                 if (tmp == e[e.length - 1] + 1) {
  19.                     e.push(tmp);
  20.                 } else {
  21.                     result.push([tmp]);
  22.                 }
  23.             }

  24.             for (let i = 0; i < result.length; i++) {
  25.                 let res = result[i];
  26.                 if (res.length > 1) {
  27.                     result[i] = res[0] + '-' + res[res.length - 1];
  28.                 } else {
  29.                     result[i] = res[0] + ''
  30.                 }
  31.             }
  32.             for (let i = 0; i < result.length; i++) {
  33.                 if (result[i].indexOf("-") != -1) {
  34.                     result[i] = result[i]
  35.                 }
  36.             }
  37.             this.fire('GetWeek', { weeks: result.join(',') });//格式为1-9,11,13,15-20
  38.         }
复制代码



上课时间组件<class-time></class-time> 里面包含星期、上课节次数(注意上课节次数必须是连续的否则需要单独添加另一个上课时间),主要难点在于判断上课节次数是否连续。
页面初始数据,默认最大上课节次13节。
  1. weekdays: [
  2.                 { name: '星期一', on: false },
  3.                 { name: '星期二', on: false },
  4.                 { name: '星期三', on: false },
  5.                 { name: '星期四', on: false },
  6.                 { name: '星期五', on: false },
  7.                 { name: '星期六', on: false },
  8.                 { name: '星期日', on: false }
  9.             ],
  10.             times: base.class_time(),
  11.             num_arr: [],
  12.             mask: false,
  13.             jie: '',
  14.             weekday: 0

  15.     class_time() {
  16.         let data = [
  17.             { 'jie': '1节', 'time': '08:30-09:15' },
  18.             { 'jie': '2节', 'time': '09:25-10:10' },
  19.             { 'jie': '3节', 'time': '10:25-11:10' },
  20.             { 'jie': '4节', 'time': '11:20-12:05' },
  21.             { 'jie': '5节', 'time': '14:00-14:45' },
  22.             { 'jie': '6节', 'time': '14:55-15:40' },
  23.             { 'jie': '7节', 'time': '15:55-16:40' },
  24.             { 'jie': '8节', 'time': '16:50-17:35' },
  25.             { 'jie': '9节', 'time': '17:45-18:30' },
  26.             { 'jie': '10节', 'time': '18:30-19:00' },
  27.             { 'jie': '11节', 'time': '19:00-19:45' },
  28.             { 'jie': '12节', 'time': '19:50-20:35' },
  29.             { 'jie': '13节', 'time': '20:45-21:30' }
  30.         ]
  31.         return data;
  32.     }
复制代码


选择上课节次数(如5-9 这里需要判断单击后选中的数据是否为连续的数字)函数set_time(index)源代码如下
  1. set_time(index) {
  2.             let jie = (index + 1);
  3.             //判断是否已添加
  4.             if (this.isInArray(this.num_arr, jie)) {
  5.                 this.delArrItem(this.num_arr, jie);
  6.                 this.num_arr.sort(function (x, y) {
  7.                     return x - y;
  8.                 });
  9.                 //console.log('删除' + jie)
  10.                 if (this.isContinuityNum(this.num_arr)) {
  11.                     this.times[index].td1 = false
  12.                 } else {
  13.                     //console.log('删除后不连续')
  14.                     this.times[index].td1 = true
  15.                     this.num_arr.push(jie);
  16.                     this.num_arr.sort(function (x, y) {
  17.                         return x - y;
  18.                     });
  19.                     api.toast({
  20.                         msg: '上课时间必须连续'
  21.                     });
  22.                 }
  23.             } else {
  24.                 this.num_arr.push(jie);
  25.                 this.num_arr.sort(function (x, y) {
  26.                     return x - y;
  27.                 });
  28.                 if (this.isContinuityNum(this.num_arr)) {
  29.                     this.times[index].td1 = true
  30.                 } else {
  31.                     //console.log('增加后不连续')
  32.                     this.delArrItem(this.num_arr, jie);
  33.                     this.num_arr.sort(function (x, y) {
  34.                         return x - y;
  35.                     });
  36.                     this.times[index].td1 = false
  37.                     api.toast({
  38.                         msg: '上课时间必须连续'
  39.                     });
  40.                 }
  41.             }
  42.    this.jie =this.num_arr[0]+ '-'+this.num_arr[(this.num_arr.length -1)];//格式1-2
  43. }

  44.         //删除数组元素
  45.         delArrItem(arr, item) {
  46.             for (var i = 0; i < arr.length; i++) {
  47.                 if (arr[i] === item) {
  48.                     if (arr[i + 1] === item) {
  49.                         arr.splice(i, 1);
  50.                         i--;
  51.                         continue;
  52.                     }
  53.                     arr.splice(i, 1);
  54.                 }
  55.             }
  56.             return arr;
  57.         },
  58.         //判断是否是连续的数字
  59.         isContinuityNum(array) {
  60.             if (!array) {
  61.                 //数组为null
  62.                 return false;
  63.             }
  64.             if (array.length == 0) {
  65.                 //数组为[]
  66.                 return true;
  67.             }
  68.             var len = array.length;
  69.             var n0 = array[0];
  70.             var sortDirection = 1;//默认升序
  71.             if (array[0] > array[len - 1]) {
  72.                 //降序
  73.                 sortDirection = -1;
  74.             }
  75.             if ((n0 * 1 + (len - 1) * sortDirection) !== array[len - 1]) {
  76.                 //筛除['3',4,5,6,7,8]
  77.                 return false;
  78.             }
  79.             var isContinuation = true;
  80.             for (var i = 0; i < len; i++) {
  81.                 if (array[i] !== (i + n0 * sortDirection)) {
  82.                     isContinuation = false;
  83.                     break;
  84.                 }
  85.             }
  86.             return isContinuation;
  87.         },

  88.         //判断元素是否在数组里面
  89.         isInArray(arr, value) {
  90.             for (var i = 0; i < arr.length; i++) {
  91.                 if (value == arr[i]) {
  92.                     return true;
  93.                 }
  94.             }
  95.             return false;
  96.         }
复制代码



最终前端需要提交给后端的数据格式如下:
  1. yearId: '200',                            //学年id,这里是指当前学期的课程
  2. name: '大学计算机',                 //课程名称
  3. teacher: '李国海',                    //任课教师
  4. bg: '1',                                   //课程颜色,系统提供7种颜色
  5. class_time: [
  6.                 { weeks: '1-20', room: '一教A307', weekday: '1', jie: '1-2' },
  7.                 { weeks: '1-20', room: '机房C405', weekday: '3', jie: '3-4' }
  8.   ]
复制代码




本文暂无评论,快来抢沙发!