Added 2-step-ds; Export

This commit is contained in:
Aaron Lee 2021-12-26 21:08:50 +08:00
parent 70ca7164cb
commit 7e621848cb
26 changed files with 1324 additions and 426 deletions

1
.gitignore vendored
View file

@ -2,3 +2,4 @@
*.env *.env
test*.* test*.*
__pycache__/* __pycache__/*
excel/*

5
app.py
View file

@ -1,5 +1,5 @@
from functions import * from functions import *
from manage import manage from manage.manage import manage
from upload import upload from upload import upload
from login import login from login import login
load_dotenv() load_dotenv()
@ -20,6 +20,7 @@ class DefaultModelView(ModelView):
restricted = True restricted = True
def __init__(self, model, session, restricted=True, name=None, category=None, endpoint=None, url=None, **kwargs): def __init__(self, model, session, restricted=True, name=None, category=None, endpoint=None, url=None, **kwargs):
self.restricted = restricted self.restricted = restricted
self.column_default_sort = ('id', True)
for k, v in kwargs.items(): for k, v in kwargs.items():
setattr(self, k, v) setattr(self, k, v)
setattr(self, 'can_export', True) setattr(self, 'can_export', True)
@ -145,4 +146,4 @@ admin.add_link(MenuLink(name='Back to Home 返回一般管理', category='', url
admin.add_link(MenuLink(name='Logout 登出', category='', url='/logout')) admin.add_link(MenuLink(name='Logout 登出', category='', url='/logout'))
if __name__ == '__main__': if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000) app.run(debug=True, host='0.0.0.0', port=5050)

333
export.py Normal file
View file

@ -0,0 +1,333 @@
from functions import *
from openpyxl import Workbook
from openpyxl.styles import Font, Alignment, Border, Side
import io
center = Alignment(horizontal="center", vertical="center")
std_font = Font(name="Calibri", size=13)
side = Side(border_style='thin')
border = Border(left=side, right=side, top=side, bottom=side)
bold_bottom = Border(left=side, right=side, top=side, bottom=Side(border_style='medium', color='FF000000'))
def create_period_sheets(workbook, class_code):
ws = workbook.create_sheet(class_code[0] + class_code[1])
ws.merge_cells('A1:F1')
ws['A1'] = '台北市私立復興實驗高級中學班級課表'
ws['A1'].font = Font(name="DFKai-SB", size=15, bold=True)
ws['A1'].alignment = center
# loop over A:F
for i in range(0, 6):
ws[str(chr(ord('A') + i)) + '1'].border = border
ws['G1'] = class_code[0] + class_code[1]
ws['G1'].font = Font(name='Courier New', size=20, bold=True)
ws['G1'].alignment = center
ws['G1'].border = border
ws.row_dimensions[1].height = 40
ws.row_dimensions[2].height = 25
ws.column_dimensions['A'].width = 3
ws.column_dimensions['B'].width = 10
ws.merge_cells('A2:B2')
ws['A2'] = '時間'
ws['C2'] = '星期一'
ws['D2'] = '星期二'
ws['E2'] = '星期三'
ws['F2'] = '星期四'
ws['G2'] = '星期五'
# loop over A2:G2
for i in range(1, 8):
ws.cell(row=2, column=i).font = Font(size=14, bold=True)
ws.cell(row=2, column=i).alignment = center
ws.cell(row=2, column=i).border = border
# loop over C:G
for i in range(2, 8):
ws.column_dimensions[str(chr(ord('A') + i))].width = 13
# get data
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT dow,period,subject,teacher FROM schedule WHERE grade=%s AND class_=%s", (class_code[0], class_code[1]))
sql = cursor.fetchall()
data = {}
subject_teacher = {}
# loop over data
for i in sql:
if i[0] not in data:
data[i[0]] = {}
data[i[0]][i[1]] = {
'subject': i[2],
'teacher': i[3]
}
if i[2] != 'GP' and i[2] != '--' and i[3] != '--' and i[2] not in subject_teacher:
subject_teacher[i[2]] = i[3]
periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9']
times = {
'm': ['7:30', '8:10'],
'1': ['8:20', '9:05'],
'2': ['9:15', '10:00'],
'3': ['10:10', '10:55'],
'4': ['11:05', '11:50'],
'n': ['11:50', '13:05'],
'5': ['13:15', '14:00'],
'6': ['14:10', '14:55'],
'7': ['15:05', '15:50'],
'8': ['15:55', '16:40'],
'9': ['16:45', '17:30']
}
curr = 3
for p in periods:
ws.merge_cells('A' + str(curr) + ':A' + str(curr + 1))
ws.row_dimensions[curr].height = 20
ws.row_dimensions[curr + 1].height = 20
ws['A' + str(curr)] = p
ws['A' + str(curr)].font = std_font
ws['A' + str(curr)].alignment = center
ws['A' + str(curr)].border = border
ws['A' + str(curr + 1)].border = border
ws['B' + str(curr)] = times[p][0]
ws['B' + str(curr)].font = std_font
ws['B' + str(curr)].alignment = center
ws['B' + str(curr)].border = border
ws['B' + str(curr + 1)] = times[p][1]
ws['B' + str(curr + 1)].font = std_font
ws['B' + str(curr + 1)].alignment = center
ws['B' + str(curr + 1)].border = border
if p == 'm' or p == 'n':
ws.merge_cells('C' + str(curr) + ':G' + str(curr + 1))
for i in range(1, 6):
ws[chr(ord('C') + i-1) + str(curr)].font = std_font
ws[chr(ord('C') + i-1) + str(curr)].alignment = center
ws[chr(ord('C') + i-1) + str(curr)].border = border
ws[chr(ord('C') + i-1) + str(curr + 1)].border = border
if p == 'm':
ws['C' + str(curr)] = '早自習'
else:
ws['C' + str(curr)] = '午餐 / 午休'
else:
for i in range(1, 6):
ws.merge_cells(chr(ord('C') + i-1) + str(curr) + ':' + chr(ord('C') + i-1) + str(curr + 1))
ws[chr(ord('C') + i-1) + str(curr)].font = std_font
ws[chr(ord('C') + i-1) + str(curr)].alignment = center
ws[chr(ord('C') + i-1) + str(curr)].border = border
ws[chr(ord('C') + i-1) + str(curr + 1)].border = border
if i in data:
if p in data[i]:
ws[chr(ord('C') + i-1) + str(curr)] = (data[i][p]['subject'] if data[i][p]['subject'] != 'GP'
and data[i][p]['subject'] != '--' else '' if data[i][p]['subject'] == '--' else data[i][p]['teacher'])
curr += 2
ws.merge_cells('A26:G26')
ws['A26'] = '科任老師一覽表'
ws['A26'].font = Font(size=14, bold=True)
ws['A26'].alignment = center
ws.row_dimensions[26].height = 20
# loop over A26:G26
for i in range(0, 7):
ws[chr(ord('A') + i) + '26'].border = border
curr = 0
for i in subject_teacher:
if (curr % 3) == 0:
pos = ['A', 'C']
elif (curr % 3) == 1:
pos = ['D', 'E']
else:
pos = ['F', 'G']
loc = str(27+ int(curr/3))
ws.merge_cells(pos[0] + loc + ':' + pos[1] + loc)
ws[pos[0] + loc].font = std_font
ws[pos[0] + loc].alignment = center
ws[pos[0] + loc].border = border
ws[pos[0] + loc] = i + ': ' + subject_teacher[i]
for j in range(ord(pos[0]), ord(pos[1]) + 1):
ws[chr(j) + loc].border = border
ws.row_dimensions[curr + 27].height = 20
curr += 1
return workbook
def create_student_list(workbook, class_code):
ws = workbook.create_sheet(class_code[0] + class_code[1])
ws.merge_cells('A1:J1')
ws['A1'] = '台北市私立復興實驗高級中學學生名單'
ws['A1'].font = Font(name="DFKai-SB", size=15, bold=True)
ws['A1'].alignment = center
# loop over A:J
for i in range(0, 11):
ws[str(chr(ord('A') + i)) + '1'].border = border
ws.merge_cells('K1:L1')
ws['K1'] = class_code[0] + class_code[1]
ws['K1'].font = Font(name='Courier New', size=20, bold=True)
ws['K1'].alignment = center
ws['K1'].border = border
ws['L1'].border = border
ws.column_dimensions['A'].width = 5
ws.column_dimensions['B'].width = 11
ws.column_dimensions['C'].width = 12
ws.row_dimensions[1].height = 25
ws.row_dimensions[2].height = 20
ws['A2'] = '#'
ws['A2'].font = Font(name="Calibri", size=13, bold=True)
ws['A2'].alignment = center
ws['A2'].border = bold_bottom
ws['B2'] = '姓名'
ws['B2'].font = Font(name="DFKai-SB", size=13, bold=True)
ws['B2'].alignment = center
ws['B2'].border = bold_bottom
ws['C2'] = 'Name'
ws['C2'].font = Font(name="Calibri", size=13, bold=True)
ws['C2'].alignment = center
ws['C2'].border = bold_bottom
for i in range(3, 12):
ws[str(chr(ord('A') + i)) + '2'].border = bold_bottom
ws.column_dimensions[str(chr(ord('A') + i))].width = 5.8
db = refresh_db()
cursor = db.cursor()
cursor.execute('SELECT num,name,ename FROM students WHERE grade=%s AND class_=%s ORDER BY num ASC', (class_code[0], class_code[1]))
data = cursor.fetchall()
last = data[-1][0]
delcnt = 0
for i in range(0, last):
ws['A' + str(3 + i)] = i+1
ws['A' + str(3 + i)].font = std_font
ws['A' + str(3 + i)].alignment = center
ws['B' + str(3 + i)] = data[i - delcnt][1] if data[i - delcnt][0] == i+1 else ''
ws['B' + str(3 + i)].font = Font(name="DFKai-SB", size=14)
ws['B' + str(3 + i)].alignment = center
ws['C' + str(3 + i)] = data[i - delcnt][2] if data[i - delcnt][0] == i+1 else ''
ws['C' + str(3 + i)].font = std_font
ws['C' + str(3 + i)].alignment = center
ws.row_dimensions[3 + i].height = 19
for j in range(0, 12):
ws[str(chr(ord('A') + j)) + str(3 + i)].border = bold_bottom if (i+1)%5==0 else border
if data[i - delcnt][0] != i+1:
delcnt += 1
return workbook
def create_teacher_periods(workbook, teacher_name, orig_username=''):
ws = workbook.create_sheet(teacher_name)
ws.merge_cells('A1:E1')
ws['A1'] = '台北市私立復興實驗高級中學科任老師課表'
ws['A1'].font = Font(name="DFKai-SB", size=15, bold=True)
ws['A1'].alignment = center
# loop over A:E
for i in range(0, 5):
ws[str(chr(ord('A') + i)) + '1'].border = border
ws.merge_cells('F1:G1')
ws['F1'] = teacher_name + " 老師"
ws['F1'].font = Font(name='Calibri', size=15, bold=True)
ws['F1'].alignment = center
ws['F1'].border = border
ws['G1'].border = border
ws.row_dimensions[1].height = 40
ws.row_dimensions[2].height = 25
ws.column_dimensions['A'].width = 3
ws.column_dimensions['B'].width = 10
ws.merge_cells('A2:B2')
ws['A2'] = '時間'
ws['C2'] = '星期一'
ws['D2'] = '星期二'
ws['E2'] = '星期三'
ws['F2'] = '星期四'
ws['G2'] = '星期五'
# loop over A2:G2
for i in range(1, 8):
ws.cell(row=2, column=i).font = Font(size=14, bold=True)
ws.cell(row=2, column=i).alignment = center
ws.cell(row=2, column=i).border = border
# loop over C:G
for i in range(2, 8):
ws.column_dimensions[str(chr(ord('A') + i))].width = 13
# get data
data = {}
db = refresh_db()
cursor = db.cursor()
if orig_username is not '':
cursor.execute('SELECT category,subclass FROM gpclasses WHERE accs LIKE %s', ('%'+orig_username+'%',))
gp_sql = cursor.fetchall()
for i in gp_sql:
cursor.execute('SELECT dow,period FROM schedule WHERE teacher=%s', (i[0], ))
tmp_sql = cursor.fetchall()
for j in tmp_sql:
if j[0] not in data:
data[j[0]] = {}
data[j[0]][j[1]] = {
'subject': i[0],
'class': i[1]
}
cursor.execute("SELECT dow,period,subject,grade,class_ FROM schedule WHERE teacher=%s", (teacher_name, ))
sql = cursor.fetchall()
# loop over data
for i in sql:
if i[0] not in data:
data[i[0]] = {}
data[i[0]][i[1]] = {
'subject': i[2],
'class': str(i[3]) + str(i[4])
}
periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9']
times = {
'm': ['7:30', '8:10'],
'1': ['8:20', '9:05'],
'2': ['9:15', '10:00'],
'3': ['10:10', '10:55'],
'4': ['11:05', '11:50'],
'n': ['11:50', '13:05'],
'5': ['13:15', '14:00'],
'6': ['14:10', '14:55'],
'7': ['15:05', '15:50'],
'8': ['15:55', '16:40'],
'9': ['16:45', '17:30']
}
curr = 3
for p in periods:
ws.merge_cells('A' + str(curr) + ':A' + str(curr + 1))
ws.row_dimensions[curr].height = 20
ws.row_dimensions[curr + 1].height = 20
ws['A' + str(curr)] = p
ws['A' + str(curr)].font = std_font
ws['A' + str(curr)].alignment = center
ws['A' + str(curr)].border = border
ws['A' + str(curr + 1)].border = border
ws['B' + str(curr)] = times[p][0]
ws['B' + str(curr)].font = std_font
ws['B' + str(curr)].alignment = center
ws['B' + str(curr)].border = border
ws['B' + str(curr + 1)] = times[p][1]
ws['B' + str(curr + 1)].font = std_font
ws['B' + str(curr + 1)].alignment = center
ws['B' + str(curr + 1)].border = border
if p == 'm' or p == 'n':
ws.merge_cells('C' + str(curr) + ':G' + str(curr + 1))
for i in range(1, 6):
ws[chr(ord('C') + i-1) + str(curr)].font = std_font
ws[chr(ord('C') + i-1) + str(curr)].alignment = center
ws[chr(ord('C') + i-1) + str(curr)].border = border
ws[chr(ord('C') + i-1) + str(curr + 1)].border = border
if p == 'm':
ws['C' + str(curr)] = '早自習'
else:
ws['C' + str(curr)] = '午餐 / 午休'
else:
for i in range(1, 6):
ws.merge_cells(chr(ord('C') + i-1) + str(curr) + ':' + chr(ord('C') + i-1) + str(curr + 1))
ws[chr(ord('C') + i-1) + str(curr)].font = std_font
ws[chr(ord('C') + i-1) + str(curr)].border = border
ws[chr(ord('C') + i-1) + str(curr + 1)].border = border
ws[chr(ord('C') + i-1) + str(curr)].alignment = center + Alignment(wrapText=True)
if i in data:
if p in data[i]:
ws[chr(ord('C') + i-1) + str(curr)] = (data[i][p]['subject'] + '\n' + data[i][p]['class'] if data[i][p]['subject'] != 'GP'
and data[i][p]['subject'] != '--' else '' if data[i][p]['subject'] == '--' else data[i][p]['teacher'])
curr += 2
return workbook

View file

@ -283,7 +283,6 @@ def resetPassword():
WHERE resetID = %s WHERE resetID = %s
""", (request.args.get('resetCode'),)) """, (request.args.get('resetCode'),))
user = cursor.fetchone() user = cursor.fetchone()
cursor.close()
dtnow = datetime.now(tz).replace(tzinfo=None) dtnow = datetime.now(tz).replace(tzinfo=None)
if user == None: if user == None:
raise Exception('無此重置密碼代碼<br>Invalid reset password code') raise Exception('無此重置密碼代碼<br>Invalid reset password code')

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

139
manage/admin.py Normal file
View file

@ -0,0 +1,139 @@
from functions import *
from export import *
admin = Blueprint('admin', __name__)
@admin.route('/manage/admin/mark', methods=['GET', 'POST'])
def mark_absent():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
if request.method == 'POST':
try:
data = request.form.to_dict()
periods = [i[7] for i in data if i.startswith('period-')]
db = refresh_db()
cursor = db.cursor()
for p in periods:
cursor.execute("INSERT INTO absent (grade, class_, date, period, num, status, note) VALUES (%s, %s, %s, %s, %s, %s, %s)",
(data['grade'], data['class'], data['date'], p, data['num'], data['type'], data['notes'] if 'notes' in data else ''))
db.commit()
except Exception as e:
flash(e)
else:
flash("`成功! (" + data['grade'] + data['class'] + "" + data['num'] + "號, 日期: " + data['date'] + ", 總計 " + str(len(periods)) + "堂課)")
return redirect('/manage/admin/mark')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT grade, class_, num, name FROM students ORDER BY grade,class_,num ASC")
sql = cursor.fetchall()
students = {}
for i in sql:
if i[0] not in students:
students[i[0]] = {}
if i[1] not in students[i[0]]:
students[i[0]][i[1]] = {}
students[i[0]][i[1]][i[2]] = i[3]
cursor.execute("SELECT date,period,grade,class_,num,status,note FROM absent ORDER BY id DESC LIMIT 10")
records = cursor.fetchall()
return render_template("admin_mark.html", students=students, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'], records=records, hideSel=True)
@admin.route('/manage/admin/export', methods=['GET'])
def admin_export():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
return render_template("admin_export.html", hideSel=True)
@admin.route('/manage/admin/export/homeroom_period', methods=['POST'])
def admin_export_homeroom_period():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
workbook = create_period_sheets(workbook, [request.form['grade'], request.form['class']])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='homeroom_period_' + request.form['grade'] + request.form['class'] +'.xlsx', as_attachment=True)
@admin.route('/manage/admin/export/homeroom_period/all', methods=['GET'])
def admin_export_homeroom_period_all():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT grade,class_ FROM homerooms")
homerooms = cursor.fetchall()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
for i in homerooms:
workbook = create_period_sheets(workbook, [str(i[0]), str(i[1])])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='homeroom_period_all.xlsx', as_attachment=True)
@admin.route('/manage/admin/export/student_list', methods=['POST'])
def admin_export_student_list():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
workbook = create_student_list(workbook, [request.form['grade'], request.form['class']])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='student_list_' + request.form['grade'] + request.form['class'] +'.xlsx', as_attachment=True)
@admin.route("/manage/admin/export/student_list/all", methods=['GET'])
def admin_export_student_list_all():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT grade,class_ FROM homerooms")
homerooms = cursor.fetchall()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
for i in homerooms:
workbook = create_student_list(workbook, [str(i[0]), str(i[1])])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='student_list_all.xlsx', as_attachment=True)
@admin.route('/manage/admin/export/teacher_period', methods=['POST'])
def admin_export_teacher_period():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
workbook = create_teacher_periods(workbook, request.form['name'], request.form['orig_username'])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='teacher_period_' + request.form['name'] + '_' + ('' if 'orig_username' not in request.form else request.form['orig_username']) +'.xlsx', as_attachment=True)
@admin.route('/manage/admin/export/teacher_period/all', methods=['GET'])
def admin_export_teacher_period_all():
if (check_login_status() or session['subuser_type'] != 'admin'):
return redirect('/logout')
refresh_token()
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT name,oldUsername FROM users")
teachers = cursor.fetchall()
workbook = Workbook()
workbook.remove_sheet(workbook.get_sheet_by_name('Sheet'))
for i in teachers:
workbook = create_teacher_periods(workbook, i[0], i[1])
excel_stream = io.BytesIO()
workbook.save(excel_stream)
excel_stream.seek(0)
return send_file(excel_stream, attachment_filename='teacher_period_all.xlsx', as_attachment=True)

102
manage/group.py Normal file
View file

@ -0,0 +1,102 @@
from functions import *
group = Blueprint('group', __name__)
@group.route('/manage/group_teach_publish', methods=['POST'])
def group_teach_publish():
if (check_login_status()):
return redirect('/logout')
refresh_token()
data = request.form.to_dict()
cclass = {
"category": data.pop('category'),
"class_id": data.pop('class_id')
}
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT about FROM gpclasses WHERE category=%s AND subclass=%s",
(cclass['category'], cclass['class_id']))
cclass["name"] = cursor.fetchone()[0]
cursor.execute("SELECT grade,class_,num,name,ename FROM students WHERE classes LIKE " + '\'%\"'+ cclass['category'] + '\": \"' + cclass['class_id'] +'\"%\'' + " ORDER BY grade ASC,class_ ASC,num ASC")
students = cursor.fetchall()
homerooms = []
for x in students:
if (str(x[0]) + '^' + str(x[1])) not in homerooms:
homerooms.append(str(x[0]) + '^' + str(x[1]))
data.pop('dsnumbers')
data.pop('dsoffense')
data.pop('dsoffenseother')
date = data.pop('date')
period = data.pop('period')
signature = data.pop('signatureData')
notes = data.pop('notes')
submissionType = data.pop('submissionType')
if (submissionType == 'newAbsent'):
absentData = []
for x in data:
xs = x.split('^')
if xs[0] == 'note':
continue
else:
absentData.append([xs[1], xs[2], xs[3], 'K' if xs[0] == '1' else 'L', data['note^'+xs[1]+'^'+xs[2]+'^'+xs[3]]])
for h in homerooms:
h = h.split('^')
cursor = db.cursor()
cursor.execute("""
SELECT signature, notes FROM submission WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (h[0], h[1], date, period))
one = cursor.fetchone()
if one is None:
jSignature = json.dumps({cclass['class_id']: signature})
cursor.execute("""
INSERT INTO submission (grade, class_, date, period, signature, notes)
VALUES (%s, %s, %s, %s, %s, %s)
""", (h[0], h[1], date, period, jSignature, notes))
db.commit()
else:
jSignature = json.loads(one[0])
if cclass['class_id'] in jSignature:
continue
jSignature[cclass['class_id']] = signature
note = one[1] + '; ' + notes
cursor.execute("""
UPDATE submission SET signature=%s, notes=%s WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (json.dumps(jSignature), note, h[0], h[1], date, period))
db.commit()
for a in absentData:
cursor = db.cursor()
cursor.execute("""
INSERT INTO absent (grade, class_, num, date, period, status, note)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (a[0], a[1], a[2], date, period, a[3], a[4]))
db.commit()
elif (submissionType == 'dsSubmit'):
dsData = []
for x in data:
xs = x.split('^')
if xs[0] == 'note':
continue
elif xs[0] == 'ds':
dsData.append([xs[1], xs[2].split('-')[0], xs[2].split('-')[1], data[x]])
for h in homerooms:
h = h.split('^')
cursor = db.cursor()
cursor.execute("""
SELECT dscfrm, notes FROM submission WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (h[0], h[1], date, period))
one = cursor.fetchone()
dsCfrm = [] if one[0] == None else json.loads(one[0])
if cclass['class_id'] in dsCfrm:
continue
dsCfrm.append(cclass['class_id'])
note = one[1] + '; ' + notes
cursor.execute("""
UPDATE submission SET dsCfrm=%s, notes=%s WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (json.dumps(dsCfrm), note, h[0], h[1], date, period))
for d in dsData:
cursor = db.cursor()
cursor.execute("""
INSERT INTO ds (grade, class_, num, date, period, note)
VALUES (%s, %s, %s, %s, %s, %s)
""", (d[0], d[1], d[2], date, period, d[3]))
db.commit()
return redirect('/manage')

141
manage/homeroom.py Normal file
View file

@ -0,0 +1,141 @@
from functions import *
homeroom = Blueprint('homeroom', __name__)
@homeroom.route('/manage/abs', methods=['GET'])
def showAllAbs():
if (check_login_status()):
return redirect('/logout')
refresh_token()
currRoom = session['homeroom'].split('^')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT num,name,ename FROM students WHERE grade=%s AND class_=%s ORDER BY num ASC", (currRoom[0], currRoom[1]))
studentsSQL = cursor.fetchall()
students = {}
for st in studentsSQL:
students[st[0]] = {
'name': st[1],
'ename': st[2],
}
cursor = db.cursor()
cursor.execute("SELECT date, period, num, status, note FROM absent WHERE grade=%s AND class_=%s ORDER BY date DESC, FIND_IN_SET(period, 'm,1,2,3,4,n,5,6,7,8,9') DESC, num ASC", (currRoom[0], currRoom[1]))
absentDataSQL = cursor.fetchall()
return render_template("list.html", title="Absent List | 缺勤紀錄", mode='ABS', students=students, data=absentDataSQL, currRoom=currRoom)
@homeroom.route('/manage/ds', methods=['GET'])
def showAllDS():
if (check_login_status()):
return redirect('/logout')
refresh_token()
currRoom = session['homeroom'].split('^')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT num,name,ename FROM students WHERE grade=%s AND class_=%s ORDER BY num ASC", (currRoom[0], currRoom[1]))
studentsSQL = cursor.fetchall()
students = {}
for st in studentsSQL:
students[st[0]] = {
'name': st[1],
'ename': st[2],
}
cursor = db.cursor()
cursor.execute("SELECT date, period, num, note FROM ds WHERE grade=%s AND class_=%s ORDER BY date DESC, FIND_IN_SET(period, 'm,1,2,3,4,n,5,6,7,8,9') DESC, num ASC", (currRoom[0], currRoom[1]))
dsDataSQL = cursor.fetchall()
return render_template("list.html", title="DS List | 定心紀錄", mode='DS', students=students, data=dsDataSQL, currRoom=currRoom)
@homeroom.route('/manage/homeroom_abs', methods=['POST'])
def homeroom_abs_publish():
if (check_login_status()):
return redirect('/logout')
refresh_token()
db = refresh_db()
data = request.form.to_dict()
date = data.pop('date')
period = data.pop('period')
signature = data.pop('signatureData')
notes = data.pop('notes')
homeroom = data.pop('homeroom').split('^')
absentData = {}
for x in data:
xt = x.split('^')
if (xt[0] == 'note'):
if xt[2] not in absentData:
absentData[xt[2]] = {}
absentData[xt[2]]['note'] = data[x]
else:
if xt[1] not in absentData:
absentData[xt[1]] = {}
absentData[xt[1]]['status'] = 'L' if x[0] == '2' else 'K'
cursor = db.cursor()
cursor.execute("""
INSERT INTO submission
(grade, class_, date, period, signature, notes)
VALUES (%s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, signature, notes))
for x in absentData:
cursor.execute("""
INSERT INTO absent
(grade, class_, date, period, num, status, note)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, x, absentData[x]['status'], absentData[x]['note'] if 'note' in absentData[x] else ''))
db.commit()
return redirect('/manage')
@homeroom.route('/manage/homeroom_ds', methods=['POST'])
def homeroom_ds_publish():
if (check_login_status()):
return redirect('/logout')
refresh_token()
db = refresh_db()
cursor = db.cursor()
data = request.form.to_dict()
print(data)
date = data.pop('date')
period = data.pop('period')
notes = ';' + data.pop('notes')
homeroom = data.pop('homeroom').split('^')
dsidv = {}
ds1 = data.pop('ds^1')
ds2 = data.pop('ds^2')
ds3 = data.pop('ds^3')
ds4 = data.pop('ds^4')
ds5 = data.pop('ds^5')
ds6 = data.pop('ds^6')
ds7 = data.pop('ds^7')
cursor.execute("""
UPDATE submission
SET ds1=%s,ds2=%s,ds3=%s,ds4=%s,ds5=%s,ds6=%s,ds7=%s,notes=concat(ifnull(notes,""), %s),dscfrm='yes'
WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (ds1, ds2, ds3, ds4, ds5, ds6, ds7, notes, homeroom[0], homeroom[1], date, period))
for x in data:
xt = x.split('^')
if (xt[0] == 'dsidv'):
dsidv[xt[1]] = data[x]
for x in dsidv:
cursor.execute("""
INSERT INTO ds
(grade, class_, date, period, num, note)
VALUES (%s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, x, dsidv[x]))
db.commit()
return redirect('/manage')
@homeroom.route('/manage/homeroom_confirm', methods=['POST'])
def homeroom_confirm():
if (check_login_status()):
return redirect('/logout')
refresh_token()
data = request.form.to_dict()
homeroom = data.pop('homeroom').split('^')
date = data.pop('date')
signature = data.pop('signatureData')
notes = data.pop('notes')
db = refresh_db()
cursor = db.cursor()
cursor.execute("""
INSERT INTO submission
(grade, class_, date, period, signature, notes)
VALUES (%s, %s, %s, 'c', %s, %s)
""", (homeroom[0], homeroom[1], date, signature, notes))
db.commit()
return redirect('/manage')

View file

@ -1,6 +1,29 @@
from functions import * from functions import *
from manage.homeroom import homeroom
from manage.student import student
from manage.admin import admin
from manage.group import group
manage = Blueprint('manage', __name__) manage = Blueprint('manage', __name__)
manage.register_blueprint(homeroom)
manage.register_blueprint(student)
manage.register_blueprint(admin)
manage.register_blueprint(group)
@manage.route('/manage', methods=['GET'])
def manageRoot():
return manageProcess("", "")
@homeroom.route('/manage/date/<date>', methods=['GET'])
def manage_date(date):
return manageProcess("date", date)
@manage.route('/manage/admin/<g>/<r>/<date>', methods=['GET'])
def manage_admin(g, r, date):
data = [
g + '^' + r,
date
]
return manageProcess("admin", data)
def manageProcess(fCommand, fData): def manageProcess(fCommand, fData):
@ -182,14 +205,9 @@ def manageProcess(fCommand, fData):
if (h not in data[cclass['category'] + ' ' + cclass['class_id']][p[0]]): if (h not in data[cclass['category'] + ' ' + cclass['class_id']][p[0]]):
data[cclass['category'] + ' ' + cclass['class_id']][p[0]][h] = {} data[cclass['category'] + ' ' + cclass['class_id']][p[0]][h] = {}
cursor = db.cursor() cursor = db.cursor()
cursor.execute("SELECT signature FROM submission WHERE grade=%s AND class_=%s AND date=%s AND period=%s", (hs[0], hs[1], currDate, p[0])) cursor.execute("SELECT signature, dscfrm FROM submission WHERE grade=%s AND class_=%s AND date=%s AND period=%s", (hs[0], hs[1], currDate, p[0]))
submissionSQL = cursor.fetchone() submissionSQL = cursor.fetchone()
submitted = False submitted = False
try:
if submissionSQL[0] == 'STUD_AFFAIR_OFFICE':
submitted = True
except:
pass
try: try:
signatures = json.loads(submissionSQL[0]) signatures = json.loads(submissionSQL[0])
if cclass['class_id'] in signatures: if cclass['class_id'] in signatures:
@ -226,6 +244,7 @@ def manageProcess(fCommand, fData):
"ename": x[4], "ename": x[4],
"status": status, "status": status,
"note": '' if studStatus == [] else studStatus[0][2], "note": '' if studStatus == [] else studStatus[0][2],
"needDS": False if hrCfrm != True and submissionSQL[1] != None and cclass['class_id'] in json.loads(submissionSQL[1]) else True
} }
return render_template('group_teach.html', dates=dates, currDate=currDate, data=data, dsoffenses=DSOFFENSES) return render_template('group_teach.html', dates=dates, currDate=currDate, data=data, dsoffenses=DSOFFENSES)
elif pl == 'homeroom': elif pl == 'homeroom':
@ -291,7 +310,7 @@ def manageProcess(fCommand, fData):
"special": True "special": True
} }
cursor = db.cursor() cursor = db.cursor()
cursor.execute("SELECT period, signature, notes, ds1,ds2,ds3,ds4,ds5,ds6,ds7 FROM submission WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate)) cursor.execute("SELECT period, signature, notes, ds1,ds2,ds3,ds4,ds5,ds6,ds7, dscfrm FROM submission WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate))
submissionSQL = cursor.fetchall() submissionSQL = cursor.fetchall()
cursor = db.cursor() cursor = db.cursor()
cursor.execute("SELECT period, num, note FROM ds WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate)) cursor.execute("SELECT period, num, note FROM ds WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate))
@ -328,6 +347,8 @@ def manageProcess(fCommand, fData):
"ds6": i[8], "ds6": i[8],
"ds7": i[9], "ds7": i[9],
} }
if i[10] == 'yes':
submission[i[0]]["dscfrm"] = True
cursor = db.cursor() cursor = db.cursor()
cursor.execute("SELECT period, num, status, note FROM absent WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate)) cursor.execute("SELECT period, num, status, note FROM absent WHERE grade=%s AND class_=%s AND date=%s", (currRoom[0], currRoom[1], currDate))
absentDataSQL = cursor.fetchall() absentDataSQL = cursor.fetchall()
@ -343,254 +364,3 @@ def manageProcess(fCommand, fData):
dates=dates, absentData=absentData, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'], dsboard=DSBOARD, dstext=DSTEXT, dsoffenses=DSOFFENSES, idvDS=idvDS) dates=dates, absentData=absentData, periods=['m', '1', '2', '3', '4', 'n', '5', '6', '7', '8', '9'], dsboard=DSBOARD, dstext=DSTEXT, dsoffenses=DSOFFENSES, idvDS=idvDS)
else: else:
return redirect('/logout') return redirect('/logout')
@manage.route('/manage', methods=['GET'])
def manageRoot():
return manageProcess("", "")
@manage.route('/manage/date/<date>', methods=['GET'])
def manage_date(date):
return manageProcess("date", date)
@manage.route('/manage/admin/<g>/<r>/<date>', methods=['GET'])
def manage_admin(g, r, date):
data = [
g + '^' + r,
date
]
return manageProcess("admin", data)
@manage.route('/student', methods=['GET'])
def showStudentAbs():
if (check_login_status()):
return redirect('/logout')
refresh_token()
if not ('user_type' in session and session['user_type'] == 'student'):
return redirect('/')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT date, period, num, status, note FROM absent WHERE grade=%s AND class_=%s AND num=%s ORDER BY date DESC, period DESC, num ASC", (session['grade'], session['class'], session['num']))
absentDataSQL = cursor.fetchall()
return render_template("list.html", title="Student Absent List | 學生缺勤紀錄", mode='STUDABS', data=absentDataSQL, currRoom=[session['grade'],session['class']], name=session['name'], num=session['num'])
@manage.route('/student/ds', methods=['GET'])
def showStudentDS():
if (check_login_status()):
return redirect('/logout')
refresh_token()
if not ('user_type' in session and session['user_type'] == 'student'):
return redirect('/')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT date, period, num, note FROM ds WHERE grade=%s AND class_=%s AND num=%s ORDER BY date DESC, period DESC, num ASC", (session['grade'], session['class'], session['num']))
dsDataSQL = cursor.fetchall()
print(dsDataSQL)
return render_template("list.html", title="Student DS List | 學生定心紀錄", mode='STUDDS', data=dsDataSQL, currRoom=[session['grade'],session['class']], name=session['name'], num=session['num'])
@manage.route('/manage/abs', methods=['GET'])
def showAllAbs():
if (check_login_status()):
return redirect('/logout')
refresh_token()
currRoom = session['homeroom'].split('^')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT num,name,ename FROM students WHERE grade=%s AND class_=%s ORDER BY num ASC", (currRoom[0], currRoom[1]))
studentsSQL = cursor.fetchall()
students = {}
for st in studentsSQL:
students[st[0]] = {
'name': st[1],
'ename': st[2],
}
cursor = db.cursor()
cursor.execute("SELECT date, period, num, status, note FROM absent WHERE grade=%s AND class_=%s ORDER BY date DESC, period DESC, num ASC", (currRoom[0], currRoom[1]))
absentDataSQL = cursor.fetchall()
return render_template("list.html", title="Absent List | 缺勤紀錄", mode='ABS', students=students, data=absentDataSQL, currRoom=currRoom)
@manage.route('/manage/ds', methods=['GET'])
def showAllDS():
if (check_login_status()):
return redirect('/logout')
refresh_token()
currRoom = session['homeroom'].split('^')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT num,name,ename FROM students WHERE grade=%s AND class_=%s ORDER BY num ASC", (currRoom[0], currRoom[1]))
studentsSQL = cursor.fetchall()
students = {}
for st in studentsSQL:
students[st[0]] = {
'name': st[1],
'ename': st[2],
}
cursor = db.cursor()
cursor.execute("SELECT date, period, num, note FROM ds WHERE grade=%s AND class_=%s ORDER BY date DESC, period DESC, num ASC", (currRoom[0], currRoom[1]))
dsDataSQL = cursor.fetchall()
return render_template("list.html", title="DS List | 定心紀錄", mode='DS', students=students, data=dsDataSQL, currRoom=currRoom)
@manage.route('/manage/group_teach_publish', methods=['POST'])
def group_teach_publish():
if (check_login_status()):
return redirect('/logout')
refresh_token()
data = request.form.to_dict()
cclass = {
"category": data.pop('category'),
"class_id": data.pop('class_id')
}
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT about FROM gpclasses WHERE category=%s AND subclass=%s",
(cclass['category'], cclass['class_id']))
cclass["name"] = cursor.fetchone()[0]
cursor.execute("SELECT grade,class_,num,name,ename FROM students WHERE classes LIKE " + '\'%\"'+ cclass['category'] + '\": \"' + cclass['class_id'] +'\"%\'' + " ORDER BY grade ASC,class_ ASC,num ASC")
students = cursor.fetchall()
homerooms = []
for x in students:
if (str(x[0]) + '^' + str(x[1])) not in homerooms:
homerooms.append(str(x[0]) + '^' + str(x[1]))
data.pop('dsnumbers')
data.pop('dsoffense')
data.pop('dsoffenseother')
date = data.pop('date')
period = data.pop('period')
signature = data.pop('signatureData')
notes = data.pop('notes')
absentData = []
dsData = []
for x in data:
xs = x.split('^')
if xs[0] == 'note':
continue
elif xs[0] == 'ds':
dsData.append([xs[1], xs[2].split('-')[0], xs[2].split('-')[1], data[x]])
else:
absentData.append([xs[1], xs[2], xs[3], 'K' if xs[0] == '1' else 'L', data['note^'+xs[1]+'^'+xs[2]+'^'+xs[3]]])
for h in homerooms:
h = h.split('^')
cursor = db.cursor()
cursor.execute("""
SELECT signature, notes FROM submission WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (h[0], h[1], date, period))
one = cursor.fetchone()
if one is None:
jSignature = json.dumps({cclass['class_id']: signature})
cursor.execute("""
INSERT INTO submission (grade, class_, date, period, signature, notes)
VALUES (%s, %s, %s, %s, %s, %s)
""", (h[0], h[1], date, period, jSignature, notes))
db.commit()
else:
jSignature = json.loads(one[0])
if cclass['class_id'] in jSignature:
continue
jSignature[cclass['class_id']] = signature
note = one[1] + '; ' + notes
cursor.execute("""
UPDATE submission SET signature=%s, notes=%s WHERE grade=%s AND class_=%s AND date=%s AND period=%s
""", (json.dumps(jSignature), note, h[0], h[1], date, period))
db.commit()
for d in dsData:
cursor = db.cursor()
cursor.execute("""
INSERT INTO ds (grade, class_, num, date, period, note)
VALUES (%s, %s, %s, %s, %s, %s)
""", (d[0], d[1], d[2], date, period, d[3]))
db.commit()
for a in absentData:
cursor = db.cursor()
cursor.execute("""
INSERT INTO absent (grade, class_, num, date, period, status, note)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (a[0], a[1], a[2], date, period, a[3], a[4]))
db.commit()
return redirect('/manage')
@manage.route('/manage/homeroom_abs', methods=['POST'])
def homeroom_abs_publish():
if (check_login_status()):
return redirect('/logout')
refresh_token()
db = refresh_db()
data = request.form.to_dict()
date = data.pop('date')
period = data.pop('period')
signature = data.pop('signatureData')
notes = data.pop('notes')
homeroom = data.pop('homeroom').split('^')
ds1 = data.pop('ds^1')
ds2 = data.pop('ds^2')
ds3 = data.pop('ds^3')
ds4 = data.pop('ds^4')
ds5 = data.pop('ds^5')
ds6 = data.pop('ds^6')
ds7 = data.pop('ds^7')
# 2: L / 1: K
absentData = {}
dsidv = {}
for x in data:
xt = x.split('^')
if (xt[0] == 'note'):
if xt[2] not in absentData:
absentData[xt[2]] = {}
absentData[xt[2]]['note'] = data[x]
elif (xt[0] == 'dsidv'):
dsidv[xt[1]] = data[x]
else:
if xt[1] not in absentData:
absentData[xt[1]] = {}
absentData[xt[1]]['status'] = 'L' if x[0] == '2' else 'K'
cursor = db.cursor()
cursor.execute("""
INSERT INTO submission
(grade, class_, date, period, signature, ds1, ds2, ds3, ds4, ds5, ds6, ds7, notes)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, signature, ds1, ds2, ds3, ds4, ds5, ds6, ds7, notes))
for x in absentData:
cursor.execute("""
INSERT INTO absent
(grade, class_, date, period, num, status, note)
VALUES (%s, %s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, x, absentData[x]['status'], absentData[x]['note']))
for x in dsidv:
cursor.execute("""
INSERT INTO ds
(grade, class_, date, period, num, note)
VALUES (%s, %s, %s, %s, %s, %s)
""", (homeroom[0], homeroom[1], date, period, x, dsidv[x]))
db.commit()
return redirect('/manage')
@manage.route('/manage/edit_abs', methods=['POST'])
def edit_abs():
if (check_login_status() or not check_permission()):
return redirect('/logout')
refresh_token()
data = request.form.to_dict()
print(data)
return ""
@manage.route('/manage/homeroom_confirm', methods=['POST'])
def homeroom_confirm():
if (check_login_status()):
return redirect('/logout')
refresh_token()
data = request.form.to_dict()
homeroom = data.pop('homeroom').split('^')
date = data.pop('date')
signature = data.pop('signatureData')
notes = data.pop('notes')
db = refresh_db()
cursor = db.cursor()
cursor.execute("""
INSERT INTO submission
(grade, class_, date, period, signature, notes)
VALUES (%s, %s, %s, 'c', %s, %s)
""", (homeroom[0], homeroom[1], date, signature, notes))
db.commit()
return redirect('/manage')

30
manage/student.py Normal file
View file

@ -0,0 +1,30 @@
from functions import *
student = Blueprint('student', __name__)
@student.route('/student', methods=['GET'])
def showStudentAbs():
if (check_login_status()):
return redirect('/logout')
refresh_token()
if not ('user_type' in session and session['user_type'] == 'student'):
return redirect('/')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT date, period, num, status, note FROM absent WHERE grade=%s AND class_=%s AND num=%s ORDER BY date DESC, FIND_IN_SET(period, 'm,1,2,3,4,n,5,6,7,8,9') DESC, num ASC", (session['grade'], session['class'], session['num']))
absentDataSQL = cursor.fetchall()
return render_template("list.html", title="Student Absent List | 學生缺勤紀錄", mode='STUDABS', data=absentDataSQL, currRoom=[session['grade'],session['class']], name=session['name'], num=session['num'])
@student.route('/student/ds', methods=['GET'])
def showStudentDS():
if (check_login_status()):
return redirect('/logout')
refresh_token()
if not ('user_type' in session and session['user_type'] == 'student'):
return redirect('/')
db = refresh_db()
cursor = db.cursor()
cursor.execute("SELECT date, period, num, note FROM ds WHERE grade=%s AND class_=%s AND num=%s ORDER BY date DESC, FIND_IN_SET(period, 'm,1,2,3,4,n,5,6,7,8,9') DESC, num ASC", (session['grade'], session['class'], session['num']))
dsDataSQL = cursor.fetchall()
print(dsDataSQL)
return render_template("list.html", title="Student DS List | 學生定心紀錄", mode='STUDDS', data=dsDataSQL, currRoom=[session['grade'],session['class']], name=session['name'], num=session['num'])

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

View file

@ -76,3 +76,50 @@ function submitForm() {
$('.container').hide(); $('.container').hide();
$('#loading').show(); $('#loading').show();
} }
function refresh_homeroom() {
var grade = $('#grade').val();
$('#class').html('<option value="">請先選擇年級</option>');
$('span#name').html = ""
if (grade === "") {
$('#class').attr('disabled', 'disabled')
return
}
// get keys in dict
var keys = Object.keys(students[grade]);
keys.forEach(element => {
$('#class').append(`<option value="${element}">${element}</option>`)
});
$('#class').removeAttr('disabled')
}
function refresh_numbers() {
var grade = $('#grade').val();
var class_ = $('#class').val();
$('span#name').html = ""
$('#number').html('<option value="">請先選擇年級、班級</option>');
if (grade === "") {
$('#class').attr('disabled', 'disabled')
if (clas_ !== "") return
} if (class_ === "") {
$('#number').attr('disabled', 'disabled')
return
}
// get keys in dict
var keys = Object.keys(students[grade][class_]);
keys.forEach(element => {
$('#number').append(`<option value="${element}">${element}</option>`)
});
$('#number').removeAttr('disabled')
}
function showName() {
var grade = $('#grade').val();
var class_ = $('#class').val();
var number = $('#number').val();
$('#name').html(students[grade][class_][number]);
}
function clearForm() {
document.getElementById('newabs').reset();
$('#class').attr('disabled', 'disabled')
$('#number').attr('disabled', 'disabled')
$('span#name').html = ""
}

View file

@ -2,13 +2,6 @@ var signaturePad, selPeriod, canvas, width = $(window).width(), modal;
var indDS = {}; var indDS = {};
function submitForm() { function submitForm() {
if (!signaturePad.isEmpty()) { if (!signaturePad.isEmpty()) {
for (var i in indDS) {
var tmp = document.createElement('input');
tmp.type = 'hidden';
tmp.name = 'ds^' + i;
tmp.value = indDS[i];
document.getElementById('attendanceData^' + selPeriod).appendChild(tmp);
}
$('#' + modal).modal('hide'); $('#' + modal).modal('hide');
loadingAnimation(); loadingAnimation();
signaturePad.off(); signaturePad.off();
@ -20,6 +13,18 @@ function submitForm() {
alert("Please sign first"); alert("Please sign first");
} }
} }
function submitDSForm() {
for (var i in indDS) {
var tmp = document.createElement('input');
tmp.type = 'hidden';
tmp.name = 'ds^' + i;
tmp.value = indDS[i];
document.getElementById('attendanceData^' + selPeriod).appendChild(tmp);
}
$('#' + modal).modal('hide');
loadingAnimation();
document.getElementById("attendanceData^" + selPeriod).submit();
}
function resizeCanvas() { function resizeCanvas() {
var ratio = Math.max(window.devicePixelRatio || 1, 1); var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio; canvas.width = canvas.offsetWidth * ratio;
@ -29,8 +34,7 @@ function resizeCanvas() {
} }
function viewSignature(period) { function viewSignature(period) {
selPeriod = period selPeriod = period
$('.viewSignatureBtn').attr({ 'disabled': 'disabled' }); document.getElementById("attendanceData^" + selPeriod).getElementsByClassName("submissionType")[0].value = "newAbsent";
$('.viewSignatureBtn').removeClass('margin-bottom');
modal = 'sign-' + period; modal = 'sign-' + period;
$('#' + modal).modal('show'); $('#' + modal).modal('show');
var cnt = 0; var cnt = 0;
@ -58,6 +62,12 @@ function viewSignature(period) {
}); });
resizeCanvas(); resizeCanvas();
} }
function signDS(period) {
selPeriod = period
document.getElementById("attendanceData^" + selPeriod).getElementsByClassName("submissionType")[0].value = "dsSubmit";
modal = 'ds-' + period;
$('#' + modal).modal('show');
}
function unCheckLate(string) { function unCheckLate(string) {
document.getElementById('late^' + string).checked = false; document.getElementById('late^' + string).checked = false;
strForNote = string.substring(string.indexOf("^") + 1); strForNote = string.substring(string.indexOf("^") + 1);

View file

@ -26,11 +26,6 @@ function submitForm() {
document.getElementById('homeroom_confirm').submit() document.getElementById('homeroom_confirm').submit()
} else { } else {
var notes = $('#subjectNotes').val(); var notes = $('#subjectNotes').val();
for (var i = 0; i < 7; i++)
document.getElementById('HR-ds'+(i+1)).value = $('.dsboard input[name="ds'+(i+1)+'"]:checked').val();
for (var i in indDS) {
$('#postHomeroomAbs').append('<input type="text" name="dsidv^' + i.split('-')[0] + '" value="'+ indDS[i] +'">')
}
document.getElementById('HR-signatureData').value = data; document.getElementById('HR-signatureData').value = data;
document.getElementById('HR-notes').value = notes; document.getElementById('HR-notes').value = notes;
document.getElementById('postHomeroomAbs').submit(); document.getElementById('postHomeroomAbs').submit();
@ -40,6 +35,16 @@ function submitForm() {
alert("Please sign first"); alert("Please sign first");
} }
} }
function submitDSForm() {
for (var i = 0; i < 7; i++)
document.getElementById('DS-ds'+(i+1)).value = $('.dsboard input[name="ds'+(i+1)+'"]:checked').val();
for (var i in indDS) {
$('#postHomeroomDS').append('<input type="text" name="dsidv^' + i.split('-')[0] + '" value="'+ indDS[i] +'">')
}
$('#DS-notes').val($('input#dsNotesEnter').val());
loadingAnimation()
document.getElementById('postHomeroomDS').submit();
}
function resizeCanvas() { function resizeCanvas() {
var ratio = Math.max(window.devicePixelRatio || 1, 1); var ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio; canvas.width = canvas.offsetWidth * ratio;
@ -88,7 +93,6 @@ function afterSelAbs(period) {
} }
function homeroomCfrm() { function homeroomCfrm() {
hrCfrm = true; hrCfrm = true;
$('.ds').attr('hidden', 'hidden');
$('#showSignPeriod').text("HOMEROOM CONFIRM"); $('#showSignPeriod').text("HOMEROOM CONFIRM");
$('#showSignSubjectName').text("班導確認"); $('#showSignSubjectName').text("班導確認");
$('.tobeform').attr('disabled', 'disabled'); $('.tobeform').attr('disabled', 'disabled');
@ -126,3 +130,7 @@ function addDS() {
$('#dsoffensesel').val(""); $('#dsoffensesel').val("");
$('#dsnumbersel').val(""); $('#dsnumbersel').val("");
} }
function showSelDS(period) {
$('#DS-period').val(period)
$('#dsCheck').modal('show');
}

View file

@ -1 +0,0 @@
this is just so that /temp doesn't disappear

View file

@ -70,8 +70,7 @@
<div class="col view-{{j}}"> <div class="col view-{{j}}">
{% if schedule[j]['subject'] == 'GP' %} {% if schedule[j]['subject'] == 'GP' %}
{% for k in submission[j] %} {% for k in submission[j] %}
{% if studGP[i[0]][schedule[j]['teacher']] == k %} {% if k!='notes' and i[0] in absentData[j] %}
{% if i[0] in absentData[j] %}
{% if absentData[j][i[0]]['status'] == 'L' %} {% if absentData[j][i[0]]['status'] == 'L' %}
<p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p> <p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p>
{% elif absentData[j][i[0]]['status'] == 'K' %} {% elif absentData[j][i[0]]['status'] == 'K' %}
@ -90,18 +89,16 @@
<p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p> <p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p>
{% endif %} {% endif %}
<p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p> <p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p>
{% else %} {% elif studGP[i[0]][schedule[j]['teacher']] == k %}
<p class="highlightAbs n-1 view-n-{{i[0]}}">V</p> <p class="highlightAbs n-1 view-n-{{i[0]}}">V</p>
{% if j in idvDS and i[0] in idvDS[j] %} {% if j in idvDS and i[0] in idvDS[j] %}
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p> <p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
{% endif %} {% endif %}
{% endif %}
{% else %} {% else %}
<p class="highlightAbs view-n-{{i[0]}}"></p> <p class="highlightAbs view-n-{{i[0]}}"></p>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{% else %} {% else %}
{% if j in submission %}
{% if i[0] in absentData[j] %} {% if i[0] in absentData[j] %}
{% if absentData[j][i[0]]['status'] == 'L' %} {% if absentData[j][i[0]]['status'] == 'L' %}
<p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p> <p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p>
@ -121,15 +118,14 @@
<p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p> <p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p>
{% endif %} {% endif %}
<p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p> <p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p>
{% else %} {% elif j in submission %}
<p class="highlightAbs n-1 view-n-{{i[0]}}">V</p> <p class="highlightAbs n-1 view-n-{{i[0]}}">V</p>
{% if j in idvDS and i[0] in idvDS[j] %}
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
{% endif %}
{% endif %}
{% else %} {% else %}
<p class="highlightAbs view-n-{{i[0]}}"></p> <p class="highlightAbs view-n-{{i[0]}}"></p>
{% endif %} {% endif %}
{% if j in idvDS and i[0] in idvDS[j] %}
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
{% endif %}
{% endif %} {% endif %}
</div> </div>
{% endfor %} {% endfor %}
@ -201,34 +197,12 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% if showUpload == '1' %} {% include 'footer.html' %}
<div class="row margin-top">
<div class="col">
<h3 style="color: red;">此排 [請勿] 隨意點選</h3>
</div>
<div class="col">
<a href="/upload/1"><button class="btn btn-danger">1. Add Homeroom</button></a>
</div>
<div class="col">
<a href="/upload/2"><button class="btn btn-danger">2. Add GP Classes</button></a>
</div>
<div class="col">
<a href="/upload/3"><button class="btn btn-danger">3. Add GP Student List</button></a>
</div>
<div class="col">
<a href="/upload/4"><button class="btn btn-danger">4. Period List</button></a>
</div>
<div class="col">
<a href="/upload/dates"><button class="btn btn-warning">[WEEKLY] Dates</button></a>
</div>
</div>
{% endif %}
</div> </div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
{% include 'footer.html' %}
<script> <script>
var homerooms = {}; var homerooms = {};
{% for i in homerooms %} {% for i in homerooms %}
@ -241,5 +215,4 @@
<script src="/static/pagejs/admin.js"></script> <script src="/static/pagejs/admin.js"></script>
<script src="/static/time.js"></script> <script src="/static/time.js"></script>
</body> </body>
</html> </html>

View file

@ -0,0 +1,92 @@
<!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 管理員 - Attendance 點名</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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="/static/allpages.css">
<link rel="stylesheet" href="/static/homeroom.css">
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
<script src="/static/gtag.js"></script>
</head>
<body>
<div class="showTime"><span id="showTime"></span></div>
{% include 'sidebar.html' %}
<style>
.col-1 label {
margin-top: 8px;
}
.reqpadding {
padding: 20px;
border: 3px solid black;
margin: 6px;
}
</style>
<div class="container">
<h1 class="margin-top">Export | 匯出資料</h1>
<div class="row">
<div class="col reqpadding">
<h2>班級課表</h2>
<form action="/manage/admin/export/homeroom_period" method="post">
<div class="form-group row">
<label for="grade">年級</label>
<input type="text" name="grade" id="grade" class="form-control" required>
</div>
<div class="form-group row">
<label for="class">班級</label>
<input type="text" name="class" id="class" class="form-control" required>
</div>
<button class="btn btn-primary">確認</button>
<a href="/manage/admin/export/homeroom_period/all"><button type="button" class="btn btn-secondary">匯出所有班級</button></a>
</form>
</div>
<div class="col reqpadding">
<h2>學生名單</h2>
<form action="/manage/admin/export/student_list" method="post">
<div class="form-group row">
<label for="grade">年級</label>
<input type="text" name="grade" id="grade" class="form-control" required>
</div>
<div class="form-group row">
<label for="class">班級</label>
<input type="text" name="class" id="class" class="form-control" required>
</div>
<button class="btn btn-primary">確認</button>
<a href="/manage/admin/export/student_list/all"><button type="button" class="btn btn-secondary">匯出所有班級</button></a>
</form>
</div>
<div class="col reqpadding">
<h2>老師課表</h2>
<form action="/manage/admin/export/teacher_period" method="post">
<div class="form-group row">
<label for="name">老師姓名</label>
<input type="text" name="name" id="name" class="form-control" required>
</div>
<div class="form-group row">
<label for="orig_username">老師原始帳號</label>
<input type="text" name="orig_username" id="orig_username" class="form-control">
</div>
<button class="btn btn-primary">確認</button>
<a href="/manage/admin/export/teacher_period/all"><button type="button" class="btn btn-secondary">匯出所有老師</button></a>
</form>
</div>
</div>
{% include 'footer.html' %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="/static/pagejs/admin.js"></script>
<script src="/static/time.js"></script>
</body>
</html>

178
templates/admin_mark.html Normal file
View file

@ -0,0 +1,178 @@
<!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 管理員 - Attendance 點名</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="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="/static/allpages.css">
<link rel="stylesheet" href="/static/homeroom.css">
<link rel="shortcut icon" type="image/x-icon" href="/static/favicon.ico" />
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-H6D61RSBHR"></script>
<script src="/static/gtag.js"></script>
</head>
<body>
<div class="showTime"><span id="showTime"></span></div>
{% include 'sidebar.html' %}
<style>
.row .col {
padding: 10px;
}
.row.border .col {
border: 1px solid black;
padding: 0;
}
.row.border {
border: 0 !important;
}
</style>
<div class="container">
<h1 class="margin-top">Mark Absent | 新增請假</h1>
<form action="/manage/admin/mark" id="newabs" method="POST">
<div class="row">
<div class="col col-3">
<div class="form-group">
<label for="date">日期</label>
<input name="date" type="date" class="form-control" id="date" value="{{ date }}" required>
</div>
</div>
<div class="col-5" style="margin-top: 40px;">
<div class="form-group checkbox-group">
<label for="period">節次</label>
{% for p in periods %}
<div class="form-check-inline">
<input name="period-{{p}}" class="form-check-input" type="checkbox" value="1" id="period-{{p}}">
<label class="form-check-label" for="period{{p}}">{{p}}</label>
</div>
{% endfor %}
</div>
</div>
<div class="col col-2">
<div class="form-group">
<label for="type">假別</label>
<select name="type" class="form-select" id="type" onchange="refresh_homeroom()" required>
<option value="G">事假</option>
<option value="S">病假</option>
<option value="F">喪假</option>
<option value="P">疫情假</option>
<option value="O">公假</option>
</select>
</div>
</div>
<div class="col col-2">
<div class="form-group">
<label for="notes">備註</label>
<input name="notes" type="text" class="form-control" id="notes" placeholder="備註">
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="form-group">
<label for="grade">年級</label>
<select name="grade" class="form-select" id="grade" onchange="refresh_homeroom()" required>
<option value="">請選擇...</option>
{% for c in students %}
<option value="{{c}}">{{c}}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label name="class" for="class">班級</label>
<select name="class" class="form-select" id="class" onchange="refresh_numbers()" disabled="disabled" required>
<option value="">請先選擇年級</option>
</select>
</div>
</div>
<div class="col">
<div class="form-group">
<label for="number">座號</label>
<select name="num" class="form-select" id="number" onchange="showName()" disabled="disabled" required>
<option value="">請先選擇年級、班級</option>
</select>
</div>
</div>
<div class="col-1" style="margin-top: 40px;"><span id="name"></span></div>
<div class="col col-1" style="margin-top: 15px;"><button class="btn btn-secondary" type="button" onclick="clearForm();">清除</button></div>
<div class="col col-1" style="margin-top: 15px;"><button class="btn btn-primary" type="submit">確認送出</button></div>
</div>
</form>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
{% if message[0] == '`' %}
<div class="alert alert-success" role="alert">
{% autoescape false %}{{message[1:]}}{% endautoescape %}
</div>
{% else %}
<div class="alert alert-danger" role="alert">
{% autoescape false %}{{message[1:]}}{% endautoescape %}
</div>
{% endif %}
{% endfor %}
{% endif %}
{% endwith %}
<br>
<h2>最新 10 筆資料 (完整資料請到 <a href="/admin/absent">這裡</a>)</h2>
<div class="row border">
<div class="col">日期</div>
<div class="col">節次</div>
<div class="col">班級</div>
<div class="col">座號</div>
<div class="col">姓名</div>
<div class="col">假別</div>
<div class="col">備註</div>
</div>
{% for r in records %}
<div class="row border">
<div class="col">{{r[0]}}</div>
<div class="col">{{r[1]}}</div>
<div class="col">{{r[2]}}{{r[3]}}</div>
<div class="col">{{r[4]}}</div>
<div class="col">{{students[r[2]][r[3]][r[4]]}}</div>
<div class="col">
{% if r[5] == 'L' %}遲到{% endif %}
{% if r[5] == 'K' %}曠課{% endif %}
{% if r[5] == 'G' %}事假{% endif %}
{% if r[5] == 'S' %}病假{% endif %}
{% if r[5] == 'F' %}喪假{% endif %}
{% if r[5] == 'P' %}疫情假{% endif %}
{% if r[5] == 'O' %}公假{% endif %}
</div>
<div class="col">{{r[6]}}</div>
</div>
{% endfor %}
{% include 'footer.html' %}
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
var students = {};
var homerooms = [];
{% for i in students %}
students['{{i}}'] = {};
homerooms['{{i}}'] = [];
{% for j in students[i] %}
students['{{i}}']['{{j}}'] = {};
homerooms['{{i}}'].push({{j}});
{% for k in students[i][j] %}
students['{{i}}']['{{j}}']['{{k}}'] = '{{students[i][j][k]}}';
{% endfor %}
{% endfor %}
{% endfor %}
</script>
<script src="/static/pagejs/admin.js"></script>
<script src="/static/time.js"></script>
</body>
</html>

View file

@ -47,6 +47,7 @@
<input type="hidden" class="signatureData" name="signatureData" value=""> <input type="hidden" class="signatureData" name="signatureData" value="">
<input type="hidden" name="category" value="{{data[c]['cdata']['category']}}"> <input type="hidden" name="category" value="{{data[c]['cdata']['category']}}">
<input type="hidden" name="class_id" value="{{data[c]['cdata']['class_id']}}"> <input type="hidden" name="class_id" value="{{data[c]['cdata']['class_id']}}">
<input type="hidden" name="submissionType" class="submissionType" value="">
<div class="col" style="margin-top: 5px;"> <div class="col" style="margin-top: 5px;">
<div class="row title sticky-top" style="background-color: white"> <div class="row title sticky-top" style="background-color: white">
<div class="col">Grade 年級</div> <div class="col">Grade 年級</div>
@ -56,6 +57,7 @@
<div class="col">Period {{p}} | 第 {{p}} 節</div> <div class="col">Period {{p}} | 第 {{p}} 節</div>
</div> </div>
{% set need_fill = namespace(found=false) %} {% set need_fill = namespace(found=false) %}
{% set need_ds = namespace(found=false) %}
{% if data[c] != None %} {% if data[c] != None %}
{% for grade in data[c][p] %} {% for grade in data[c][p] %}
{% for student in data[c][p][grade] %} {% for student in data[c][p][grade] %}
@ -113,18 +115,25 @@
onchange="unCheckLate('{{p}}^{{grade}}^{{student}}')"> onchange="unCheckLate('{{p}}^{{grade}}^{{student}}')">
</div> </div>
{% endif %} {% endif %}
{% if data[c][p][grade][student]['needDS'] == True %}
{% set need_ds.found = true %}
{% endif %}
</div> </div>
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% if not need_fill.found %} {% if need_fill.found %}
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
onclick="viewSignature('{{p}}')" disabled="disabled">
Already Submitted</button>
{% else %}
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button" <button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
onclick="viewSignature('{{p}}')"> onclick="viewSignature('{{p}}')">
↑ Confirm 確認 (Period {{p}}) ↑</button> ↑ Confirm 確認 (Period {{p}}) ↑</button>
{% elif need_ds.found %}
<button class="btn btn-warning margin-bottom viewSignatureBtn" type="button"
onclick="signDS('{{p}}')">
↑ Confirm DS 定心專案 (Period {{p}}) ↑</button>
{% else %}
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
onclick="viewSignature('{{p}}')" disabled="disabled">
Already Submitted</button>
{% endif %} {% endif %}
<div id="sign-{{p}}" class="signDiv modal fade" id="staticBackdrop" data-bs-backdrop="static" <div id="sign-{{p}}" class="signDiv modal fade" id="staticBackdrop" data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true"> data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
@ -150,15 +159,47 @@
margin-top: 0; margin-top: 0;
} }
</style> </style>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear
Signature 清除簽名</button>
<button type="button" class="btn btn-danger" onclick="location.reload();">Cancel
取消</button>
<button type="button" class="btn btn-primary submitButton" onclick="submitForm()">Submit
提交</button>
</div>
</div>
</div>
</div>
<div id="ds-{{p}}" class="signDiv modal fade" id="staticBackdrop" data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">定心專案 DS</h5>
</div>
<div class="modal-body">
<div class="ds"> <div class="ds">
<h3 class="margin-top">定心專案</h3> {% for i in range(dsboard|length) %}
<div class="row dsboard" style="width: 40%; margin-left: 30%;">
<div class="col col-4">
<span>{{dsboard[i]}}</span>
</div>
{% for j in range(6) %}
<div class="col">
<input class="form-check-input" type="radio" name="ds{{i+1}}" id="ds{{i+1}}{{j}}" value="{{j}}" {%if j==5%}checked{%endif%}>
<label class="form-check-label" for="ds{{i+1}}{{j}}">{{j}}</label>
</div>
{% endfor %}
</div>
{% endfor %}
<div id="indds" class="row margin-top" style="width: 90%; margin-left: 5%"> <div id="indds" class="row margin-top" style="width: 90%; margin-left: 5%">
<div class="col-2"> <div class="col-2">
<select class="form-select" name="dsnumbers" id="dsnumbersel"> <select class="form-select" name="dsnumbers" id="dsnumbersel">
<option value="">選擇號碼</option> <option value="">選擇號碼</option>
{% for grade in data[c][p] %} {% for grade in data[c][p] %}
{% for i in data[c][p][grade] %} {% for i in data[c][p][grade] %}
{% if data[c][p][grade][i]['status'] == 'na' %} {% if data[c][p][grade][i]['needDS'] == True %}
<option value="{{grade}}-{{i}}-{{data[c][p][grade][i]['name']}}-{{data[c][p][grade][i]['ename']}}">{{grade}}-{{i}}-{{data[c][p][grade][i]['name']}}-{{data[c][p][grade][i]['ename']}}</option> <option value="{{grade}}-{{i}}-{{data[c][p][grade][i]['name']}}-{{data[c][p][grade][i]['ename']}}">{{grade}}-{{i}}-{{data[c][p][grade][i]['name']}}-{{data[c][p][grade][i]['ename']}}</option>
{% endif %} {% endif %}
{% endfor %} {% endfor %}
@ -176,18 +217,17 @@
<div class="col-5"> <div class="col-5">
<input type="text" class="form-control" name="dsoffenseother" id="dsoffenseother" placeholder="Other"> <input type="text" class="form-control" name="dsoffenseother" id="dsoffenseother" placeholder="Other">
</div> </div>
<div class="col noborder"><button type="button" class="btn btn-secondary" onclick="addDS()"><i class="fas fa-plus"></i></button></div> <div class="col noborder"><button type="button" class="btn btn-secondary nomargin-top" onclick="addDS()"><i class="fas fa-plus"></i></button></div>
</div> </div>
<div id="inddsview" class="margin-top" style="width: 90%; margin-left: 5%;"><div class="col"></div></div> <div id="inddsview" class="margin-top" style="width: 90%; margin-left: 5%;"><div class="col"></div></div>
</div> </div>
<h3 class="margin-top">Notes 備註欄</h3>
<input type="textarea" class="form-control" name="notes" id="dsNotesEnter"
placeholder="Enter Notes 請輸入備註" style="width: 80%; margin-left: 10%;" row="3">
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear <button type="button" class="btn btn-danger" onclick="location.reload();">Cancel 取消</button>
Signature 清除簽名</button> <button type="button" class="btn btn-primary" onclick="submitDSForm()">Submit 提交</button>
<button type="button" class="btn btn-danger" onclick="location.reload();">Cancel
取消</button>
<button type="button" class="btn btn-primary submitButton" onclick="submitForm()">Submit
提交</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -83,8 +83,7 @@
<div class="col view-{{j}}" {% if currPeriod==j %}style="background-color: #ffdf81;"{%endif%}> <div class="col view-{{j}}" {% if currPeriod==j %}style="background-color: #ffdf81;"{%endif%}>
{% if schedule[j]['subject'] == 'GP' %} {% if schedule[j]['subject'] == 'GP' %}
{% for k in submission[j] %} {% for k in submission[j] %}
{% if studGP[i[0]][schedule[j]['teacher']] == k %} {% if k!='notes' and i[0] in absentData[j] %}
{% if i[0] in absentData[j] %}
{% if absentData[j][i[0]]['status'] == 'L' %} {% if absentData[j][i[0]]['status'] == 'L' %}
<p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p> <p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p>
{% elif absentData[j][i[0]]['status'] == 'K' %} {% elif absentData[j][i[0]]['status'] == 'K' %}
@ -103,12 +102,11 @@
<p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p> <p class="highlightAbs n-2 view-n-{{i[0]}}">{{absentData[j][i[0]]['status']}}</p>
{% endif %} {% endif %}
<p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p> <p class="highlightAbs">{{absentData[j][i[0]]['note']}}</p>
{% else %} {% elif studGP[i[0]][schedule[j]['teacher']] == k %}
<p class="highlightAbs n-1 view-n-{{i[0]}}">V</p> <p class="highlightAbs n-1 view-n-{{i[0]}}">V</p>
{% if j in idvDS and i[0] in idvDS[j] %} {% if j in idvDS and i[0] in idvDS[j] %}
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p> <p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
{% endif %} {% endif %}
{% endif %}
{% else %} {% else %}
<p class="highlightAbs view-n-{{i[0]}}"></p> <p class="highlightAbs view-n-{{i[0]}}"></p>
{% endif %} {% endif %}
@ -162,8 +160,10 @@
<div class="col"></div> <div class="col"></div>
{% for i in periods %} {% for i in periods %}
<div id="btns-{{i}}" class="col" {% if currPeriod==i %} style="background-color: #ffdf81;" {% endif %}> <div id="btns-{{i}}" class="col" {% if currPeriod==i %} style="background-color: #ffdf81;" {% endif %}>
{% if (schedule[i]['subject'] == 'GP' or i in submission or 'c' in submission) %} {% if (schedule[i]['subject'] == 'GP' or 'c' in submission) or (i in submission and submission[i]['dscfrm'] == True) %}
<button class="btn btn-primary afterSelButton" disabled="disabled"></button> <button class="btn btn-primary afterSelButton" disabled="disabled"></button>
{% elif i in submission and submission[i]['dscfrm'] != True %}
<button class="btn btn-warning afterSelButton" onclick="showSelDS('{{i|string}}')">定心<br>{{schedule[i]['subject']}}</button>
{% else %} {% else %}
<button class="btn btn-primary afterSelButton" <button class="btn btn-primary afterSelButton"
onclick="afterSelAbs('{{i|string}}', 'newSubmit')">Confirm<br>{{schedule[i]['subject']}}</button> onclick="afterSelAbs('{{i|string}}', 'newSubmit')">Confirm<br>{{schedule[i]['subject']}}</button>
@ -193,13 +193,19 @@
<input type="text" id="HR-signatureData" name="signatureData" value=""> <input type="text" id="HR-signatureData" name="signatureData" value="">
<input type="text" id="HR-notes" name="notes" value=""> <input type="text" id="HR-notes" name="notes" value="">
<input type="text" id="HR-homeroom" name="homeroom" value="{{currRoom[0]}}^{{currRoom[1]}}"> <input type="text" id="HR-homeroom" name="homeroom" value="{{currRoom[0]}}^{{currRoom[1]}}">
<input type="text" id="HR-ds1" name="ds^1" value=""> </form>
<input type="text" id="HR-ds2" name="ds^2" value=""> <form action="/manage/homeroom_ds" id="postHomeroomDS" hidden="hidden" method="POST">
<input type="text" id="HR-ds3" name="ds^3" value=""> <input type="text" id="DS-date" name="date" value="{{currDate}}">
<input type="text" id="HR-ds4" name="ds^4" value=""> <input type="text" id="DS-period" name="period" value="">
<input type="text" id="HR-ds5" name="ds^5" value=""> <input type="text" id="DS-ds1" name="ds^1" value="">
<input type="text" id="HR-ds6" name="ds^6" value=""> <input type="text" id="DS-ds2" name="ds^2" value="">
<input type="text" id="HR-ds7" name="ds^7" value=""> <input type="text" id="DS-ds3" name="ds^3" value="">
<input type="text" id="DS-ds4" name="ds^4" value="">
<input type="text" id="DS-ds5" name="ds^5" value="">
<input type="text" id="DS-ds6" name="ds^6" value="">
<input type="text" id="DS-ds7" name="ds^7" value="">
<input type="text" id="DS-notes" name="notes" value="">
<input type="text" id="DS-homeroom" name="homeroom" value="{{currRoom[0]}}^{{currRoom[1]}}">
</form> </form>
{% if 'c' in submission %} {% if 'c' in submission %}
<button class="btn btn-primary margin-top afterSelButton" onclick="homeroomCfrm()" disabled="disabled"> <button class="btn btn-primary margin-top afterSelButton" onclick="homeroomCfrm()" disabled="disabled">
@ -223,8 +229,30 @@
<h4 class="alert-heading">請確認是否全班全到Please check if everyone is present!</h4> <h4 class="alert-heading">請確認是否全班全到Please check if everyone is present!</h4>
</div> </div>
<div class="forSign"><canvas id="signature_pad"></canvas></div> <div class="forSign"><canvas id="signature_pad"></canvas></div>
<h3 class="margin-top">Notes 備註欄</h3>
<input type="textarea" class="form-control" name="notes" id="subjectNotes"
placeholder="Enter Notes 請輸入備註" style="width: 80%; margin-left: 10%;" row="3">
</div>
<div class="modal-footer">
<div class="row">
<div class="col"><button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear Signature 清除簽名</button></div>
<div class="col"><button type="button" class="btn btn-danger" onclick="location.reload();">Cancel 取消</button></div>
<div class="col"><button type="button" class="btn btn-primary" onclick="submitForm()">Submit 提交</button></div>
</div>
</div>
</div>
</div>
</div>
<div id="dsCheck" class="modal fade" id="staticBackdrop" data-bs-backdrop="static"
data-bs-keyboard="false" tabindex="-1" aria-labelledby="staticBackdropLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">定心專案 DS</h5>
</div>
<div class="modal-body">
<div class="ds"> <div class="ds">
<h3 class="margin-top">定心專案 DS</h3>
{% for i in range(dsboard|length) %} {% for i in range(dsboard|length) %}
<div class="row dsboard" style="width: 40%; margin-left: 30%;"> <div class="row dsboard" style="width: 40%; margin-left: 30%;">
<div class="col col-4"> <div class="col col-4">
@ -263,14 +291,13 @@
<div id="inddsview" class="margin-top" style="width: 90%; margin-left: 5%;"><div class="col"></div></div> <div id="inddsview" class="margin-top" style="width: 90%; margin-left: 5%;"><div class="col"></div></div>
</div> </div>
<h3 class="margin-top">Notes 備註欄</h3> <h3 class="margin-top">Notes 備註欄</h3>
<input type="textarea" class="form-control" name="notes" id="subjectNotes" <input type="textarea" class="form-control" name="notes" id="dsNotesEnter"
placeholder="Enter Notes 請輸入備註" style="width: 80%; margin-left: 10%;" row="3"> placeholder="Enter Notes 請輸入備註" style="width: 80%; margin-left: 10%;" row="3">
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<div class="row"> <div class="row">
<div class="col"><button class="btn btn-secondary" type="button" onclick="signaturePad.clear()">Clear Signature 清除簽名</button></div>
<div class="col"><button type="button" class="btn btn-danger" onclick="location.reload();">Cancel 取消</button></div> <div class="col"><button type="button" class="btn btn-danger" onclick="location.reload();">Cancel 取消</button></div>
<div class="col"><button type="button" class="btn btn-primary" onclick="submitForm()">Submit 提交</button></div> <div class="col"><button type="button" class="btn btn-primary" onclick="submitDSForm()">Submit 提交</button></div>
</div> </div>
</div> </div>
</div> </div>
@ -326,13 +353,13 @@
{% endif %} {% endif %}
{% endfor %} {% endfor %}
</div> </div>
{% include 'footer.html' %}
</div> </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 src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
{% include 'footer.html' %}
<script> <script>
var periodData = {} var periodData = {}
{% for i in periods %} {% for i in periods %}

View file

@ -78,13 +78,13 @@
</div> </div>
{% endfor %} {% endfor %}
</div> </div>
{% include 'footer.html' %}
</div> </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 src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
{% include 'footer.html' %}
<script src="/static/pagejs/homeroom.js"></script> <script src="/static/pagejs/homeroom.js"></script>
<script src="/static/time.js"></script> <script src="/static/time.js"></script>
</body> </body>

View file

@ -24,6 +24,7 @@
<ul class="list-unstyled components mb-5"> <ul class="list-unstyled components mb-5">
<li class="active"> <li class="active">
<a href="/manage"><span class="fa fa-home"></span> Home 主頁</a> <a href="/manage"><span class="fa fa-home"></span> Home 主頁</a>
{% if not hideSel %}
<div class="col"> <div class="col">
<div class="row"> <div class="row">
<select name="grade" id="sel-grade" class="form-select" onchange="getHR()" required> <select name="grade" id="sel-grade" class="form-select" onchange="getHR()" required>
@ -53,6 +54,13 @@
<button type="button" class="btn btn-primary" onclick="redirAdmin()">查詢</button> <button type="button" class="btn btn-primary" onclick="redirAdmin()">查詢</button>
</div> </div>
</div> </div>
{% endif %}
</li>
<li>
<a href="/manage/admin/mark"><span class="fa fa-user-times"></span> Mark New Absent<br>新增請假</a>
</li>
<li>
<a href="/manage/admin/export"><span class="fa fa-download"></span> Export<br>匯出</a>
</li> </li>
<li> <li>
<a href="/admin"><span class="fa fa-toolbox"></span> Admin<br>資料庫管理</a> <a href="/admin"><span class="fa fa-toolbox"></span> Admin<br>資料庫管理</a>