mirror of
https://github.com/aaronleetw/Attendance.git
synced 2024-11-14 11:01:39 -08:00
Prototype Finish
This commit is contained in:
parent
a47d69a954
commit
6ee0ce15d5
14 changed files with 841 additions and 484 deletions
|
@ -1,35 +0,0 @@
|
|||
number,name,eng_name
|
||||
1,朱昱翧,Themis
|
||||
2,余欣璇,Zoe
|
||||
3,吳丞育,Audrey
|
||||
4,吳欣芃,Lisa
|
||||
5,吳苡瑄,Rachel
|
||||
6,王怡捷,Audrey
|
||||
7,林子琳,Emma
|
||||
8,林思佑,Una
|
||||
9,林珈年,Jessica
|
||||
10,姜心唯,Misha
|
||||
11,張庭暄,Chang
|
||||
12,許詠淳,Catherine
|
||||
13,陳宣彤,idk
|
||||
14,羅子珊,Shannon
|
||||
15,蘇宜柔,Chloe
|
||||
16,王邦熹,Wallace
|
||||
17,李秉謙,Alan
|
||||
18,劉青懷,idk
|
||||
19,林稟翔,Wilbert
|
||||
20,柯喬勳,Joshua
|
||||
21,馮顗中,idk
|
||||
22,張睿恩,Brian
|
||||
23,姜廉竣,idk
|
||||
24,陳允昊,Jeremy
|
||||
25,陳宣豪,Demetris
|
||||
26,陳宥嘉,Joseph
|
||||
27,陳麟泳,Aaron
|
||||
28,賀凱強,Jonathan
|
||||
29,楊上霆,Chase
|
||||
30,楊承武,Ben
|
||||
31,廖建瑋,Daniel
|
||||
32,潘逸,James
|
||||
33,朱禹安,Iforgot
|
||||
34,徐敏萱,idk
|
|
|
@ -1,35 +0,0 @@
|
|||
number,3-IG
|
||||
1,1103-01
|
||||
2,1103-01
|
||||
3,1103-02
|
||||
4,1103-01
|
||||
5,1103-01
|
||||
6,1103-02
|
||||
7,1103-01
|
||||
8,1103-01
|
||||
9,1103-01
|
||||
10,1103-01
|
||||
11,1103-01
|
||||
12,1103-01
|
||||
13,1103-02
|
||||
14,1103-01
|
||||
15,1103-02
|
||||
16,1103-01
|
||||
17,1103-02
|
||||
18,1103-02
|
||||
19,1103-01
|
||||
20,1103-02
|
||||
21,1103-01
|
||||
22,1103-02
|
||||
23,1103-01
|
||||
24,1103-02
|
||||
25,1103-02
|
||||
26,1103-02
|
||||
27,1103-01
|
||||
28,1103-02
|
||||
29,1103-01
|
||||
30,1103-01
|
||||
31,1103-01
|
||||
32,1103-01
|
||||
33,1103-02
|
||||
34,1103-01
|
|
|
@ -1,35 +0,0 @@
|
|||
number,name,eng_name,3-IG
|
||||
1,王子芯,Heidi,1103-01
|
||||
2,朱宸儀,Megan,1103-01
|
||||
3,牟奇薇,Summer,1103-02
|
||||
4,吳偲梵,Sophia,1103-01
|
||||
5,林書誼,Charlotte,1103-01
|
||||
6,林葦亭,Chelsea,1103-02
|
||||
7,凌孟妍,Iris,1103-01
|
||||
8,翁翊婷,Evelyn,1103-01
|
||||
9,郭倚熏,Patty,1103-01
|
||||
10,陳宣穎,Renee,1103-01
|
||||
11,曾若霏,Danielle,1103-01
|
||||
12,湯家綺,Joanna,1103-01
|
||||
13,黃以甯,Kate,1103-02
|
||||
14,黃玄,Cheryl,1103-01
|
||||
15,劉煒琪,Winona,1103-02
|
||||
16,潘俞希,Alina,1103-01
|
||||
17,鄭軒,Jasper,1103-02
|
||||
18,吳彥縢,Austin,1103-02
|
||||
19,吳昶佑,Eric,1103-01
|
||||
20,李翊愷,Aaron Lee,1103-02
|
||||
21,李翊誠,Alex,1103-01
|
||||
22,曹庭睿,Alvin,1103-02
|
||||
23,莊家睿,Gary,1103-01
|
||||
24,張馨予,Cindy,1103-02
|
||||
25,常有慈,Cindy,1103-02
|
||||
26,陳柏元,Michael,1103-02
|
||||
27,陳雋喆,Derek,1103-01
|
||||
28,曾柏皓,Cory,1103-02
|
||||
29,黃獻主,Arthur,1103-01
|
||||
30,盧秉漢,Hiro,1103-01
|
||||
31,李文,Tom,1103-01
|
||||
32,謝承霖,Walter,1103-01
|
||||
33,關義,Aaron Kuan,1103-02
|
||||
34,謝佾儒,Yi-Ju,1103-01
|
|
|
@ -1,35 +0,0 @@
|
|||
number,3-IG,2-TEST
|
||||
1,1103-01,1102-5
|
||||
2,1103-01,1102-5
|
||||
3,1103-02,1102-5
|
||||
4,1103-01,1102-5
|
||||
5,1103-01,1102-5
|
||||
6,1103-02,1102-5
|
||||
7,1103-01,1102-5
|
||||
8,1103-01,1102-5
|
||||
9,1103-01,1102-5
|
||||
10,1103-01,1102-5
|
||||
11,1103-01,1102-5
|
||||
12,1103-01,1102-5
|
||||
13,1103-02,1102-5
|
||||
14,1103-01,1102-5
|
||||
15,1103-02,1102-5
|
||||
16,1103-01,1102-5
|
||||
17,1103-02,1102-5
|
||||
18,1103-02,1102-5
|
||||
19,1103-01,1102-5
|
||||
20,1103-02,1102-5
|
||||
21,1103-01,1102-9
|
||||
22,1103-02,1102-9
|
||||
23,1103-01,1102-9
|
||||
24,1103-02,1102-9
|
||||
25,1103-02,1102-9
|
||||
26,1103-02,1102-9
|
||||
27,1103-01,1102-9
|
||||
28,1103-02,1102-9
|
||||
29,1103-01,1102-9
|
||||
30,1103-01,1102-9
|
||||
31,1103-01,1102-9
|
||||
32,1103-01,1102-9
|
||||
33,1103-02,1102-9
|
||||
34,1103-01,1102-9
|
|
|
@ -1,35 +0,0 @@
|
|||
number,name,eng_name
|
||||
1,王子芯,Heidi
|
||||
2,朱宸儀,Megan
|
||||
3,牟奇薇,Summer
|
||||
4,吳偲梵,Sophia
|
||||
5,林書誼,Charlotte
|
||||
6,林葦亭,Chelsea
|
||||
7,凌孟妍,Iris
|
||||
8,翁翊婷,Evelyn
|
||||
9,郭倚熏,Patty
|
||||
10,陳宣穎,Renee
|
||||
11,曾若霏,Danielle
|
||||
12,湯家綺,Joanna
|
||||
13,黃以甯,Kate
|
||||
14,黃玄,Cheryl
|
||||
15,劉煒琪,Winona
|
||||
16,潘俞希,Alina
|
||||
17,鄭軒,Jasper
|
||||
18,吳彥縢,Austin
|
||||
19,吳昶佑,Eric
|
||||
20,李翊愷,Aaron Lee
|
||||
21,李翊誠,Alex
|
||||
22,曹庭睿,Alvin
|
||||
23,莊家睿,Gary
|
||||
24,張馨予,Cindy
|
||||
25,常有慈,Cindy
|
||||
26,陳柏元,Michael
|
||||
27,陳雋喆,Derek
|
||||
28,曾柏皓,Cory
|
||||
29,黃獻主,Arthur
|
||||
30,盧秉漢,Hiro
|
||||
31,李文,Tom
|
||||
32,謝承霖,Walter
|
||||
33,關義,Aaron Kuan
|
||||
34,謝佾儒,Yi-Ju
|
|
|
@ -1,35 +0,0 @@
|
|||
number,3-IG
|
||||
1,1103-01
|
||||
2,1103-01
|
||||
3,1103-02
|
||||
4,1103-01
|
||||
5,1103-01
|
||||
6,1103-02
|
||||
7,1103-01
|
||||
8,1103-01
|
||||
9,1103-01
|
||||
10,1103-01
|
||||
11,1103-01
|
||||
12,1103-01
|
||||
13,1103-02
|
||||
14,1103-01
|
||||
15,1103-02
|
||||
16,1103-01
|
||||
17,1103-02
|
||||
18,1103-02
|
||||
19,1103-01
|
||||
20,1103-02
|
||||
21,1103-01
|
||||
22,1103-02
|
||||
23,1103-01
|
||||
24,1103-02
|
||||
25,1103-02
|
||||
26,1103-02
|
||||
27,1103-01
|
||||
28,1103-02
|
||||
29,1103-01
|
||||
30,1103-01
|
||||
31,1103-01
|
||||
32,1103-01
|
||||
33,1103-02
|
||||
34,1103-01
|
|
460
app.py
460
app.py
|
@ -1,12 +1,12 @@
|
|||
from flask import *
|
||||
import pyrebase
|
||||
from datetime import datetime
|
||||
import time
|
||||
import pytz
|
||||
from sendgrid import SendGridAPIClient
|
||||
from sendgrid.helpers.mail import Mail
|
||||
import csv
|
||||
import os
|
||||
import pandas as pd
|
||||
import base64
|
||||
from random import randint
|
||||
from dotenv import load_dotenv
|
||||
from pprint import pprint
|
||||
load_dotenv()
|
||||
|
@ -26,6 +26,7 @@ config = {
|
|||
firebase = pyrebase.initialize_app(config)
|
||||
db = firebase.database()
|
||||
auth = firebase.auth()
|
||||
storage = firebase.storage()
|
||||
tz = pytz.timezone('Asia/Taipei')
|
||||
|
||||
|
||||
|
@ -42,149 +43,138 @@ def manageProcess(fCommand, fData):
|
|||
# end bug fix
|
||||
pl = db.child("Users").child(
|
||||
session['uid']).child("permission").get().val()
|
||||
print(pl)
|
||||
print(db.child("Users").child(
|
||||
'DRZqqSSpg3OkPSCuWkv417dv0vh1').child("permission").get().val())
|
||||
print(fCommand, fData, session['uid'], pl)
|
||||
if pl == 'admin':
|
||||
return pl
|
||||
homerooms = db.child("Homerooms").get().val()
|
||||
currRoom = []
|
||||
if fCommand == "admin":
|
||||
currRoom = fData[0].split("^")
|
||||
else:
|
||||
for i in homerooms:
|
||||
currRoom.append(i)
|
||||
for j in homerooms[i]:
|
||||
currRoom.append(j)
|
||||
break
|
||||
break
|
||||
homeroomData = homerooms[currRoom[0]][currRoom[1]]
|
||||
absData = homeroomData["Absent"]
|
||||
homeroomData.pop('Absent')
|
||||
homeroomData.pop('placeholder')
|
||||
currDate = ""
|
||||
if fCommand != "":
|
||||
currDate = fData[1]
|
||||
else:
|
||||
for i in absData:
|
||||
currDate = i
|
||||
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
|
||||
break
|
||||
return render_template('admin.html', homerooms=homerooms, absData=absData, homeroomCode=currRoom, homeroomData=homeroomData, currDate=currDate, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'])
|
||||
elif pl == 'group':
|
||||
classes = db.child("Users").child(
|
||||
session['uid']).child("class").get().val()
|
||||
cclass = {}
|
||||
cateData = {}
|
||||
for i in classes:
|
||||
cateData = db.child("Classes").child(
|
||||
"GP_Class").child(i).get().val()
|
||||
cclass = {
|
||||
"name": db.child("Classes").child(i).child(
|
||||
"Class").child(classes[i]).child("name").get().val(),
|
||||
"name": cateData['Class'][classes[i]]['name'],
|
||||
"teacher": cateData['Class'][classes[i]]['teacher'],
|
||||
"classroom": cateData['Class'][classes[i]]['classroom'],
|
||||
"category": i,
|
||||
"class_id": classes[i]
|
||||
}
|
||||
print("got class")
|
||||
students = db.child("Classes").child(cclass['category']).child(
|
||||
"Class").child(cclass['class_id']).child("Students").get().val()
|
||||
print(students['9']['11'])
|
||||
all_stud_list = {}
|
||||
for grade in students:
|
||||
print(grade)
|
||||
all_stud_list[grade] = {}
|
||||
print(type(students[grade]))
|
||||
for homeroom in students[grade]:
|
||||
print(homeroom)
|
||||
roomData = db.child("Homerooms").child(
|
||||
grade).child(homeroom).get().val()
|
||||
all_stud_list[grade][homeroom] = {}
|
||||
if type(students[grade][homeroom]) == list:
|
||||
i = 0
|
||||
for student in students[grade][homeroom]:
|
||||
if student == 0:
|
||||
all_stud_list[grade][homeroom][i] = {
|
||||
"name": roomData[str(i)]["name"],
|
||||
"eng_name": roomData[str(i)]["eng_name"]
|
||||
}
|
||||
i += 1
|
||||
else:
|
||||
for student in students[grade][homeroom]:
|
||||
print(student)
|
||||
all_stud_list[grade][homeroom][student] = {
|
||||
"name": roomData[student]["name"],
|
||||
"eng_name": roomData[student]["eng_name"]
|
||||
}
|
||||
print("got students")
|
||||
dates = db.child("Classes").child(
|
||||
cclass['category']).child("Dates").get().val()
|
||||
status = 0
|
||||
attendance = {}
|
||||
homerooms = cateData['Homerooms']
|
||||
currDate = ""
|
||||
absData = {}
|
||||
for h in homerooms:
|
||||
h = h.split('^')
|
||||
print(h)
|
||||
hrData = db.child("Homerooms").child(h[0]).child(h[1]).get().val()
|
||||
tmpAbsData = hrData['Absent']
|
||||
hrData.pop('Absent')
|
||||
hrData.pop('placeholder')
|
||||
periods = []
|
||||
dow = ""
|
||||
if currDate == "":
|
||||
if fCommand == 'date':
|
||||
currDate = fData
|
||||
for j in tmpAbsData[currDate]:
|
||||
if j == "dow":
|
||||
dow = tmpAbsData[currDate][j]
|
||||
continue
|
||||
elif j == "confirm":
|
||||
continue
|
||||
if (tmpAbsData[currDate][j]['name'] == 'GP' and
|
||||
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
|
||||
periods.append(j)
|
||||
|
||||
if fCommand == 'date':
|
||||
currDate = fData
|
||||
if cclass['class_id'] in dates[currDate]:
|
||||
status = 1
|
||||
for grade in dates[currDate]['Absent']:
|
||||
attendance[grade] = {}
|
||||
for homeroom in dates[currDate]['Absent'][grade]:
|
||||
attendance[grade][homeroom] = {}
|
||||
for student in dates[currDate]['Absent'][grade][homeroom]:
|
||||
attendance[grade][homeroom][student] = 0
|
||||
else:
|
||||
for i in dates:
|
||||
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
|
||||
currDate = i
|
||||
if cclass['class_id'] in dates[currDate]:
|
||||
status = 1
|
||||
for grade in dates[currDate]['Absent']:
|
||||
attendance[grade] = {}
|
||||
for homeroom in dates[currDate]['Absent'][grade]:
|
||||
attendance[grade][homeroom] = {}
|
||||
for student in dates[currDate]['Absent'][grade][homeroom]:
|
||||
attendance[grade][homeroom][student] = 0
|
||||
break
|
||||
dates[i].pop('placeholder')
|
||||
print("got dates")
|
||||
return render_template('group_teach.html', cclass=cclass, all_stud_list=all_stud_list, dates=dates, currDate=currDate, status=status, attendance=attendance)
|
||||
else:
|
||||
for i in tmpAbsData:
|
||||
currDate = i
|
||||
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
|
||||
tmp = False
|
||||
for j in tmpAbsData[i]:
|
||||
if j == "dow":
|
||||
dow = tmpAbsData[i][j]
|
||||
continue
|
||||
elif j == "confirm":
|
||||
continue
|
||||
if (tmpAbsData[i][j]['name'] == 'GP' and
|
||||
tmpAbsData[i][j]['teacher'] == cclass['category']):
|
||||
periods.append(j)
|
||||
tmp = True
|
||||
if tmp == True:
|
||||
break
|
||||
else:
|
||||
for j in tmpAbsData[currDate]:
|
||||
if j == "dow":
|
||||
dow = tmpAbsData[currDate][j]
|
||||
continue
|
||||
elif j == "confirm":
|
||||
continue
|
||||
if (tmpAbsData[currDate][j]['name'] == 'GP' and
|
||||
tmpAbsData[currDate][j]['teacher'] == cclass['category']):
|
||||
periods.append(j)
|
||||
for p in periods:
|
||||
if not p in absData:
|
||||
absData[p] = {}
|
||||
for p in periods:
|
||||
if not h[0] in absData[p]:
|
||||
absData[p][h[0]] = {}
|
||||
absData[p][h[0]][h[1]] = {}
|
||||
for num in hrData:
|
||||
if (cclass['category'] in hrData[num]['GP_Class'] and
|
||||
hrData[num]['GP_Class'][cclass['category']] == cclass['class_id']):
|
||||
for p in periods:
|
||||
absData[p][h[0]][h[1]][num] = {
|
||||
"name": hrData[num]['name'],
|
||||
"eng_name": hrData[num]['eng_name'],
|
||||
"alr_fill": ('signature' in tmpAbsData[currDate][p] and
|
||||
cclass['class_id'] in tmpAbsData[currDate][p]['signature']),
|
||||
"absent": num in tmpAbsData[currDate][p]
|
||||
}
|
||||
print(absData)
|
||||
return render_template('group_teach.html', cclass=cclass, absData=absData, dow=dow, currDate=currDate, tmpAbsData=tmpAbsData)
|
||||
elif pl == 'homeroom':
|
||||
homeroom = db.child("Users").child(
|
||||
session['uid']).child("homeroom").get().val()
|
||||
homeroomCode = homeroom.split('^')
|
||||
homeroom = db.child("Homerooms").child(
|
||||
homeroomCode[0]).child(homeroomCode[1]).get().val()
|
||||
categories = homeroom['Categories'].split('^')
|
||||
currCategory = categories[0]
|
||||
session['uid']).child("homeroom").get().val().split('^')
|
||||
homeroomData = db.child("Homerooms").child(homeroom[0]).child(
|
||||
homeroom[1]).get().val()
|
||||
absData = homeroomData["Absent"]
|
||||
homeroomData.pop('Absent')
|
||||
homeroomData.pop('placeholder')
|
||||
currDate = ""
|
||||
gpClasses = db.child("Classes").child(currCategory).get().val()
|
||||
dates = gpClasses['Dates']
|
||||
confirmedClasses = []
|
||||
status = 0
|
||||
|
||||
if fCommand == 'date':
|
||||
currDate = fData
|
||||
tmp1 = 0
|
||||
tmp2 = 0
|
||||
for k in gpClasses['Class']:
|
||||
if k in dates[currDate]:
|
||||
confirmedClasses.append(k)
|
||||
tmp2 += 1
|
||||
tmp1 += 1
|
||||
if tmp1 == tmp2:
|
||||
status = 1
|
||||
else:
|
||||
for i in dates:
|
||||
for i in absData:
|
||||
currDate = i
|
||||
if i >= datetime.now(tz).strftime("%Y-%m-%d"):
|
||||
currDate = i
|
||||
tmp1 = 0
|
||||
tmp2 = 0
|
||||
for k in gpClasses['Class']:
|
||||
if k in dates[currDate]:
|
||||
confirmedClasses.append(k)
|
||||
tmp2 += 1
|
||||
tmp1 += 1
|
||||
if tmp1 == tmp2:
|
||||
status = 1
|
||||
break
|
||||
print("got dates")
|
||||
db.child("Classes").child(currCategory).child("Dates")
|
||||
homeroom.pop('Categories')
|
||||
all_stud_list = {}
|
||||
for i in homeroom:
|
||||
all_stud_list[i] = {}
|
||||
all_stud_list[i]['name'] = homeroom[i]['name']
|
||||
all_stud_list[i]['eng_name'] = homeroom[i]['eng_name']
|
||||
all_stud_list[i]['gpClass'] = homeroom[i]['Classes'][currCategory]
|
||||
if all_stud_list[i]['gpClass'] in confirmedClasses:
|
||||
if (homeroomCode[0] in gpClasses['Dates'][currDate]['Absent'] and
|
||||
homeroomCode[1] in gpClasses['Dates'][currDate]['Absent'][homeroomCode[0]] and
|
||||
i in gpClasses['Dates'][currDate]['Absent'][homeroomCode[0]][homeroomCode[1]]):
|
||||
# confirmed by teacher and absent
|
||||
all_stud_list[i]['status'] = 2
|
||||
else:
|
||||
# confirmed by teacher and not absent
|
||||
all_stud_list[i]['status'] = 1
|
||||
else:
|
||||
all_stud_list[i]['status'] = 0 # not yet confirmed by teacher
|
||||
return render_template('homeroom.html', all_stud_list=all_stud_list, currDate=currDate, dates=dates, gpClasses=gpClasses, confirmedClasses=confirmedClasses,
|
||||
currCategory=currCategory, categories=categories, homeroomCode=homeroomCode, status=status)
|
||||
|
||||
return render_template('homeroom.html', absData=absData, homeroomCode=homeroom, homeroomData=homeroomData, currDate=currDate, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'])
|
||||
else:
|
||||
return redirect('/')
|
||||
return redirect('/logout')
|
||||
|
||||
|
||||
@ app.route('/', methods=['GET', 'POST'])
|
||||
|
@ -211,17 +201,26 @@ def index():
|
|||
return redirect('/manage')
|
||||
|
||||
|
||||
@app.route('/manage', methods=['GET'])
|
||||
@ app.route('/manage', methods=['GET'])
|
||||
def manage():
|
||||
return manageProcess("", "")
|
||||
|
||||
|
||||
@app.route('/manage/date', methods=['POST'])
|
||||
@ app.route('/manage/date', methods=['POST'])
|
||||
def manage_date():
|
||||
return manageProcess("date", request.form['date'])
|
||||
|
||||
|
||||
@app.route('/manage/group_teach_publish', methods=['POST'])
|
||||
@app.route('/manage/admin', methods=['POST'])
|
||||
def manage_admin():
|
||||
data = [
|
||||
request.form['grade'] + '^' + request.form['room'],
|
||||
request.form['date']
|
||||
]
|
||||
return manageProcess("admin", data)
|
||||
|
||||
|
||||
@ app.route('/manage/group_teach_publish', methods=['POST'])
|
||||
def group_teach_publish():
|
||||
classes = db.child("Users").child(
|
||||
session['uid']).child("class").get().val()
|
||||
|
@ -231,28 +230,83 @@ def group_teach_publish():
|
|||
"name": db.child("Classes").child(i).child(
|
||||
"Class").child(classes[i]).child("name").get().val(),
|
||||
"category": i,
|
||||
"class_id": classes[i]
|
||||
"class_id": classes[i],
|
||||
"homerooms": db.child("Classes").child(
|
||||
"GP_Class").child(i).child("Homerooms").get().val()
|
||||
}
|
||||
print("got class")
|
||||
cDate = ""
|
||||
for key in request.form.keys():
|
||||
print(type(key), key)
|
||||
if key == 'date':
|
||||
print('here')
|
||||
cDate = request.form[key]
|
||||
db.child("Classes").child(cclass['category']).child(
|
||||
"Dates").child(request.form[key]).update({'confirmed': 0})
|
||||
db.child("Classes").child(cclass['category']).child(
|
||||
"Dates").child(request.form[key]).update({cclass['class_id']: request.form['signatureData']})
|
||||
elif key == 'signatureData':
|
||||
pass
|
||||
else:
|
||||
# spilt string
|
||||
id = key.split('^')
|
||||
print(id)
|
||||
db.child("Classes").child(cclass['category']).child("Dates").child(
|
||||
cDate).child("Absent").child(id[0]).child(id[1]).update({id[2]: 1})
|
||||
return "Success!"
|
||||
date = request.form['date']
|
||||
period = request.form['period']
|
||||
signature = request.form['signatureData']
|
||||
signature = signature.removeprefix('data:image/png;base64,')
|
||||
signature = bytes(signature, 'utf-8')
|
||||
rand = str(randint(100000000000000, 999999999999999))
|
||||
rand += ".png"
|
||||
with open(os.path.join('temp', rand), "wb") as fh:
|
||||
fh.write(base64.decodebytes(signature))
|
||||
storage.child(os.path.join('signatures', rand)
|
||||
).put(os.path.join('temp', rand))
|
||||
|
||||
formData = request.form.to_dict()
|
||||
formData.pop('signatureData')
|
||||
formData.pop('date')
|
||||
formData.pop('period')
|
||||
for i in formData:
|
||||
i = i.split('^')
|
||||
db.child("Homerooms").child(i[0]).child(i[1]).child(
|
||||
"Absent").child(date).child(period).update({i[2]: 0})
|
||||
for h in cclass['homerooms']:
|
||||
h = h.split('^')
|
||||
db.child("Homerooms").child(h[0]).child(h[1]).child(
|
||||
"Absent").child(date).child(period).child("signature").update({cclass['class_id']: str(storage.child(os.path.join('signatures', rand)).get_url(None))})
|
||||
os.remove(os.path.join('temp', rand))
|
||||
return redirect('/manage')
|
||||
|
||||
|
||||
@ app.route('/manage/homeroom_abs', methods=['POST'])
|
||||
def homeroom_abs_publish():
|
||||
date = request.form['date']
|
||||
homeroom = request.form['homeroom'].split('^')
|
||||
period = request.form['period']
|
||||
signature = request.form['signatureData']
|
||||
signature = signature.removeprefix('data:image/png;base64,')
|
||||
signature = bytes(signature, 'utf-8')
|
||||
rand = str(randint(100000000000000, 999999999999999))
|
||||
rand += ".png"
|
||||
with open(os.path.join('temp', rand), "wb") as fh:
|
||||
fh.write(base64.decodebytes(signature))
|
||||
storage.child(os.path.join('signatures', rand)
|
||||
).put(os.path.join('temp', rand))
|
||||
formData = request.form.to_dict()
|
||||
formData.pop('signatureData')
|
||||
formData.pop('date')
|
||||
formData.pop('homeroom')
|
||||
formData.pop('period')
|
||||
for i in formData:
|
||||
db.child("Homerooms").child(homeroom[0]).child(
|
||||
homeroom[1]).child("Absent").child(date).child(period).update({i: 0})
|
||||
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child(
|
||||
"Absent").child(date).child(period).update({'signature': str(storage.child(os.path.join('signatures', rand)).get_url(None))})
|
||||
os.remove(os.path.join('temp', rand))
|
||||
return redirect('/manage')
|
||||
|
||||
|
||||
@app.route('/manage/homeroom_confirm', methods=['POST'])
|
||||
def homeroom_confirm():
|
||||
date = request.form['date']
|
||||
homeroom = request.form['homeroom'].split('^')
|
||||
signature = request.form['signatureData']
|
||||
signature = signature.removeprefix('data:image/png;base64,')
|
||||
signature = bytes(signature, 'utf-8')
|
||||
rand = str(randint(100000000000000, 999999999999999))
|
||||
rand += ".png"
|
||||
with open(os.path.join('temp', rand), "wb") as fh:
|
||||
fh.write(base64.decodebytes(signature))
|
||||
storage.child(os.path.join('signatures', rand)
|
||||
).put(os.path.join('temp', rand))
|
||||
db.child("Homerooms").child(homeroom[0]).child(homeroom[1]).child("Absent").child(date).update(
|
||||
{"confirm": str(storage.child(os.path.join('signatures', rand)).get_url(None))})
|
||||
return redirect('/manage')
|
||||
|
||||
|
||||
@ app.route('/upload/homeroom', methods=['GET', 'POST'])
|
||||
|
@ -280,6 +334,36 @@ def upload_homeroom():
|
|||
return "Successfully uploaded " + gradec + "-" + classc
|
||||
|
||||
|
||||
@ app.route('/upload/gp_classes', methods=['GET', 'POST'])
|
||||
def upload_gp_classes():
|
||||
if request.method == 'GET':
|
||||
return render_template('uploadcsv.html', title="Group Classes", url="/upload/gp_classes")
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
csv_file = request.files['csv']
|
||||
filepath = os.path.join('./temp', csv_file.filename)
|
||||
csv_file.save(filepath)
|
||||
csv_dict = pd.read_csv(filepath)
|
||||
category_cnt = csv_dict.shape[1] - 1
|
||||
for i in range(category_cnt):
|
||||
tmp_csv = csv_dict[csv_dict.columns[i+1]].tolist()
|
||||
for j in range(len(tmp_csv)):
|
||||
if type(tmp_csv[j]) == float:
|
||||
break
|
||||
if j % 4 == 0:
|
||||
db.child("Classes").child("GP_Class").child(csv_dict.columns[i+1]).child("Class").child(
|
||||
tmp_csv[j]).child("name").set(tmp_csv[j+1])
|
||||
db.child("Classes").child("GP_Class").child(csv_dict.columns[i+1]).child("Class").child(
|
||||
tmp_csv[j]).child("teacher").set(tmp_csv[j+2])
|
||||
db.child("Classes").child("GP_Class").child(csv_dict.columns[i+1]).child("Class").child(
|
||||
tmp_csv[j]).child("classroom").set(tmp_csv[j+3])
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
return "Error. Please try again\n("+str(e)+")"
|
||||
return "Successfully uploaded"
|
||||
|
||||
|
||||
@ app.route('/upload/stud_in_group', methods=['GET', 'POST'])
|
||||
def upload_stud_in_group():
|
||||
if request.method == 'GET':
|
||||
|
@ -295,13 +379,13 @@ def upload_stud_in_group():
|
|||
csv_dict = csv.DictReader(file)
|
||||
headers = csv_dict.fieldnames
|
||||
headers = headers[1:]
|
||||
for h in headers:
|
||||
db.child("Classes").child("GP_Class").child(
|
||||
h).child("Homerooms").update({gradec+'^'+classc: 0})
|
||||
for row in csv_dict:
|
||||
for h in headers:
|
||||
db.child("Homerooms").child(gradec).child(classc).child(
|
||||
row['number']).child("Classes").child(h).set(row[h])
|
||||
db.child("Classes").child(h).child("Class").child(row[h]).child(
|
||||
"Students").child(gradec).child(classc).update({str(row['number']): 0})
|
||||
|
||||
row['number']).child("GP_Class").update({h: row[h]})
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
|
@ -309,6 +393,76 @@ def upload_stud_in_group():
|
|||
return "Successfully uploaded " + gradec + "-" + classc
|
||||
|
||||
|
||||
@ app.route('/upload/period_list', methods=['GET', 'POST'])
|
||||
def upload_period_list():
|
||||
if request.method == 'GET':
|
||||
return render_template('uploadcsv.html', title="Period List", url="/upload/period_list")
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
# get csv
|
||||
gradec = request.form['gradeCode']
|
||||
classc = request.form['classcode']
|
||||
csv_file = request.files['csv']
|
||||
filepath = os.path.join('./temp', csv_file.filename)
|
||||
csv_file.save(filepath)
|
||||
csv_dict = pd.read_csv(filepath)
|
||||
periodCodes = csv_dict['Period Day'].tolist()
|
||||
for i in range(5):
|
||||
tmp_csv = csv_dict[str(i+1)].tolist()
|
||||
print(tmp_csv)
|
||||
for j in range(len(tmp_csv)):
|
||||
if not (periodCodes[j].endswith('-t')):
|
||||
if type(tmp_csv[j]) == float:
|
||||
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
|
||||
str(i+1)).child(periodCodes[j]).update({'name': '--'})
|
||||
else:
|
||||
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
|
||||
str(i+1)).child(periodCodes[j]).update({'name': tmp_csv[j]})
|
||||
if not(periodCodes[j] == 'm' or periodCodes[j] == 'n'):
|
||||
j += 1
|
||||
db.child("Classes").child("Homeroom").child(gradec).child(classc).child(
|
||||
str(i+1)).child(periodCodes[j-1]).update({'teacher': tmp_csv[j]})
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
return "Error. Please try again\n("+str(e)+")"
|
||||
return "Successfully uploaded " + gradec + "-" + classc
|
||||
|
||||
|
||||
@ app.route('/upload/dates', methods=['GET', 'POST'])
|
||||
def upload_dates():
|
||||
if request.method == 'GET':
|
||||
return render_template('uploadcsv.html', title="School Days", url="/upload/dates")
|
||||
elif request.method == 'POST':
|
||||
try:
|
||||
csv_file = request.files['csv']
|
||||
filepath = os.path.join('./temp', csv_file.filename)
|
||||
csv_file.save(filepath)
|
||||
with open(filepath) as file:
|
||||
csv_dict = csv.DictReader(file)
|
||||
headers = csv_dict.fieldnames
|
||||
temp = db.child("Homerooms").get().val()
|
||||
for row in csv_dict:
|
||||
for h in headers:
|
||||
for t in temp:
|
||||
for i in temp[t]:
|
||||
periodData = db.child("Classes").child(
|
||||
"Homeroom").child(t).child(i).get().val()
|
||||
print(type(t), t)
|
||||
print(type(i), i)
|
||||
db.child("Homerooms").child(t).child(i).child(
|
||||
"Absent").child(h).update({"dow": row[h]})
|
||||
db.child("Homerooms").child(t).child(i).child(
|
||||
"Absent").child(h).update(
|
||||
periodData[int(row[h])]
|
||||
)
|
||||
os.remove(filepath)
|
||||
except Exception as e:
|
||||
os.remove(filepath)
|
||||
return "Error. Please try again\n("+str(e)+")"
|
||||
return "Successfully uploaded dates"
|
||||
|
||||
|
||||
# @ app.route('/upload/rm_all_data_of_class', methods=['GET', "POST"])
|
||||
# def rm_all_data_of_class():
|
||||
# if request.method == 'GET':
|
||||
|
@ -322,7 +476,7 @@ def upload_stud_in_group():
|
|||
# return "Successfully removed " + classc
|
||||
|
||||
|
||||
@app.route('/logout', methods=['GET'])
|
||||
@ app.route('/logout', methods=['GET'])
|
||||
def logout():
|
||||
session.clear()
|
||||
return redirect('/')
|
||||
|
|
|
@ -7,13 +7,13 @@ Flask == 2.0.1
|
|||
# Attendance/test.py: 1
|
||||
Pyrebase == 3.0.27
|
||||
|
||||
# Attendance/app.py: 9
|
||||
# Attendance/app.py: 7
|
||||
pandas == 1.1.3
|
||||
|
||||
# Attendance/app.py: 10
|
||||
# Attendance/test.py: 3
|
||||
python_dotenv == 0.19.0
|
||||
|
||||
# Attendance/app.py: 4
|
||||
pytz == 2020.1
|
||||
|
||||
# Attendance/app.py: 5,6
|
||||
sendgrid == 6.7.1
|
||||
gunicorn == 20.1.0
|
|
@ -30,6 +30,14 @@ div.forSign canvas {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.margin-bottom {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
div.signDiv {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
p.highlightAbs {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -42,6 +50,6 @@ p.highlightAbs.n-2 {
|
|||
color: red;
|
||||
}
|
||||
|
||||
div.classlist {
|
||||
text-align: left;
|
||||
.margin-top {
|
||||
margin-top: 20px;
|
||||
}
|
22
static/homeroom.css
Normal file
22
static/homeroom.css
Normal file
|
@ -0,0 +1,22 @@
|
|||
div.container {
|
||||
max-width: 90%;
|
||||
}
|
||||
|
||||
.btn.afterSelButton {
|
||||
padding: .200rem .50rem;
|
||||
}
|
||||
|
||||
|
||||
body {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.viewSignatures .col .row .col {
|
||||
border: 1px solid;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.row {
|
||||
--bs-gutter-x: 0;
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Admin_View</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/homeroom.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Admin_View</h1>
|
||||
<h2>{{homeroomCode[0]}}: {{homeroomCode[1]}}</h2>
|
||||
<h2>Status: ({{currDate}}, 星期{{absData[currDate]['dow']}})</h2>
|
||||
<a href="/logout"><button class="btn btn-primary">Logout 登出</button></a>
|
||||
<div class="container margin-bottom">
|
||||
<form action="/manage/admin" id="adminSelForm" method="post">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<select name="grade" id="sel-grade" class="form-select" onchange="getHR()" required>
|
||||
<option value="">選擇年級</option>
|
||||
{% for grade in homerooms %}
|
||||
<option value="{{grade}}">{{grade}}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select name="room" id="sel-room" class="form-select" disabled required>
|
||||
<option value="">請先選擇年級</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
<select name="date" id="date" class="form-select">
|
||||
{% for date in absData %}
|
||||
{% if date == currDate %}
|
||||
<option value="{{date}}" selected="selected">{{date}}</option>
|
||||
{% else %}
|
||||
<option value="{{date}}">{{date}}</option>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-1">
|
||||
<button class="btn btn-primary" onclick="loadingAnimation()">查詢</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="row title">
|
||||
<div class="col">HR</div>
|
||||
<div class="col">Number</div>
|
||||
<div class="col">Name</div>
|
||||
<div class="col">Eng Name</div>
|
||||
<div class="col">Morning</div>
|
||||
<div class="col">1</div>
|
||||
<div class="col">2</div>
|
||||
<div class="col">3</div>
|
||||
<div class="col">4</div>
|
||||
<div class="col">Nap</div>
|
||||
<div class="col">5</div>
|
||||
<div class="col">6</div>
|
||||
<div class="col">7</div>
|
||||
<div class="col">8</div>
|
||||
<div class="col">9</div>
|
||||
</div>
|
||||
<div class="row title">
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<div class="col">{{absData[currDate][i]['name']}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row title">
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<div class="col">{{absData[currDate][i]['teacher']}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if data != None %}
|
||||
{% for i in homeroomData %}
|
||||
<div class="row">
|
||||
<div class="col">{{homeroomCode[0]}}{{homeroomCode[1]}}</div>
|
||||
<div class="col">{{i}}</div>
|
||||
<div class="col">{{ homeroomData[i]['name'] }}</div>
|
||||
<div class="col">{{ homeroomData[i]['eng_name'] }}</div>
|
||||
{% for j in periods %}
|
||||
{% if 'signature' in absData[currDate][j] %}
|
||||
{% if i in absData[currDate][j] %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-2">X</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if absData[currDate][j]['name'] != 'GP' %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-1">V</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if (homeroomData[i]['GP_Class'][absData[currDate][j]['teacher']] in
|
||||
absData[currDate][j]['signature'])%}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-1">V</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-2"></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs"></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% for c in range(periods|length + 1) %}
|
||||
{% if c % 2 == 0 %}
|
||||
<div class="row signatures">
|
||||
{% endif %}
|
||||
<div class="col half">
|
||||
{% if c == 0 %}
|
||||
<div class="row">Homeroom Teacher</div>
|
||||
<div class="row"><img src="{{absData[currDate]['confirm']}}" alt=""></div>
|
||||
{% else %}
|
||||
{% if absData[currDate][periods[c-1]]['name'] == 'GP' %}
|
||||
{% if 'signature' in absData[currDate][periods[c-1]] %}
|
||||
{% for i in absData[currDate][periods[c-1]]['signature'] %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['teacher']}}: {{i}}</div>
|
||||
<div class="row"><img src="{{absData[currDate][periods[c-1]]['signature'][i]}}" alt=""></div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['teacher']}}: No Signature
|
||||
</div>
|
||||
<div class="row"></div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['name']}}:
|
||||
{{absData[currDate][periods[c-1]]['teacher']}}
|
||||
</div>
|
||||
<div class="row"><img src="{{absData[currDate][periods[c-1]]['signature']}}" alt=""></div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if c % 2 == 1 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row margin-top">
|
||||
<div class="col">
|
||||
<h3>此排請勿點選</h3>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/upload/homeroom"><button class="btn btn-primary">1. Add Homeroom</button></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/upload/gp_classes"><button class="btn btn-primary">2. Add GP Classes</button></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/upload/stud_in_group"><button class="btn btn-primary">3. Add GP Student List</button></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/upload/period_list"><button class="btn btn-primary">4. Period List</button></a>
|
||||
</div>
|
||||
<div class="col">
|
||||
<a href="/upload/dates"><button class="btn btn-primary">[WEEKLY] Dates</button></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
<script>
|
||||
var homerooms = {};
|
||||
{% for i in homerooms %}
|
||||
homerooms['{{i}}'] = [];
|
||||
{% for j in homerooms[i] %}
|
||||
homerooms['{{i}}'].push({{ j }});
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
console.log(homerooms)
|
||||
function loadingAnimation() {
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
function getHR() {
|
||||
var grade = $('#sel-grade').val();
|
||||
$('#sel-room').html('<option value="">請先選擇年級</option>');
|
||||
if (grade === "") {
|
||||
$('#sel-room').attr('disabled', 'disabled')
|
||||
return
|
||||
}
|
||||
homerooms[grade].forEach(element => {
|
||||
$('#sel-room').append(`<option value="${element}">${element}</option>`)
|
||||
});
|
||||
$('#sel-room').removeAttr('disabled')
|
||||
}
|
||||
function submitQuery() {
|
||||
loadingAnimation();
|
||||
document.getElementById('hrSelForm').submit();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -16,10 +16,11 @@
|
|||
<div class="container">
|
||||
<h1>Group_Teach_View</h1>
|
||||
<h2>{{cclass['category']}}: {{cclass['class_id']}}: {{cclass['name']}}</h2>
|
||||
<h2>Status: {{status}} ({{currDate}})</h2>
|
||||
<h2>({{currDate}}) ({{dow}})</h2>
|
||||
<a href="/logout"><button class="btn btn-primary">Logout 登出</button></a>
|
||||
<form action="/manage/date" id="dateSelForm" method="post">
|
||||
<select name="date" id="date" class="form-select" onchange="chgDate(this);">
|
||||
{% for date in dates %}
|
||||
{% for date in tmpAbsData %}
|
||||
{% if date == currDate %}
|
||||
<option value="{{date}}" selected="selected">{{date}}</option>
|
||||
{% else %}
|
||||
|
@ -28,15 +29,12 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</form>
|
||||
{% if status == 1 %}
|
||||
<div class="alert alert-warning" role="alert">
|
||||
Already Sumitted!
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if status == 0 %}
|
||||
<form action="/manage/group_teach_publish" id="attendanceData" method="post">
|
||||
{% set alr_fill = namespace(found=false) %}
|
||||
{% for i in absData %}
|
||||
<form action="/manage/group_teach_publish" id="attendanceData^{{i}}" method="post">
|
||||
<input type="hidden" name="date" value="{{currDate}}">
|
||||
<input type="hidden" name="signatureData" value="">
|
||||
<input type="hidden" name="period" value="{{i}}">
|
||||
<input type="hidden" class="signatureData" name="signatureData" value="">
|
||||
<div class="col">
|
||||
<div class="row title">
|
||||
<div class="col">Grade</div>
|
||||
|
@ -44,58 +42,96 @@
|
|||
<div class="col">Number</div>
|
||||
<div class="col">Name</div>
|
||||
<div class="col">Eng Name</div>
|
||||
<div class="col">Attendance (Check Absent)</div>
|
||||
<div class="col">Period {{i}}</div>
|
||||
</div>
|
||||
{% if data != None %}
|
||||
{% for grade in all_stud_list %}
|
||||
{% for homeroom in all_stud_list[grade] %}
|
||||
{% for student in all_stud_list[grade][homeroom] %}
|
||||
{% for grade in absData[i] %}
|
||||
{% for homeroom in absData[i][grade] %}
|
||||
{% for student in absData[i][grade][homeroom] %}
|
||||
<div class="row">
|
||||
<div class="col">{{grade}}</div>
|
||||
<div class="col">{{homeroom}}</div>
|
||||
<div class="col">{{ student }}</div>
|
||||
<div class="col">{{ all_stud_list[grade][homeroom][student]['name'] }}</div>
|
||||
<div class="col">{{ all_stud_list[grade][homeroom][student]['eng_name'] }}</div>
|
||||
<div class="col"><input type="checkbox" name="{{grade}}^{{homeroom}}^{{student}}"></div>
|
||||
<div class="col">{{ absData[i][grade][homeroom][student]['name'] }}</div>
|
||||
<div class="col">{{ absData[i][grade][homeroom][student]['eng_name'] }}</div>
|
||||
{% if absData[i][grade][homeroom][student]['alr_fill'] %}
|
||||
{% set alr_fill.found = true %}
|
||||
{% if absData[i][grade][homeroom][student]['absent'] %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-2">X</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-1">V</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="col">
|
||||
{% if 'confirm' in absData[i][grade][homeroom] %}
|
||||
<p class="highlightAbs">--</p>
|
||||
{% else %}
|
||||
<input type="checkbox" class="{{grade}}^{{homeroom}}^{{student}}">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<h3>Please Sign Below</h3>
|
||||
<div class="forSign"><canvas id="signature_pad"></canvas></div>
|
||||
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear Signature</button>
|
||||
<button class="btn btn-primary" type="button" onclick="submitForm()">Submit</button>
|
||||
{% if alr_fill.found %}
|
||||
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
|
||||
onclick="viewSignature('{{i}}')" disabled="disabled">
|
||||
Already Submitted</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
|
||||
onclick="viewSignature('{{i}}')">
|
||||
↑ Confirmed, Sign (Period {{i}}) ↑</button>
|
||||
{% endif %}
|
||||
<div class="signDiv" id="sign^{{i}}" hidden="hidden">
|
||||
<h3>Please Sign Below</h3>
|
||||
<div class="forSign"><canvas id="signature_pad^{{i}}"></canvas></div>
|
||||
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear
|
||||
Signature</button><button class="btn btn-primary" type="button"
|
||||
onclick="submitForm()">Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
|
||||
<script src=" https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<script>
|
||||
var canvas = document.getElementById("signature_pad");
|
||||
var signaturePad = new SignaturePad(canvas);
|
||||
function resizeCanvas() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
canvas.getContext("2d").scale(ratio, ratio);
|
||||
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
|
||||
}
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
resizeCanvas();
|
||||
var signaturePad, selPeriod;
|
||||
function submitForm() {
|
||||
if (!signaturePad.isEmpty()) {
|
||||
signaturePad.off();
|
||||
var data = signaturePad.toDataURL('image/png');
|
||||
document.getElementsByName('signatureData')[0].value = data;
|
||||
document.getElementById('attendanceData').submit();
|
||||
document.getElementById("attendanceData^" + selPeriod).getElementsByClassName("signatureData")[0].value = data;
|
||||
document.getElementById("attendanceData^" + selPeriod).submit();
|
||||
}
|
||||
else {
|
||||
alert("Please sign first");
|
||||
}
|
||||
}
|
||||
function viewSignature(period) {
|
||||
selPeriod = period
|
||||
$('.viewSignatureBtn').attr({ 'disabled': 'disabled' });
|
||||
$('.viewSignatureBtn').removeClass('margin-bottom');
|
||||
document.getElementById('sign^' + period).removeAttribute('hidden');
|
||||
var canvas = document.getElementById("signature_pad^" + period);
|
||||
signaturePad = new SignaturePad(canvas);
|
||||
function resizeCanvas() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
canvas.getContext("2d").scale(ratio, ratio);
|
||||
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
|
||||
}
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
resizeCanvas();
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
|
|
|
@ -9,17 +9,18 @@
|
|||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/allpages.css">
|
||||
<link rel="stylesheet" href="/static/login.css">
|
||||
<link rel="stylesheet" href="/static/homeroom.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Homeroom_View</h1>
|
||||
<h2>{{homeroomCode[0]}}: {{homeroomCode[1]}}</h2>
|
||||
<h2>Status: ({{currDate}})</h2>
|
||||
<h2>Status: ({{currDate}}, 星期{{absData[currDate]['dow']}})</h2>
|
||||
<a href="/logout"><button class="btn btn-primary">Logout 登出</button></a>
|
||||
<form action="/manage/date" id="dateSelForm" method="post">
|
||||
<select name="date" id="date" class="form-select" onchange="chgDate();">
|
||||
{% for date in dates %}
|
||||
{% for date in absData %}
|
||||
{% if date == currDate %}
|
||||
<option value="{{date}}" selected="selected">{{date}}</option>
|
||||
{% else %}
|
||||
|
@ -30,114 +31,172 @@
|
|||
</form>
|
||||
<form action="/manage/homeroom_confirm" id="homeroom_confirm" method="post">
|
||||
<input type="hidden" name="date" value="{{currDate}}">
|
||||
<input type="hidden" name="category" value="{{currCategory}}">
|
||||
<input type="hidden" name="signatureData" value="">
|
||||
<input type="hidden" name="homeroom" value="{{homeroomCode[0]}}^{{homeroomCode[1]}}">
|
||||
<input type="hidden" id="hrCfrm-sign" name="signatureData" value="">
|
||||
</form>
|
||||
<div class="col">
|
||||
<div class="row title">
|
||||
<div class="col">Homeroom</div>
|
||||
<div class="col">HR</div>
|
||||
<div class="col">Number</div>
|
||||
<div class="col">Name</div>
|
||||
<div class="col">Eng Name</div>
|
||||
<div class="col">GP_Class</div>
|
||||
<div class="col">Attendance (Here=V, Abs=X)</div>
|
||||
<div class="col">Morning</div>
|
||||
<div class="col">1</div>
|
||||
<div class="col">2</div>
|
||||
<div class="col">3</div>
|
||||
<div class="col">4</div>
|
||||
<div class="col">Nap</div>
|
||||
<div class="col">5</div>
|
||||
<div class="col">6</div>
|
||||
<div class="col">7</div>
|
||||
<div class="col">8</div>
|
||||
<div class="col">9</div>
|
||||
</div>
|
||||
<div class="row title">
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<div class="col">{{absData[currDate][i]['name']}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="row title">
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<div class="col">{{absData[currDate][i]['teacher']}}</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if data != None %}
|
||||
{% for i in all_stud_list %}
|
||||
{% for i in homeroomData %}
|
||||
<div class="row">
|
||||
<div class="col">{{homeroomCode[0]}}{{homeroomCode[1]}}</div>
|
||||
<div class="col">{{i}}</div>
|
||||
<div class="col">{{ all_stud_list[i]['name'] }}</div>
|
||||
<div class="col">{{ all_stud_list[i]['eng_name'] }}</div>
|
||||
<div class="col">{{ all_stud_list[i]['gpClass'] }}:
|
||||
{{gpClasses['Class'][all_stud_list[i]['gpClass']]['name']}}</div>
|
||||
<div class="col">{{ homeroomData[i]['name'] }}</div>
|
||||
<div class="col">{{ homeroomData[i]['eng_name'] }}</div>
|
||||
{% for j in periods %}
|
||||
{% if 'signature' in absData[currDate][j] %}
|
||||
{% if i in absData[currDate][j] %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-{{all_stud_list[i]['status']}}">
|
||||
{% if all_stud_list[i]['status'] == 1 %}
|
||||
V
|
||||
{% elif all_stud_list[i]['status'] == 2 %}
|
||||
X
|
||||
{% endif %}
|
||||
</p>
|
||||
<p class="highlightAbs n-2">X</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if absData[currDate][j]['name'] != 'GP' %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-1">V</p>
|
||||
</div>
|
||||
{% else %}
|
||||
{% if (homeroomData[i]['GP_Class'][absData[currDate][j]['teacher']] in
|
||||
absData[currDate][j]['signature'])%}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-1">V</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs n-2"></p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% elif absData[currDate][j]['name'] == 'GP' %}
|
||||
<div class="col">
|
||||
<p class="highlightAbs"></p>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col">
|
||||
{% if 'confirm' in absData[currDate] %}
|
||||
<p class="highlightAbs"></p>
|
||||
{% else %}
|
||||
<input type="checkbox" class="tobeform {{j}}^{{i}}">
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
<div class="row">
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<div class="col">
|
||||
{% if ('signature' in absData[currDate][i] or absData[currDate][i]['name'] == 'GP' or
|
||||
'confirm' in absData[currDate]) %}
|
||||
<button class="btn btn-primary afterSelButton" disabled="disabled"
|
||||
onclick="afterSelAbs('{{i|string}}')">Confirm</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary afterSelButton"
|
||||
onclick="afterSelAbs('{{i|string}}')">Confirm</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<!-- show signature of confirmed classes -->
|
||||
{% for c in range(confirmedClasses|length) %}
|
||||
<form action="/manage/homeroom_abs" id="postHomeroomAbs" hidden="hidden" method="post">
|
||||
<input type="text" id="HR-date" name="date" value="{{currDate}}">
|
||||
<input type="text" id="HR-period" name="period" value="">
|
||||
<input type="text" id="HR-signatureData" name="signatureData" value="">
|
||||
<input type="text" id="HR-homeroom" name="homeroom" value="{{homeroomCode[0]}}^{{homeroomCode[1]}}">
|
||||
</form>
|
||||
{% if 'confirm' in absData[currDate] %}
|
||||
<button class="btn btn-primary margin-top afterSelButton" onclick="homeroomCfrm()" disabled="disabled">
|
||||
Already Confirmed</button>
|
||||
{% else %}
|
||||
<button class="btn btn-primary margin-top afterSelButton" onclick="homeroomCfrm()">Homeroom
|
||||
Teacher Confirm</button>
|
||||
{% endif %}
|
||||
<div id="finalCheck" hidden="hidden">
|
||||
<h3>Please Sign Below</h3>
|
||||
<div class="forSign"><canvas id="signature_pad"></canvas></div>
|
||||
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear Signature</button>
|
||||
<button class="btn btn-primary" type="button" onclick="submitForm()">Submit</button>
|
||||
</div>
|
||||
{% for c in range(periods|length + 1) %}
|
||||
{% if c % 2 == 0 %}
|
||||
<div class="row signatures">
|
||||
{% endif %}
|
||||
<div class="col half">
|
||||
<div class="row">{{confirmedClasses[c]}}: {{gpClasses['Class'][confirmedClasses[c]]['name']}}
|
||||
{% if c == 0 %}
|
||||
<div class="row">Homeroom Teacher</div>
|
||||
<div class="row"><img src="{{absData[currDate]['confirm']}}" alt=""></div>
|
||||
{% else %}
|
||||
{% if absData[currDate][periods[c-1]]['name'] == 'GP' %}
|
||||
{% if 'signature' in absData[currDate][periods[c-1]] %}
|
||||
{% for i in absData[currDate][periods[c-1]]['signature'] %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['teacher']}}: {{i}}</div>
|
||||
<div class="row"><img src="{{absData[currDate][periods[c-1]]['signature'][i]}}" alt=""></div>
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['teacher']}}: No Signature
|
||||
</div>
|
||||
<div class="row"><img src="{{gpClasses['Dates'][currDate][confirmedClasses[c]]}}" alt=""></div>
|
||||
<div class="row"></div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="row">{{periods[c-1]}}: {{absData[currDate][periods[c-1]]['name']}}:
|
||||
{{absData[currDate][periods[c-1]]['teacher']}}
|
||||
</div>
|
||||
<div class="row"><img src="{{absData[currDate][periods[c-1]]['signature']}}" alt=""></div>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if c % 2 == 1 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
<!-- Show Class Data -->
|
||||
<div class="classlist">
|
||||
<h2>Classes in {{currCategory}}</h2>
|
||||
<ul>
|
||||
{% for c in gpClasses['Class'] %}
|
||||
<li>
|
||||
<h3>{{c}}: {{gpClasses['Class'][c]['name']}}</h3>
|
||||
</li>
|
||||
<ul>
|
||||
<li>
|
||||
<h4>Classroom: {{ gpClasses['Class'][c]['classroom'] }}</h4>
|
||||
</li>
|
||||
<li>
|
||||
<h4>Teacher: {{ gpClasses['Class'][c]['teacher'] }}</h4>
|
||||
</li>
|
||||
</ul>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% if status == 1 %}
|
||||
<h3>Please Sign Below</h3>
|
||||
<div class="forSign"><canvas id="signature_pad"></canvas></div>
|
||||
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear Signature</button>
|
||||
<button class="btn btn-primary" type="button" onclick="submitForm()">Submit</button>
|
||||
{% else %}
|
||||
<h3>Please wait for all {{currCategory}} teachers to enter data.</h3>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if status == 1 %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
|
||||
<script>
|
||||
var canvas = document.getElementById("signature_pad");
|
||||
var signaturePad = new SignaturePad(canvas);
|
||||
function resizeCanvas() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
canvas.getContext("2d").scale(ratio, ratio);
|
||||
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
|
||||
}
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
resizeCanvas();
|
||||
function submitForm() {
|
||||
if (!signaturePad.isEmpty()) {
|
||||
signaturePad.off();
|
||||
var data = signaturePad.toDataURL('image/png');
|
||||
document.getElementsByName('signatureData')[0].value = data;
|
||||
document.getElementsByTagName('form')[0].submit();
|
||||
}
|
||||
else {
|
||||
alert("Please sign first");
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var signaturePad, hrCfrm = false;
|
||||
function loadingAnimation() {
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
|
@ -146,6 +205,56 @@
|
|||
loadingAnimation();
|
||||
document.getElementById('dateSelForm').submit();
|
||||
}
|
||||
function submitForm() {
|
||||
if (!signaturePad.isEmpty()) {
|
||||
loadingAnimation()
|
||||
signaturePad.off();
|
||||
var data = signaturePad.toDataURL('image/png');
|
||||
if (hrCfrm) {
|
||||
$('#hrCfrm-sign').val(data);
|
||||
document.getElementById('homeroom_confirm').submit()
|
||||
} else {
|
||||
document.getElementById('HR-signatureData').value = data;
|
||||
document.getElementById('postHomeroomAbs').submit();
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("Please sign first");
|
||||
}
|
||||
}
|
||||
function showSignaturePad() {
|
||||
$('#finalCheck').removeAttr('hidden');
|
||||
var canvas = document.getElementById("signature_pad");
|
||||
signaturePad = new SignaturePad(canvas);
|
||||
function resizeCanvas() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
canvas.height = canvas.offsetHeight * ratio;
|
||||
canvas.getContext("2d").scale(ratio, ratio);
|
||||
signaturePad.clear(); // otherwise isEmpty() might return incorrect value
|
||||
}
|
||||
window.addEventListener("resize", resizeCanvas);
|
||||
resizeCanvas();
|
||||
}
|
||||
function afterSelAbs(period) {
|
||||
var tobeformArr = [];
|
||||
$('#postHomeroomAbs #HR-period').val(period);
|
||||
$('.tobeform').attr('disabled', 'disabled');
|
||||
$('.afterSelButton').attr('disabled', 'disabled');
|
||||
$('.tobeform').each(function (i, obj) {
|
||||
if ($(this).attr('class').split(' ')[1].split('^')[0] == period &&
|
||||
$(this).is(":checked")) {
|
||||
$('#postHomeroomAbs').append('<input type="checkbox" name="' + $(this).attr('class').split(' ')[1].split('^')[1]
|
||||
+ '" checked="checked">');
|
||||
}
|
||||
});
|
||||
// show signature pad
|
||||
showSignaturePad()
|
||||
}
|
||||
function homeroomCfrm() {
|
||||
hrCfrm = true;
|
||||
showSignaturePad();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -34,11 +34,28 @@
|
|||
<label for="csv">{{title}}</label>
|
||||
<input type="file" class="form-control-file" id="csv" name="csv">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Upload</button>
|
||||
<button onclick="loadingAnimation()" type="submit" class="btn btn-primary">Upload</button>
|
||||
</form>
|
||||
<!-- show danger zone -->
|
||||
<div class="alert alert-danger" role="alert">
|
||||
<h4 class="alert-heading">Warning! 警告!</h4>
|
||||
<p>If you are not the adminstrator, please do not click "upload" This might make the system
|
||||
unuseable.</p>
|
||||
<p>非管理員請勿點選! 可能會讓系統無法使用!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loading" style="text-align:center; width:100%; display:none;"><img src="/static/loading.gif" alt=""
|
||||
style="height:100%;" />
|
||||
</div>
|
||||
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
|
||||
<script>
|
||||
function loadingAnimation() {
|
||||
$('.container').hide();
|
||||
$('#loading').show();
|
||||
}
|
||||
</script>
|
||||
<!-- end csv form center -->
|
||||
</body>
|
||||
|
||||
|
|
Loading…
Reference in a new issue