def show_student_profile(username): '''查看学生的个人信息 :参数 username:学生的用户名''' student = User.query.filter_by(username=username).first() if student: tab = request.args.get('tab','',type=str) if tab == 'lessons': lessons = student.lessons.filter_by(is_delete=False).order_by(Lesson.time.desc()).all() for lesson in lessons: lesson.teacher = User.query.get(lesson.teacher_id) lesson.localtime = get_localtime(lesson.time,current_user) # 开课十分钟前,课程是可以取消的 if lesson.time>datetime.utcnow()+timedelta(0,600): lesson.cancel = True else: lesson.cancel = False return render_template('administrator/student_profile.html',student=student,tab=tab,lessons=lessons,username=username) elif tab == 'profile': teacher_id = student.student_profile.first().teacher_id if teacher_id: student.teacher = User.query.get(teacher_id) else: student.teacher = None student.localsince = get_localtime(student.member_since,current_user) student_country=student.timezone if len(student_country)>2: student.timezone_str = country_timezones[student_country[:2]][int(student_country[-1])] else: student.timezone_str = country_timezones[student_country][0] return render_template('administrator/student_profile.html',student=student,tab=tab,username=username)
def check_detail(lesson_id): lesson = Lesson.query.get_or_404(lesson_id) status_dict = {'Complete':'正常完成','Tea Absent':'教师缺勤','Stu Absent':'学生缺勤','Tea Late':'教师迟到'} #添加中文描述的课时完成状态 lesson.c_status = status_dict[lesson.status] #添加本节课的教师对象 teacher = User.query.get(lesson.teacher_id) lesson.teacher = teacher #添加用户以用户时区为标准的上课时间对象 lesson.localtime = get_localtime(lesson.time,current_user) record = lesson.lesson_record.first() return render_template('administrator/check_detail.html',lesson=lesson,record=record)
def personal_info(): '''协管员的个人信息,主要是为了修改自己的时区信息''' form = PersonalInfoForm() if form.validate_on_submit(): user = current_user._get_current_object() user.name = form.name.data user.location = form.location.data user.timezone = form.timezone.data db.session.add(user) flash('成功修改个人信息') return redirect(url_for('moderator.personal_info')) form.email.data = current_user.email form.username.data = current_user.username form.name.data = current_user.name form.location.data = current_user.location form.timezone.data = current_user.timezone local_member_since = get_localtime(current_user.member_since, current_user) form.member_since.data = local_member_since.strftime('%Y-%m-%d') return render_template('moderator/personal_info.html', form=form)
def modify_schedule(username, time_type): '''根据协管员提交的教师用户名和要修改的时间类型来处理 :参数 username:教师的用户名 :参数 time_type:要修改的时间类型 ''' teacher = User.query.filter_by(username=username, is_delete=False).first() if teacher: # 设置临时休息时间 if time_type == '1': form = RestTimeForm() if form.validate_on_submit(): available_start = datetime.utcnow() + timedelta(1) if form.end.data <= form.start.data or form.start.data < available_start: flash('起始时间或结束时间有误') return redirect( url_for('moderator.modify_schedule', username=username, time_type=time_type)) else: # 保存到数据库里,假设开始时间是9点,结束时间是11点 # 那就要保存9点和10点这两个时间点 time = form.start.data end = form.end.data while time < end: naive_utctime = get_utctime(time, current_user) sr = SpecialRest.query.filter_by( rest_time=naive_utctime, teacher_id=teacher.id, type=form.rest_type.data).first() if not sr: sr = SpecialRest() sr.rest_time = naive_utctime sr.teacher_id = teacher.id sr.type = form.rest_type.data sr.expire = False db.session.add(sr) time = time + timedelta(seconds=3600) flash('休息时间设置成功') return redirect( url_for('moderator.modify_schedule', username=username, time_type='4')) form.teacher.data = teacher.name return render_template('moderator/modify_schedule.html', form=form, username=username, time_type=time_type) # 设置临时的补班时间 elif time_type == '2': form = MakeupTimeForm() if form.validate_on_submit(): available_start = datetime.utcnow() + timedelta(1) if form.end.data <= form.start.data or form.start.data < available_start: flash('起始时间或结束时间有误') return redirect( url_for('moderator.modify_schedule', username=username, time_type=time_type)) else: # 把数据保存到数据库里面 time = form.start.data end = form.end.data while time < end: naive_utctime = get_utctime(time, current_user) mt = MakeUpTime.query.filter_by( make_up_time=naive_utctime, teacher_id=teacher.id).first() if not mt: mt = MakeUpTime() mt.make_up_time = naive_utctime mt.teacher_id = teacher.id mt.expire = False db.session.add(mt) time = time + timedelta(seconds=3600) flash('补班时间设置成功') return redirect( url_for('moderator.modify_schedule', username=username, time_type='5')) form.teacher.data = teacher.name return render_template('moderator/modify_schedule.html', form=form, username=username, time_type=time_type) # 修改老师的常规工作时间 elif time_type == '3': # 查询这位老师的工作时间,它们是UTC时间,还要转化为协管员时区的时间 if teacher.word_time.first(): worktime = teacher.work_time.first().work_time worktime_list = worktime.split(';') else: worktime_list = [] # 让每个星期从星期天开始 cal = Calendar(6) # 随便获取一个完整的naive的星期的日期 week = cal.monthdatescalendar(2020, 2)[0] # 获取utc时区对象 utc = timezone('UTC') # 获取协管员时区对象 moderator_country = current_user.timezone if len(moderator_country) > 2: moderator_tz = country_timezones[moderator_country[:2]][int( moderator_country[-1])] else: moderator_tz = country_timezones[moderator_country][0] tz_obj = timezone(moderator_tz) # 用来存放按照这个星期来看,用户视角的上课时间(年月日小时) temp = [] for w in worktime_list: date = week[int(w[0])] time = datetime(date.year, date.month, date.day, int(w[2:]), tzinfo=utc) time = time.astimezone(tz_obj) temp.append(time) # datetime里的6代表星期天,也就是我定义的0,这里用一个字典来保存这种映射关系 weekday_map = {6: 0, 0: 1, 1: 2, 2: 3, 3: 4, 4: 5, 5: 6} # 清空worktime_list列表,用于存储用户视角的常规工作时间 worktime_list = [] for time in temp: # 依然要把每个工作时间点变成0-1的形式,存进列表 worktime_list.append( str(weekday_map[time.weekday()]) + '-' + str(time.hour)) return render_template('moderator/modify_schedule.html', username=username, time_type=time_type, teacher=teacher, worktime_list=worktime_list) # 取消休息 elif time_type == '4': special_rest_list = teacher.special_rest.filter_by( expire=False).order_by(SpecialRest.rest_time.asc()).all() for sr in special_rest_list: sr.localtime = get_localtime(sr.rest_time, current_user) return render_template('moderator/modify_schedule.html', username=username, time_type=time_type, special_rest_list=special_rest_list, teacher=teacher) # 取消补班 elif time_type == '5': makeup_time_list = teacher.make_up_time.filter_by( expire=False).order_by(MakeUpTime.make_up_time.asc()).all() for mt in makeup_time_list: mt.localtime = get_localtime(mt.make_up_time, current_user) return render_template('moderator/modify_schedule.html', username=username, time_type=time_type, makeup_time_list=makeup_time_list, teacher=teacher) else: flash('修改时间类型有误') return redirect(url_for('main.personal_center')) flash('教师不存在') return redirect(url_for('main.personal_center'))
def book_lesson(student_username, teacher_username): teacher = User.query.filter_by(username=teacher_username, role_id=3, is_delete=False).first() student = User.query.filter(User.username == student_username, User.is_delete == False).first() if teacher and (student.role_id == 1 or student.role_id == 2): #取出老师的工作时间字符串并转化为列表 worktime = teacher.work_time.first().work_time worktime_list = worktime.split(';') #把以星期为单位的教师工作时间转化为UTC年月日小时的时间 #第一步:构造出UTC的此时此刻 cal = Calendar(6) # 让每个星期都从星期天开始 utc = timezone('UTC') utcnow = datetime.utcnow() utcnow = datetime(utcnow.year, utcnow.month, utcnow.day, utcnow.hour, tzinfo=utc) # 第二步:计算出可以选课的起始时间,也就是此时此刻的24小时后,以及截至时间,也就是现在开始的29天后 available_start = utcnow + timedelta(1) available_end = utcnow + timedelta(29) # 第三步:找到起始日期和结束日期所在的星期,拼接出可以选课的28天的列表, # 大列表里的小列表代表一个个以周日开始的星期 start_flag = False all_available_dates = [] for week in cal.monthdatescalendar(available_start.year, available_start.month): # 在没找到起始日期所在的星期的时候,要检查这个星期是否就是我们寻找的 if not start_flag and available_start.date() in week: start_flag = True # 从找到了起始日期所在的星期开始,我们要把它所在的以及它后面的星期加到列表里 if start_flag: all_available_dates.append(week) # 遍历结束日期所在的月,如果当前星期不在列表里,就添加(因为前后两个月可能有重复的星期) # 遇到结束日期所在的星期,后面的就不用看了 for week in cal.monthdatescalendar(available_end.year, available_end.month): if available_end not in week: all_available_dates.append(week) if available_end.date() in week: break # 第四步:根据老师的工作时间,构造出以datetime对象为元素的列表 # 创建一个空列表,存放老师的以小时为单位的工作时间 new_worktime_list = [] for week in all_available_dates: # w是类似于0-1这样的字符串,它表示星期天的UTC时间1点钟 for w in worktime_list: date = week[int(w[0])] time = datetime(date.year, date.month, date.day, int(w[2:]), tzinfo=utc) if time < available_start or time > available_end: continue new_worktime_list.append(time) # 第五步:把教师的特殊休息时间去掉 special_rest_set = set() temp = teacher.special_rest.filter_by(expire=False).all() for data in temp: rest_time = datetime(data.rest_time.year, data.rest_time.month, data.rest_time.day, data.rest_time.hour, tzinfo=utc) if rest_time >= available_start: special_rest_set.add(rest_time) else: data.expire = True db.session.add(data) for i in new_worktime_list[:]: if i in special_rest_set: new_worktime_list.remove(i) # 第六步:把教师的补班时间加进去(这一步要放在前面,因为可能补班的时间也被选上课了) makeup_time_list = [] temp = teacher.make_up_time.filter_by(expire=False).all() for data in temp: makeup_time = datetime(data.make_up_time.year, data.make_up_time.month, data.make_up_time.day, data.make_up_time.hour, tzinfo=utc) if makeup_time >= available_start: makeup_time_list.append(makeup_time) # 把已经过期的补班时间的expire字段修改为True else: data.expire = True db.session.add(data) new_worktime_list += makeup_time_list # 第七步:生成一个已预约的课程时间列表,并把这些时间从老师的工作时间里去掉 # 为了节约资源,我们在查询的时候就筛选一下时间 lessons = Lesson.query.filter( Lesson.teacher_id == teacher.id, Lesson.is_delete == False, Lesson.time >= datetime.utcnow() + timedelta(1)).all() # 先用set存放时间,因为查询比较快 lessons_set = set() for lesson in lessons: time = lesson.time time = datetime(time.year, time.month, time.day, time.hour, tzinfo=utc) lessons_set.add(time) for i in new_worktime_list[:]: if i in lessons_set: new_worktime_list.remove(i) lessons_list = list(lessons_set) #计算出协管员的时区 visitor_country = current_user.timezone if len(visitor_country) > 2: visitor_tz = country_timezones[visitor_country[:2]][int( visitor_country[-1])] else: visitor_tz = country_timezones[visitor_country][0] tz_obj = timezone(visitor_tz) # 根据时区,生成协管员视角的可以选课的28天的日历 visitor_start = get_localtime(available_start, current_user) visitor_end = get_localtime(available_end, current_user) visitor_dates = [] start_flag = False for week in cal.monthdatescalendar(visitor_start.year, visitor_start.month): # 因为遍历一个星期也会浪费时间,所以我们这里设两个条件 # 如果flag已经是True了,就不需要再看结束日期在不在这个星期里了 if not start_flag and visitor_start.date() in week: start_flag = True if start_flag: visitor_dates.append(week) # 因为前后两个月可能有重复的星期,所以要判断是否在列表里,不在的才添加 for week in cal.monthdatescalendar(visitor_end.year, visitor_end.month): if week not in visitor_dates: visitor_dates.append(week) # 如果已经到了结束日期所在的星期,就不用看后面的了 if visitor_end.date() in week: break # 获取页码 page = request.args.get('page', 1, type=int) # 如果有用户恶意修改页码,我们要把页码变成1 if page > len(visitor_dates) or page < 1: page = 1 # 每个星期的月份和年,应该以这个星期中间的那一天为标准 current_page = Pagination(visitor_dates, page, 1, len(visitor_dates), visitor_dates[page - 1]) middle_day = current_page.items[3] month_name = calendar.month_name[middle_day.month] year = middle_day.year this_week = [] only_dates = [] for date in current_page.items: this_week.append('%s-%s-%s' % (date.year, date.month, date.day)) only_dates.append(date.day) #把老师的可选的时间列表换成协管员时区的时间(字符串) for i, time in enumerate(new_worktime_list): time = time.astimezone(tz_obj) new_worktime_list[i] = '%s-%s-%s-%s' % (time.year, time.month, time.day, time.hour) #把老师有课的时间转换成协管员时区的时间(字符串) for i, time in enumerate(lessons_list): time = time.astimezone(tz_obj) lessons_list[i] = '%s-%s-%s-%s' % (time.year, time.month, time.day, time.hour) # 处理ajax请求 time = request.form.get('time', '', type=str) if time: time = time.split('-') #先构造一个没有时区的datetime对象 time = datetime(int(time[0]), int(time[1]), int(time[2]), int(time[3])) #再把它变成时区为协管员所在地区的datetime对象 time = tz_obj.localize(time) #再把时区变成utc时区 time = time.astimezone(utc) # 再判断一次是否在可选时间范围内 if time >= available_start: # 如果该用户是学生,需要操作课时包里的剩余课时 if student.role_id == 2: active_package = student.orders.filter( Order.pay_status == 'paid', Order.left_amount > 0).order_by( Order.pay_time.asc()).first() if active_package: # 课时包的课程数量扣掉一节 active_package.left_amount -= 1 db.session.add(active_package) # 把选课信息存进数据库 lesson = student.lessons.filter( Lesson.time == time, Lesson.teacher_id == teacher.id).first() if lesson: lesson.is_delete = False else: lesson = Lesson() lesson.student_id = student.id lesson.teacher_id = teacher.id lesson.time = time lesson.message = '' lesson.lesson_type = active_package.lesson_type db.session.add(lesson) msg = "您已经成功地为学生%s选了一节%s老师的%s课" % ( student.username, teacher.name, active_package.lesson_type) return jsonify({'status': 'ok', 'msg': msg}) else: return jsonify({ 'status': 'ok', 'msg': '该生已经没有剩余课时,请联系该生购买课时包' }) # 如果该用户是游客,需要查看是否已经上过试听课 elif student.role_id == 1: #如果该游客已经有一节试听课记录了,并且那节试听课是完成或者还未开始的状态,不允许他再次选择试听课 trial = Lesson.query.filter_by( student_id=student.id, lesson_type='Trial').order_by( Lesson.time.desc()).first() if trial and (trial.status == 'Complete' or trial.status == 'Not started'): return jsonify({ 'status': 'fail', 'msg': "该生已经正常完成一节试听课,或正在等待一节试听课开始,不能再选" }) else: # 先看看学生之前是否已经选过同一时间同一老师的试听课了 lesson = student.lessons.filter( Lesson.time == time, Lesson.teacher_id == teacher.id).first() if lesson: lesson.is_delete = False else: lesson = Lesson() lesson.student_id = student.id lesson.teacher_id = teacher.id lesson.time = time lesson.message = '' lesson.lesson_type = 'Trial' db.session.add(lesson) msg = "您已经成功为学生%s选了一节%s老师的试听课" % (student.username, teacher.username) return jsonify({'status': 'ok', 'msg': msg}) else: return jsonify({'status': 'fail', 'msg': '您需要至少提前24小时选课'}) return render_template('moderator/book_lesson.html', student=student, teacher=teacher, this_week=this_week, only_dates=only_dates, new_worktime_list=new_worktime_list, month_name=month_name, year=year, current_page=current_page, lessons_list=lessons_list) else: flash('学生或老师有误') return redirect(url_for('moderator.pre_book_lesson'))
def my_students(): '''这是我的所有学生的视图''' username = request.args.get('username','',type=str) student = [] lessons = [] primary_teacher = [] tab = request.args.get('tab','',type=str) #如果有用户名,就要查看某个学生的信息,否则就查看该教师的所有学生 if username: student = User.query.filter_by(username=username).first() tz = current_user.timezone if len(tz) == 2: tz_str = country_timezones[tz][0] else: tz_str = country_timezones[tz[:2]][int(tz[3:])] tz = timezone(tz_str) utc = timezone('UTC') #查看该学生的所有课程 if tab == 'lessons': lessons = student.lessons.filter_by(is_delete=False).order_by(Lesson.time.desc()).all() #给每节课添加教师信息,以及根据教师时区转化出的教师当地的上课时间 for lesson in lessons: teacher = User.query.get(lesson.teacher_id) lesson.teacher = teacher utctime = datetime(lesson.time.year,lesson.time.month,lesson.time.day,lesson.time.hour,tzinfo=utc) localtime = utctime.astimezone(tz) lesson.localtime = localtime #查看该学生的个人信息 elif tab == 'profile': member_since = student.member_since utcsince = datetime(member_since.year,member_since.month,member_since.day,member_since.hour,tzinfo=utc) localsince = utcsince.astimezone(tz) student.localsince = localsince student.timezone_str = tz_str teacher_id = student.student_profile.first().teacher_id primary_teacher = User.query.get(teacher_id) return render_template('teacher/my_students.html',username=username,student=student,tab=tab,lessons=lessons,primary_teacher=primary_teacher) #如果没有用户名,那就查询我的所有学生 student_profiles = StudentProfile.query.filter_by(teacher_id=current_user.id).all() students=[] for profile in student_profiles: # 通过学生简历找到学生用户 student = profile.student # 先把全部已支付的课时包的query对象查出来,一会儿要多次使用 all_packages = student.orders.filter(Order.pay_status=='paid') # 查询该学生的课时类型 active_packages = all_packages.filter(Order.left_amount>0).order_by(Order.id.asc()).all() # 如果有活跃课时包(里面还有剩余课时的课时包),那学生的课时类型就是最老的课时包的类型 if active_packages: lesson_type = active_packages[0].lesson_type # 如果没有活跃课时包,那学生的课时类型就是最新的已完成的课时包的类型 else: lesson_type = all_packages.order_by(Order.id.desc()).first().lesson_type student.lesson_type = lesson_type # 查询该学生的全部课时数和全部剩余课时数 all_packages = all_packages.all() total_lessons = 0 total_left = 0 for package in all_packages: total_lessons += package.lesson_amount total_left += package.left_amount student.total_left = total_left student.total_finished = total_lessons-total_left if student.last_seen: local_last_seen = get_localtime(student.last_seen,current_user) else: local_last_seen = None student.local_last_seen = local_last_seen students.append(student) return render_template('teacher/my_students.html',students=students)
def record_lesson(id): '''这是填写课程详情的视图''' lesson = Lesson.query.get_or_404(id) lesson.localtime = get_localtime(lesson.time,current_user) form = RecordLessonForm() # 可能是修改,也可能是新建 record = lesson.lesson_record.first() or LessonRecord() if not record.lesson_id: record.lesson_id = lesson.id if form.validate_on_submit(): record.talk = form.talk.data record.this_lesson = form.this_lesson.data record.next_lesson = form.next_lesson.data record.homework = form.homework.data record.textbook = form.textbook.data record.other = form.other.data # 选课的时候已经扣了课时,而一般情况下,课程就是正常完成了,不需要做什么 # 如果课程状态由Complete,Tea Late,Stu Absent,None变成了Tea Absent,那就要把课时加回来 if lesson.status in {'Complete','Tea Late','Stu Absent',None} and form.status.data == 'Tea Absent': # 我们要从最新的课时包开始,找到第一个不满(也就是left_amount<lesson_amount的课时包),把还给学生的课加到这个包里 all_packages = lesson.student.orders.filter(Order.pay_status=='paid').order_by(Order.id.desc()).all() for package in all_packages: if package.left_amount <package.lesson_amount: package.left_amount += 1 break db.session.add(package) # 如果课程状态由Tea Absent又变成了Complete,Tea Late,Stu Absent,就说明老师一开始填错了,再把课时扣掉 elif lesson.status == 'Tea Absent' and form.status.data in {'Complete','Tea Late','Stu Absent'}: current_package = lesson.student.orders.filter(Order.pay_status=='paid',Order.left_amount>0).order_by(Order.id.asc()).first() current_package.left_amount -= 1 db.session.add(current_package) # 如果这节课的状态由None,Tea Absent或Stu Absent变成了Complete,Tea Late,更新最后一次见到学生的时间 if lesson.status in {None,'Tea Absent','Stu Absent'} and form.status.data in {'Complete','Tea Late'}: if lesson.student.last_seen is None or lesson.time > lesson.student.last_seen: lesson.student.last_seen = lesson.time db.session.add(lesson.student) # 如果这节课的状态由Complete,Tea Late变成了Tea Absent,Stu Absent,这可能会使得最后一次见学生的时间往前推 elif lesson.status in {'Complete','Tea Late'} and form.status.data in {'Tea Absent','Stu Absent'}: # 只有这节课的时间正好就是最后一次见学生的时间时,才需要修改,否则这是一节老课,不影响最后见学生的时间 if lesson.time == lesson.student.last_seen: # 查询出这个学生的所有课时,降序排列 all_lessons = lesson.student.lessons.filter(Lesson.is_delete==False).order_by(Lesson.id.desc()).all() for lesson_ in all_lessons: # 找到离现在最近的见到学生的课时,把这个时间更新为最后见到学生的时间(注意要刨除当前这节课,所以要找的替代者的时间必须早于当前这节课) if lesson_.status in {'Complete','Tea Late'} and lesson_.time<lesson.time: lesson.student.last_seen = lesson_.time break # 如果找不到这样的课时,那就说明其实学生一节课也没上,把最后见到学生的时间改为None else: lesson.student.last_seen = None db.session.add(lesson.student) lesson.status = form.status.data lesson.t_comment = form.t_comment.data db.session.add(record) db.session.add(lesson) return redirect(url_for('main.personal_center')) form.talk.data = record.talk form.this_lesson.data = record.this_lesson form.next_lesson.data = record.next_lesson form.homework.data = record.homework form.textbook.data = record.textbook form.other.data = record.other form.status.data = lesson.status form.t_comment.data = lesson.t_comment return render_template('teacher/record_lesson.html',form=form,lesson=lesson)
def personal_center(): '''这是个人中心的视图,不同角色会显示不同的页面''' if current_user.role.name == 'Visitor': #查询该游客是否定过试听课 trial_lessons = Lesson.query.filter_by(student_id=current_user.id, lesson_type='Trial').all() #如果定过试听课 if trial_lessons: #获取游客的时区信息 if len(current_user.timezone) == 2: tz = country_timezones[current_user.timezone][0] tz = timezone(tz) else: tz = country_timezones[current_user.timezone[:2]][int( current_user.timezone[3:])] tz = timezone(tz) utc = timezone('UTC') #把试听课的时间转化为游客当地的时间,同时也查询出老师的对象,然后把时间和教师信息都附加到每节试听课对象上 for lesson in trial_lessons: utctime = datetime(lesson.time.year, lesson.time.month, lesson.time.day, lesson.time.hour, tzinfo=utc) localtime = utctime.astimezone(tz) localtime = '%s-%s-%s %s:00' % (localtime.year, localtime.month, localtime.day, localtime.hour) lesson.localtime = localtime teacher = User.query.get(lesson.teacher_id) lesson.teacher = teacher return render_template('visitor/homepage.html', trial_lessons=trial_lessons) elif current_user.role.name == 'Student': #查询出学生所有的课程 lessons = current_user.lessons.filter_by(is_delete=False).order_by( Lesson.time.desc()).all() utc = timezone('UTC') tz = current_user.timezone if len(tz) == 2: tz = country_timezones[tz] else: tz = country_timezones[tz[:2]][int(tz[3:])] tz = timezone(tz) for lesson in lessons: lesson.teacher = User.query.get(lesson.teacher_id) time = lesson.time utctime = datetime(time.year, time.month, time.day, time.hour, tzinfo=utc) localtime = utctime.astimezone(tz) lesson.localtime = localtime if lesson.status == 'Not started': #课程开始时间距离现在还大于10分钟 if lesson.time > datetime.utcnow() + timedelta(0, 600): lesson.cancel = True else: lesson.cancel = False return render_template('student/homepage.html', lessons=lessons) elif current_user.role.name == 'Teacher': #查询出24小时内老师的未开始课程 lessons = Lesson.query.filter_by(teacher_id=current_user.id, status='Not started', is_delete=False).order_by( Lesson.time.desc()).all() lesson_list = [] if lessons: utcnow = datetime.utcnow() utc = timezone('UTC') #获取老师的时区信息(是国家代码和数字的组合,比如CN-0) tz = current_user.timezone if len(tz) == 2: #获取具体的时区代码,比如Asia/Shanghai tz = country_timezones[tz][0] else: tz = country_timezones[tz[:2]][int(tz[3:])] #获取时区对象 tz = timezone(tz) for lesson in lessons: #如果课程的时间距离现在已经大于24小时了,就跳出循环 if lesson.time > utcnow + timedelta(1): break #在24小时内的课都添加到列表里 utctime = datetime(lesson.time.year, lesson.time.month, lesson.time.day, lesson.time.hour, tzinfo=utc) localtime = utctime.astimezone(tz) lesson.localtime = localtime lesson_list.append(lesson) return render_template('teacher/homepage.html', lesson_list=lesson_list) elif current_user.role.name == 'Moderator': # 查找最近24小时内入学的新生 utcnow = datetime.utcnow() start_time = utcnow - timedelta(1) new_orders = Order.query.filter(Order.pay_status == 'paid', Order.pay_time >= start_time).order_by( Order.pay_time.desc()).all() students = { order.student for order in new_orders if order.student.orders.filter_by(pay_status='paid').order_by( Order.pay_time.asc()).first().pay_time >= start_time } students = list(students) for student in students: teacher_id = student.student_profile.first().teacher_id if teacher_id: student.teacher = User.query.get(teacher_id) else: student.teacher = None student.enrollment_time = get_localtime( student.orders.filter_by(pay_status='paid').order_by( Order.pay_time.asc()).first().pay_time, current_user) return render_template('moderator/homepage.html', students=students) elif current_user.role.name == 'Administrator': # 查找最近24小时内入学的新生 utcnow = datetime.utcnow() start_time = utcnow - timedelta(1) new_orders = Order.query.filter(Order.pay_status == 'paid', Order.pay_time >= start_time).order_by( Order.pay_time.desc()).all() students = { order.student for order in new_orders if order.student.orders.filter_by(pay_status='paid').order_by( Order.pay_time.asc()).first().pay_time >= start_time } students = list(students) for student in students: teacher_id = student.student_profile.first().teacher_id if teacher_id: student.teacher = User.query.get(teacher_id) else: student.teacher = None student.enrollment_time = get_localtime( student.orders.filter_by(pay_status='paid').order_by( Order.pay_time.asc()).first().pay_time, current_user) return render_template('administrator/homepage.html', students=students)
def book_lesson(): '''这是学生订课的视图''' # 找到该学生的老师 teacher = User.query.filter_by( id=current_user.student_profile.first().teacher_id).first() # 学生可能还没有分配老师,我们只操作分配了老师的情况 if teacher: #取出老师的工作时间字符串并转化为列表 worktime = teacher.work_time.first().work_time worktime_list = worktime.split(';') #把以星期为单位的教师工作时间转化为UTC年月日小时的时间 #第一步:构造出UTC的此时此刻 cal = Calendar(6) # 让每个星期都从星期天开始 utc = timezone('UTC') utcnow = datetime.utcnow() utcnow = datetime(utcnow.year, utcnow.month, utcnow.day, utcnow.hour, tzinfo=utc) # 第二步:计算出可以选课的起始时间,也就是此时此刻的24小时后,以及截至时间,也就是现在开始的29天后 available_start = utcnow + timedelta(1) available_end = utcnow + timedelta(29) # 第三步:找到起始日期和结束日期所在的星期,拼接出可以选课的28天的列表, # 大列表里的小列表代表一个个以周日开始的星期 start_flag = False all_available_dates = [] for week in cal.monthdatescalendar(available_start.year, available_start.month): # 在没找到起始日期所在的星期的时候,要检查这个星期是否就是我们寻找的 if not start_flag and available_start.date() in week: start_flag = True # 从找到了起始日期所在的星期开始,我们要把它所在的以及它后面的星期加到列表里 if start_flag: all_available_dates.append(week) # 遍历结束日期所在的月,如果当前星期不在列表里,就添加(因为前后两个月可能有重复的星期) # 遇到结束日期所在的星期,后面的就不用看了 for week in cal.monthdatescalendar(available_end.year, available_end.month): if available_end not in week: all_available_dates.append(week) if available_end.date() in week: break # 第四步:根据老师的工作时间,构造出以datetime对象为元素的列表 # 创建一个空列表,存放老师的以小时为单位的工作时间 new_worktime_list = [] for week in all_available_dates: # w是类似于0-1这样的字符串,它表示星期天的UTC时间1点钟 for w in worktime_list: date = week[int(w[0])] time = datetime(date.year, date.month, date.day, int(w[2:]), tzinfo=utc) if time < available_start or time > available_end: continue new_worktime_list.append(time) # 第五步:把教师的特殊休息时间去掉 special_rest_set = set() temp = teacher.special_rest.filter_by(expire=False).all() for data in temp: rest_time = datetime(data.rest_time.year, data.rest_time.month, data.rest_time.day, data.rest_time.hour, tzinfo=utc) if rest_time >= available_start: special_rest_set.add(rest_time) else: data.expire = True db.session.add(data) for i in new_worktime_list[:]: if i in special_rest_set: new_worktime_list.remove(i) # 第六步:把教师的补班时间加进去(这一步要放在前面,因为可能补班的时间也被选上课了) makeup_time_list = [] # 先把当前显示没有过期的补班时间都查出来 temp = teacher.make_up_time.filter_by(expire=False).all() for data in temp: makeup_time = datetime(data.make_up_time.year, data.make_up_time.month, data.make_up_time.day, data.make_up_time.hour, tzinfo=utc) if makeup_time >= available_start: makeup_time_list.append(makeup_time) # 如果补班时间在可选开始时间之前,说明事实上已经过期了 # 把expire改为True else: data.expire = True db.session.add(data) new_worktime_list += makeup_time_list # 第七步:生成一个已预约的课程时间列表,并把这些时间从老师的工作时间里去掉 # 为了节约资源,我们在查询的时候就筛选一下时间 lessons = Lesson.query.filter( Lesson.teacher_id == teacher.id, Lesson.is_delete == False, Lesson.time >= datetime.utcnow() + timedelta(1)).all() # 先用set存放时间,因为查询比较快 lessons_set = set() for lesson in lessons: time = lesson.time time = datetime(time.year, time.month, time.day, time.hour, tzinfo=utc) lessons_set.add(time) for i in new_worktime_list[:]: if i in lessons_set: new_worktime_list.remove(i) lessons_list = list(lessons_set) #计算出游客的时区 visitor_country = current_user.timezone if len(visitor_country) > 2: visitor_tz = country_timezones[visitor_country[:2]][int( visitor_country[-1])] else: visitor_tz = country_timezones[visitor_country][0] tz_obj = timezone(visitor_tz) # 根据时区,生成游客视角的可以选课的28天的日历 visitor_start = get_localtime(available_start, current_user) visitor_end = get_localtime(available_end, current_user) visitor_dates = [] start_flag = False for week in cal.monthdatescalendar(visitor_start.year, visitor_start.month): # 因为遍历一个星期也会浪费时间,所以我们这里设两个条件 # 如果flag已经是True了,就不需要再看结束日期在不在这个星期里了 if not start_flag and visitor_start.date() in week: start_flag = True if start_flag: visitor_dates.append(week) # 因为前后两个月可能有重复的星期,所以要判断是否在列表里,不在的才添加 for week in cal.monthdatescalendar(visitor_end.year, visitor_end.month): if week not in visitor_dates: visitor_dates.append(week) # 如果已经到了结束日期所在的星期,就不用看后面的了 if visitor_end.date() in week: break # 获取页码 page = request.args.get('page', 1, type=int) # 如果有用户恶意修改页码,我们要把页码变成1 if page > len(visitor_dates) or page < 1: page = 1 # 每个星期的月份和年,应该以这个星期中间的那一天为标准 current_page = Pagination(visitor_dates, page, 1, len(visitor_dates), visitor_dates[page - 1]) middle_day = current_page.items[3] month_name = calendar.month_name[middle_day.month] year = middle_day.year this_week = [] only_dates = [] for date in current_page.items: this_week.append('%s-%s-%s' % (date.year, date.month, date.day)) only_dates.append(date.day) #把老师的可选的时间列表换成游客时区的时间(字符串) for i, time in enumerate(new_worktime_list): time = time.astimezone(tz_obj) new_worktime_list[i] = '%s-%s-%s-%s' % (time.year, time.month, time.day, time.hour) #把老师有课的时间转换成游客时区的时间(字符串) for i, time in enumerate(lessons_list): time = time.astimezone(tz_obj) lessons_list[i] = '%s-%s-%s-%s' % (time.year, time.month, time.day, time.hour) # 查看并处理选课的ajax请求 time = request.form.get('time', '', type=str) if time: time = time.split('-') #先构造一个没有时区的datetime对象 time = datetime(int(time[0]), int(time[1]), int(time[2]), int(time[3])) #再把它变成时区为游客所在地区的datetime对象 time = tz_obj.localize(time) #再把时区变成utc时区 time = time.astimezone(utc) # 再判断一次是否在可选时间范围内 if time >= available_start: # 看看学生的课时包里是否还有课 active_package = current_user.orders.filter( Order.pay_status == 'paid', Order.left_amount > 0).order_by(Order.id.asc()).first() if active_package: # 课时包的课程数量扣掉一节 active_package.left_amount -= 1 db.session.add(active_package) # 把选课信息存进数据库 lesson = current_user.lessons.filter( Lesson.time == time, Lesson.teacher_id == teacher.id).first() if lesson: lesson.is_delete = False else: lesson = Lesson() lesson.student_id = current_user.id lesson.teacher_id = teacher.id lesson.time = time lesson.message = '' lesson.lesson_type = active_package.lesson_type db.session.add(lesson) return jsonify({ 'status': 'ok', 'msg': "You've successfully booked a lesson." }) else: return jsonify({ 'status': 'fail', 'msg': "You don't have any lessons now. Please buy another package." }) else: return jsonify({ 'status': 'fail', 'msg': 'You need to book lessons not earlier than 24 hours from now.' }) return render_template('student/book_lesson.html', teacher=teacher, this_week=this_week, only_dates=only_dates, new_worktime_list=new_worktime_list, month_name=month_name, year=year, current_page=current_page, lessons_list=lessons_list) return render_template('student/book_lesson.html', teacher=teacher)