mirror of
https://github.com/aaronleetw/Attendance.git
synced 2024-11-14 19:11:39 -08:00
Added 2-step-ds; Export
This commit is contained in:
parent
70ca7164cb
commit
7e621848cb
26 changed files with 1324 additions and 426 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
|||
*.env
|
||||
test*.*
|
||||
__pycache__/*
|
||||
excel/*
|
5
app.py
5
app.py
|
@ -1,5 +1,5 @@
|
|||
from functions import *
|
||||
from manage import manage
|
||||
from manage.manage import manage
|
||||
from upload import upload
|
||||
from login import login
|
||||
load_dotenv()
|
||||
|
@ -20,6 +20,7 @@ class DefaultModelView(ModelView):
|
|||
restricted = True
|
||||
def __init__(self, model, session, restricted=True, name=None, category=None, endpoint=None, url=None, **kwargs):
|
||||
self.restricted = restricted
|
||||
self.column_default_sort = ('id', True)
|
||||
for k, v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
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'))
|
||||
|
||||
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
333
export.py
Normal 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
|
1
login.py
1
login.py
|
@ -283,7 +283,6 @@ def resetPassword():
|
|||
WHERE resetID = %s
|
||||
""", (request.args.get('resetCode'),))
|
||||
user = cursor.fetchone()
|
||||
cursor.close()
|
||||
dtnow = datetime.now(tz).replace(tzinfo=None)
|
||||
if user == None:
|
||||
raise Exception('無此重置密碼代碼<br>Invalid reset password code')
|
||||
|
|
BIN
manage/__pycache__/admin.cpython-39.pyc
Normal file
BIN
manage/__pycache__/admin.cpython-39.pyc
Normal file
Binary file not shown.
BIN
manage/__pycache__/group.cpython-39.pyc
Normal file
BIN
manage/__pycache__/group.cpython-39.pyc
Normal file
Binary file not shown.
BIN
manage/__pycache__/homeroom.cpython-39.pyc
Normal file
BIN
manage/__pycache__/homeroom.cpython-39.pyc
Normal file
Binary file not shown.
BIN
manage/__pycache__/manage.cpython-39.pyc
Normal file
BIN
manage/__pycache__/manage.cpython-39.pyc
Normal file
Binary file not shown.
BIN
manage/__pycache__/student.cpython-39.pyc
Normal file
BIN
manage/__pycache__/student.cpython-39.pyc
Normal file
Binary file not shown.
139
manage/admin.py
Normal file
139
manage/admin.py
Normal 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
102
manage/group.py
Normal 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
141
manage/homeroom.py
Normal 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')
|
|
@ -1,6 +1,29 @@
|
|||
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.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):
|
||||
|
@ -182,14 +205,9 @@ def manageProcess(fCommand, fData):
|
|||
if (h not in data[cclass['category'] + ' ' + cclass['class_id']][p[0]]):
|
||||
data[cclass['category'] + ' ' + cclass['class_id']][p[0]][h] = {}
|
||||
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()
|
||||
submitted = False
|
||||
try:
|
||||
if submissionSQL[0] == 'STUD_AFFAIR_OFFICE':
|
||||
submitted = True
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
signatures = json.loads(submissionSQL[0])
|
||||
if cclass['class_id'] in signatures:
|
||||
|
@ -226,6 +244,7 @@ def manageProcess(fCommand, fData):
|
|||
"ename": x[4],
|
||||
"status": status,
|
||||
"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)
|
||||
elif pl == 'homeroom':
|
||||
|
@ -291,7 +310,7 @@ def manageProcess(fCommand, fData):
|
|||
"special": True
|
||||
}
|
||||
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()
|
||||
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))
|
||||
|
@ -328,6 +347,8 @@ def manageProcess(fCommand, fData):
|
|||
"ds6": i[8],
|
||||
"ds7": i[9],
|
||||
}
|
||||
if i[10] == 'yes':
|
||||
submission[i[0]]["dscfrm"] = True
|
||||
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))
|
||||
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)
|
||||
else:
|
||||
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
30
manage/student.py
Normal 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 |
|
@ -76,3 +76,50 @@ function submitForm() {
|
|||
$('.container').hide();
|
||||
$('#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 = ""
|
||||
}
|
||||
|
|
|
@ -2,13 +2,6 @@ var signaturePad, selPeriod, canvas, width = $(window).width(), modal;
|
|||
var indDS = {};
|
||||
function submitForm() {
|
||||
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');
|
||||
loadingAnimation();
|
||||
signaturePad.off();
|
||||
|
@ -20,6 +13,18 @@ function submitForm() {
|
|||
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() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
|
@ -29,8 +34,7 @@ function resizeCanvas() {
|
|||
}
|
||||
function viewSignature(period) {
|
||||
selPeriod = period
|
||||
$('.viewSignatureBtn').attr({ 'disabled': 'disabled' });
|
||||
$('.viewSignatureBtn').removeClass('margin-bottom');
|
||||
document.getElementById("attendanceData^" + selPeriod).getElementsByClassName("submissionType")[0].value = "newAbsent";
|
||||
modal = 'sign-' + period;
|
||||
$('#' + modal).modal('show');
|
||||
var cnt = 0;
|
||||
|
@ -58,6 +62,12 @@ function viewSignature(period) {
|
|||
});
|
||||
resizeCanvas();
|
||||
}
|
||||
function signDS(period) {
|
||||
selPeriod = period
|
||||
document.getElementById("attendanceData^" + selPeriod).getElementsByClassName("submissionType")[0].value = "dsSubmit";
|
||||
modal = 'ds-' + period;
|
||||
$('#' + modal).modal('show');
|
||||
}
|
||||
function unCheckLate(string) {
|
||||
document.getElementById('late^' + string).checked = false;
|
||||
strForNote = string.substring(string.indexOf("^") + 1);
|
||||
|
|
|
@ -26,11 +26,6 @@ function submitForm() {
|
|||
document.getElementById('homeroom_confirm').submit()
|
||||
} else {
|
||||
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-notes').value = notes;
|
||||
document.getElementById('postHomeroomAbs').submit();
|
||||
|
@ -40,6 +35,16 @@ function submitForm() {
|
|||
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() {
|
||||
var ratio = Math.max(window.devicePixelRatio || 1, 1);
|
||||
canvas.width = canvas.offsetWidth * ratio;
|
||||
|
@ -88,7 +93,6 @@ function afterSelAbs(period) {
|
|||
}
|
||||
function homeroomCfrm() {
|
||||
hrCfrm = true;
|
||||
$('.ds').attr('hidden', 'hidden');
|
||||
$('#showSignPeriod').text("HOMEROOM CONFIRM");
|
||||
$('#showSignSubjectName').text("班導確認");
|
||||
$('.tobeform').attr('disabled', 'disabled');
|
||||
|
@ -126,3 +130,7 @@ function addDS() {
|
|||
$('#dsoffensesel').val("");
|
||||
$('#dsnumbersel').val("");
|
||||
}
|
||||
function showSelDS(period) {
|
||||
$('#DS-period').val(period)
|
||||
$('#dsCheck').modal('show');
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
this is just so that /temp doesn't disappear
|
|
@ -70,8 +70,7 @@
|
|||
<div class="col view-{{j}}">
|
||||
{% if schedule[j]['subject'] == 'GP' %}
|
||||
{% for k in submission[j] %}
|
||||
{% if studGP[i[0]][schedule[j]['teacher']] == k %}
|
||||
{% if i[0] in absentData[j] %}
|
||||
{% if k!='notes' and i[0] in absentData[j] %}
|
||||
{% if absentData[j][i[0]]['status'] == 'L' %}
|
||||
<p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
<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>
|
||||
{% if j in idvDS and i[0] in idvDS[j] %}
|
||||
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p class="highlightAbs view-n-{{i[0]}}"></p>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% else %}
|
||||
{% if j in submission %}
|
||||
{% if i[0] in absentData[j] %}
|
||||
{% if absentData[j][i[0]]['status'] == 'L' %}
|
||||
<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>
|
||||
{% endif %}
|
||||
<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>
|
||||
{% if j in idvDS and i[0] in idvDS[j] %}
|
||||
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p class="highlightAbs view-n-{{i[0]}}"></p>
|
||||
{% endif %}
|
||||
{% if j in idvDS and i[0] in idvDS[j] %}
|
||||
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -201,34 +197,12 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% if showUpload == '1' %}
|
||||
<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 %}
|
||||
{% 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>
|
||||
{% include 'footer.html' %}
|
||||
<script>
|
||||
var homerooms = {};
|
||||
{% for i in homerooms %}
|
||||
|
@ -241,5 +215,4 @@
|
|||
<script src="/static/pagejs/admin.js"></script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
92
templates/admin_export.html
Normal file
92
templates/admin_export.html
Normal 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
178
templates/admin_mark.html
Normal 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>
|
|
@ -47,6 +47,7 @@
|
|||
<input type="hidden" class="signatureData" name="signatureData" value="">
|
||||
<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="submissionType" class="submissionType" value="">
|
||||
<div class="col" style="margin-top: 5px;">
|
||||
<div class="row title sticky-top" style="background-color: white">
|
||||
<div class="col">Grade 年級</div>
|
||||
|
@ -56,6 +57,7 @@
|
|||
<div class="col">Period {{p}} | 第 {{p}} 節</div>
|
||||
</div>
|
||||
{% set need_fill = namespace(found=false) %}
|
||||
{% set need_ds = namespace(found=false) %}
|
||||
{% if data[c] != None %}
|
||||
{% for grade in data[c][p] %}
|
||||
{% for student in data[c][p][grade] %}
|
||||
|
@ -113,18 +115,25 @@
|
|||
onchange="unCheckLate('{{p}}^{{grade}}^{{student}}')">
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if data[c][p][grade][student]['needDS'] == True %}
|
||||
{% set need_ds.found = true %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if not need_fill.found %}
|
||||
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
|
||||
onclick="viewSignature('{{p}}')" disabled="disabled">
|
||||
Already Submitted</button>
|
||||
{% else %}
|
||||
{% if need_fill.found %}
|
||||
<button class="btn btn-primary margin-bottom viewSignatureBtn" type="button"
|
||||
onclick="viewSignature('{{p}}')">
|
||||
↑ 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 %}
|
||||
<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">
|
||||
|
@ -150,15 +159,47 @@
|
|||
margin-top: 0;
|
||||
}
|
||||
</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">
|
||||
<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 class="col-2">
|
||||
<select class="form-select" name="dsnumbers" id="dsnumbersel">
|
||||
<option value="">選擇號碼</option>
|
||||
{% for grade in data[c][p] %}
|
||||
{% 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>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
@ -176,18 +217,17 @@
|
|||
<div class="col-5">
|
||||
<input type="text" class="form-control" name="dsoffenseother" id="dsoffenseother" placeholder="Other">
|
||||
</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 id="inddsview" class="margin-top" style="width: 90%; margin-left: 5%;"><div class="col"></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 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>
|
||||
<button type="button" class="btn btn-danger" onclick="location.reload();">Cancel 取消</button>
|
||||
<button type="button" class="btn btn-primary" onclick="submitDSForm()">Submit 提交</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -83,8 +83,7 @@
|
|||
<div class="col view-{{j}}" {% if currPeriod==j %}style="background-color: #ffdf81;"{%endif%}>
|
||||
{% if schedule[j]['subject'] == 'GP' %}
|
||||
{% for k in submission[j] %}
|
||||
{% if studGP[i[0]][schedule[j]['teacher']] == k %}
|
||||
{% if i[0] in absentData[j] %}
|
||||
{% if k!='notes' and i[0] in absentData[j] %}
|
||||
{% if absentData[j][i[0]]['status'] == 'L' %}
|
||||
<p class="highlightAbs n-3 view-n-{{i[0]}}">𝜑</p>
|
||||
{% 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>
|
||||
{% endif %}
|
||||
<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>
|
||||
{% if j in idvDS and i[0] in idvDS[j] %}
|
||||
<p class="highlightAbs n-2">{{idvDS[j][i[0]]}}</p>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p class="highlightAbs view-n-{{i[0]}}"></p>
|
||||
{% endif %}
|
||||
|
@ -162,8 +160,10 @@
|
|||
<div class="col"></div>
|
||||
{% for i in periods %}
|
||||
<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>
|
||||
{% 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 %}
|
||||
<button class="btn btn-primary afterSelButton"
|
||||
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-notes" name="notes" value="">
|
||||
<input type="text" id="HR-homeroom" name="homeroom" value="{{currRoom[0]}}^{{currRoom[1]}}">
|
||||
<input type="text" id="HR-ds1" name="ds^1" value="">
|
||||
<input type="text" id="HR-ds2" name="ds^2" value="">
|
||||
<input type="text" id="HR-ds3" name="ds^3" value="">
|
||||
<input type="text" id="HR-ds4" name="ds^4" value="">
|
||||
<input type="text" id="HR-ds5" name="ds^5" value="">
|
||||
<input type="text" id="HR-ds6" name="ds^6" value="">
|
||||
<input type="text" id="HR-ds7" name="ds^7" value="">
|
||||
</form>
|
||||
<form action="/manage/homeroom_ds" id="postHomeroomDS" hidden="hidden" method="POST">
|
||||
<input type="text" id="DS-date" name="date" value="{{currDate}}">
|
||||
<input type="text" id="DS-period" name="period" value="">
|
||||
<input type="text" id="DS-ds1" name="ds^1" value="">
|
||||
<input type="text" id="DS-ds2" name="ds^2" 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>
|
||||
{% if 'c' in submission %}
|
||||
<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>
|
||||
</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">
|
||||
<h3 class="margin-top">定心專案 DS</h3>
|
||||
{% for i in range(dsboard|length) %}
|
||||
<div class="row dsboard" style="width: 40%; margin-left: 30%;">
|
||||
<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>
|
||||
<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">
|
||||
</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 class="col"><button type="button" class="btn btn-primary" onclick="submitDSForm()">Submit 提交</button></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -326,13 +353,13 @@
|
|||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
</div>
|
||||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
||||
crossorigin="anonymous"></script>
|
||||
{% include 'footer.html' %}
|
||||
<script>
|
||||
var periodData = {}
|
||||
{% for i in periods %}
|
||||
|
|
|
@ -78,13 +78,13 @@
|
|||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% include 'footer.html' %}
|
||||
</div>
|
||||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
|
||||
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
|
||||
crossorigin="anonymous"></script>
|
||||
{% include 'footer.html' %}
|
||||
<script src="/static/pagejs/homeroom.js"></script>
|
||||
<script src="/static/time.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<ul class="list-unstyled components mb-5">
|
||||
<li class="active">
|
||||
<a href="/manage"><span class="fa fa-home"></span> Home 主頁</a>
|
||||
{% if not hideSel %}
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<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>
|
||||
</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>
|
||||
<a href="/admin"><span class="fa fa-toolbox"></span> Admin<br>資料庫管理</a>
|
||||
|
|
Loading…
Reference in a new issue