使用APICloud AVM多端框架開發課程表功能

海的盡頭發表於2022-06-07

一、效果展示

二、功能實現的思路

本專案基於APICloud的AVM多端框架編寫,因此需要想辦法去構造特定資料、然後再改變資料,本專案核心業務就是課程資料的處理,難點就是課表的新增。

專案主要針對大學課表進行設計,課程很多地方存在不確定性,如課程周次數可能連續也可能不連續、上課時間可能1-2節也可能一整天、上課教室也可能不一樣,因此課程的資料結構如下圖。

後端需要提供當前周、當前周課程資料、新增課程等介面,當然課程資料查詢是比較複雜的,這裡就不講。前端主要是將課表資訊顯示在指定位置,資料比較簡單。

1、課程列表頁面

(1)當前周課程原始資料結構

這個資料需要再重組,因為需要將課程擺放到指定位置,必須知道距離頂部距離以及自身高度。可以通過上課時間jie這個引數獲取height,top。

 let data = [{
            'name': '大資料視覺化技術',
            'room': '機房C414',
            'weekday': '3',
            'bg': '2',
            'jie': '3-4',
            'top': '140px',
            'height': '140px'
 }]

橫向分為8份,每份寬度12.5%,高度70px,預設可以顯示13節課。課程背景預設有7種樣式,星期對應的是left引數也有7種樣式,上課節次對應top引數有12種樣式具體css如下:

.bg-1 { background: linear-gradient(#facea8, #fe8979)}
.bg-2 { background: linear-gradient(#dfc3fe, #90c5fb)}
.bg-3 { background: linear-gradient(#9deef5, #68e1b5)}
.bg-4 { background: linear-gradient(#eeba93, #dd65c7)}
.bg-5 { background: linear-gradient(#e6f6c9, #68e1b5)}
.bg-6 { background: linear-gradient(#dfc3fe, #dd65c7)}
.bg-7 { background: linear-gradient(#c8e65f, #7abafb)}

.week-1 {left: 12.5%;}
.week-2 {left: 25%;}
.week-3 {left: 37.5%;}
.week-4 {left: 50%;}
.week-5 {left: 62.5%;}
.week-6 {left: 75%;}
.week-0 {left: 87.5%;}

每一門課程都是用絕對定位,寬度相同,根據上課時間決定高度、位置程式碼表示如下

<view class="course_list">
        <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">
                <text class=" course-name">{{rs.name}}</text>
                <text class="course-room">{{rs.room}}</text>
        </view>
</view>

(2)當前周星期資料結構

獲取當前周的時間程式碼如下

this.setDate(new Date());
        setDate(date) {
            let arr = [];
            let week = date.getDay() - 1;
            date = this.addDate(date, week * -1);
            this.currentFirstDate = new Date(date);
            for (var i = 0; i < 7; i++) {
                arr[i] = this.formatDate(i == 0 ? date : this.addDate(date, 1))
            }
            this.week_data = arr
            this.currentWeek()
        },
        addDate(date, n) {
            date.setDate(date.getDate() + n);
            return date;
        },
        formatDate(date) {
            let year = date.getFullYear();
            let month = (date.getMonth() + 1);
            let day = date.getDate();
            let week = ['週日', '週一', '週二', '週三', '週四', '週五', '週六'][date.getDay()];
            this.currentMonth = month;
            if (month < 10) { month = '0' + month; }
            if (day < 10) { day = '0' + day; }
            return { "week": week, "date": month + '/' + day, "active": false };
        },
        //當前星期
        currentWeek() {
            let date = new Date();
            let weekday = date.getDay();
            if (weekday == 1) {
                this.week_data[0].active = true
            } else if (weekday == 2) {
                this.week_data[1].active = true
            } else if (weekday == 3) {
                this.week_data[2].active = true
            } else if (weekday == 4) {
                this.week_data[3].active = true
            } else if (weekday == 5) {
                this.week_data[4].active = true
            } else if (weekday == 6) {
                this.week_data[5].active = true
            } else if (weekday == 0) {
                this.week_data[6].active = true
            }
        }

上一週以及下一週相應程式碼

        last() {
            if (this.week > 1) {
                this.week = this.week - 1
                this.setDate(this.addDate(this.currentFirstDate, -7));
            }
        },
        next() {
            if (this.week < 20) {
                this.week = this.week + 1
                this.setDate(this.addDate(this.currentFirstDate, 7));
            }
        },

2、課程新增頁面

本專案主要針對大學課程進行設計,由於上課時間地點可能不規律,因此需要考慮周次、節次、星期、上課地點幾個因素。為了方便使用者快速新增課程,同一門課程可支援新增多個上課時間。頁面業務邏輯只有周次選擇、時間選擇兩個地方有點複雜因此將其拆分為兩個元件<class-week></class-week> <class-time></class-time>

課程的主要欄位如下

name: '大學計算機',       //課程名稱
room: '機房C411',        //上課教室
teacher: '李國海',       //任課教師
weekday: '0',            //星期
weeks: '1-9,11-20',      //上課週數
jie: '5-9',              //上課節次
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周全部選中。

(1)單週choose(1),雙週choose(2),全選choose(0)具體業務處理原始碼如下:

choose(n) {
            for (let i in this.weeks) {
                this.weeks[i].on = false
            }
            if (n == 1) {
                if (this.choose == 1) {
                    this.choose = 3
                } else {
                    this.choose = 1
                    for (let i = 0; i < this.weeks.length; i++) {
                        if (this.weeks[i].week % 2 != 0) {
                            this.weeks[i].on = true
                        }
                    }
                }

            } else if (n == 2) {
                if (this.choose == 2) {
                    this.choose = 3
                } else {
                    this.choose = 2
                    for (let i = 0; i < this.weeks.length; i++) {
                        if (this.weeks[i].week % 2 == 0) {
                            this.weeks[i].on = true
                        }
                    }
                }
            } else if (n == 0) {
                if (this.choose == 0) {
                    this.choose = 3
                } else {
                    this.choose = 0
                    for (let i in this.weeks) {
                        this.weeks[i].on = true
                    }
                }
            }
        }

(2)選擇某一週的函式set_week(i) 原始碼如下

set_week(i) {
            if (this.weeks[i].on == true) {
                this.weeks[i].on = false
            } else {
                this.weeks[i].on = true
            }
        }

(3)確定按鈕get_weeks()原始碼如下

get_weeks() {
            this.mask = false //影藏元件
            let arr = [];
            for (let i = 0; i < this.weeks.length; i++) {
                let on = this.weeks[i].on;
                if (on == true) {
                    arr.push(this.weeks[i].week);
                }
            }

            let result = [];
            let tmp;
            while (tmp = arr.shift()) {
                if (result.length == 0) {
                    result.push([tmp]);
                    continue;
                }
                let e = result[result.length - 1];
                if (tmp == e[e.length - 1] + 1) {
                    e.push(tmp);
                } else {
                    result.push([tmp]);
                }
            }

            for (let i = 0; i < result.length; i++) {
                let res = result[i];
                if (res.length > 1) {
                    result[i] = res[0] + '-' + res[res.length - 1];
                } else {
                    result[i] = res[0] + ''
                }
            }
            for (let i = 0; i < result.length; i++) {
                if (result[i].indexOf("-") != -1) {
                    result[i] = result[i]
                }
            }
            this.fire('GetWeek', { weeks: result.join(',') });//格式為1-9,11,13,15-20
        }

上課時間元件<class-time></class-time> 裡面包含星期、上課節次數(注意上課節次數必須是連續的否則需要單獨新增另一個上課時間),主要難點在於判斷上課節次數是否連續。
頁面初始資料,預設最大上課節次13節。

weekdays: [
                { name: '星期一', on: false },
                { name: '星期二', on: false },
                { name: '星期三', on: false },
                { name: '星期四', on: false },
                { name: '星期五', on: false },
                { name: '星期六', on: false },
                { name: '星期日', on: false }
            ],
            times: base.class_time(),
            num_arr: [],
            mask: false,
            jie: '',
            weekday: 0

    class_time() {
        let data = [
            { 'jie': '1節', 'time': '08:30-09:15' },
            { 'jie': '2節', 'time': '09:25-10:10' },
            { 'jie': '3節', 'time': '10:25-11:10' },
            { 'jie': '4節', 'time': '11:20-12:05' },
            { 'jie': '5節', 'time': '14:00-14:45' },
            { 'jie': '6節', 'time': '14:55-15:40' },
            { 'jie': '7節', 'time': '15:55-16:40' },
            { 'jie': '8節', 'time': '16:50-17:35' },
            { 'jie': '9節', 'time': '17:45-18:30' },
            { 'jie': '10節', 'time': '18:30-19:00' },
            { 'jie': '11節', 'time': '19:00-19:45' },
            { 'jie': '12節', 'time': '19:50-20:35' },
            { 'jie': '13節', 'time': '20:45-21:30' }
        ]
        return data;
    }

選擇上課節次數(如5-9 這裡需要判斷單擊後選中的資料是否為連續的數字)函式set_time(index)原始碼如下

set_time(index) {
            let jie = (index + 1);
            //判斷是否已新增
            if (this.isInArray(this.num_arr, jie)) {
                this.delArrItem(this.num_arr, jie);
                this.num_arr.sort(function (x, y) {
                    return x - y;
                });
                //console.log('刪除' + jie)
                if (this.isContinuityNum(this.num_arr)) {
                    this.times[index].td1 = false
                } else {
                    //console.log('刪除後不連續')
                    this.times[index].td1 = true
                    this.num_arr.push(jie);
                    this.num_arr.sort(function (x, y) {
                        return x - y;
                    });
                    api.toast({
                        msg: '上課時間必須連續'
                    });
                }
            } else {
                this.num_arr.push(jie);
                this.num_arr.sort(function (x, y) {
                    return x - y;
                });
                if (this.isContinuityNum(this.num_arr)) {
                    this.times[index].td1 = true
                } else {
                    //console.log('增加後不連續')
                    this.delArrItem(this.num_arr, jie);
                    this.num_arr.sort(function (x, y) {
                        return x - y;
                    });
                    this.times[index].td1 = false
                    api.toast({
                        msg: '上課時間必須連續'
                    });
                }
            }
   this.jie =this.num_arr[0]+ '-'+this.num_arr[(this.num_arr.length -1)];//格式1-2
}

        //刪除陣列元素
        delArrItem(arr, item) {
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] === item) {
                    if (arr[i + 1] === item) {
                        arr.splice(i, 1);
                        i--;
                        continue;
                    }
                    arr.splice(i, 1);
                }
            }
            return arr;
        },
        //判斷是否是連續的數字
        isContinuityNum(array) {
            if (!array) {
                //陣列為null
                return false;
            }
            if (array.length == 0) {
                //陣列為[]
                return true;
            }
            var len = array.length;
            var n0 = array[0];
            var sortDirection = 1;//預設升序
            if (array[0] > array[len - 1]) {
                //降序
                sortDirection = -1;
            }
            if ((n0 * 1 + (len - 1) * sortDirection) !== array[len - 1]) {
                //篩除['3',4,5,6,7,8]
                return false;
            }
            var isContinuation = true;
            for (var i = 0; i < len; i++) {
                if (array[i] !== (i + n0 * sortDirection)) {
                    isContinuation = false;
                    break;
                }
            }
            return isContinuation;
        },

        //判斷元素是否在陣列裡面
        isInArray(arr, value) {
            for (var i = 0; i < arr.length; i++) {
                if (value == arr[i]) {
                    return true;
                }
            }
            return false;
        }

最終前端需要提交給後端的資料格式如下:

yearId: '200',                       //學年id,這裡是指那一學期的課程
name: '大學計算機',                    //課程名稱
teacher: '李國海',                    //任課教師
bg: '1',                             //課程顏色,系統提供7種顏色
class_time: [
                { weeks: '1-20', room: '一教A307', weekday: '1', jie: '1-2' },
                { weeks: '1-20', room: '機房C405', weekday: '3', jie: '3-4' }
]

相關文章