scenar
This commit is contained in:
196
scenar.py
Executable file
196
scenar.py
Executable file
@@ -0,0 +1,196 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import cgi
|
||||||
|
import cgitb
|
||||||
|
import pandas as pd
|
||||||
|
from openpyxl import Workbook
|
||||||
|
from openpyxl.styles import Alignment, Border, Font, PatternFill, Side
|
||||||
|
from openpyxl.utils import get_column_letter
|
||||||
|
from datetime import datetime
|
||||||
|
from io import StringIO
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
cgitb.enable()
|
||||||
|
|
||||||
|
print("Content-Type: text/html")
|
||||||
|
print()
|
||||||
|
|
||||||
|
form = cgi.FieldStorage()
|
||||||
|
|
||||||
|
title = form.getvalue('title')
|
||||||
|
detail = form.getvalue('detail')
|
||||||
|
csv_content = form.getvalue('csv_content')
|
||||||
|
program_descriptions = {
|
||||||
|
"C": form.getvalue('desc_C', "Program naplnujici cile"),
|
||||||
|
"S": form.getvalue('desc_S', "Program pro podporu skupinove dynamiky"),
|
||||||
|
"K": form.getvalue('desc_K', "Kreativni program"),
|
||||||
|
"P": form.getvalue('desc_P', "Provozni blok"),
|
||||||
|
"O": form.getvalue('desc_O', "Vyplnove a ostatni programy"),
|
||||||
|
}
|
||||||
|
program_colors = {
|
||||||
|
"C": 'FF' + form.getvalue('color_C', "ADD8E6").lstrip('#'),
|
||||||
|
"S": 'FF' + form.getvalue('color_S', "90EE90").lstrip('#'),
|
||||||
|
"K": 'FF' + form.getvalue('color_K', "FFFF00").lstrip('#'),
|
||||||
|
"P": 'FF' + form.getvalue('color_P', "D3D3D3").lstrip('#'),
|
||||||
|
"O": 'FF' + form.getvalue('color_O', "FFB6C1").lstrip('#'),
|
||||||
|
}
|
||||||
|
|
||||||
|
def read_csv_from_string(csv_string):
|
||||||
|
return pd.read_csv(StringIO(csv_string), sep=";", header=None, names=["Datum", "Zacatek", "Konec", "Program", "Typ", "Garant", "Poznamka"])
|
||||||
|
|
||||||
|
def calculate_row_height(cell_value, column_width):
|
||||||
|
if not cell_value:
|
||||||
|
return 15
|
||||||
|
|
||||||
|
max_line_length = column_width * 1.2
|
||||||
|
lines = cell_value.split('\n')
|
||||||
|
line_count = 0
|
||||||
|
for line in lines:
|
||||||
|
line_count += len(line) // max_line_length + 1
|
||||||
|
|
||||||
|
return line_count * 15
|
||||||
|
|
||||||
|
def create_timetable(data, title, detail, program_descriptions, program_colors):
|
||||||
|
wb = Workbook()
|
||||||
|
ws = wb.active
|
||||||
|
|
||||||
|
thick_border = Border(left=Side(style='thick', color='000000'),
|
||||||
|
right=Side(style='thick', color='000000'),
|
||||||
|
top=Side(style='thick', color='000000'),
|
||||||
|
bottom=Side(style='thick', color='000000'))
|
||||||
|
|
||||||
|
ws['A1'] = title
|
||||||
|
ws['A1'].alignment = Alignment(horizontal="center", vertical="center")
|
||||||
|
ws['A1'].font = Font(size=24, bold=True)
|
||||||
|
ws['A1'].border = thick_border
|
||||||
|
|
||||||
|
ws['A2'] = detail
|
||||||
|
ws['A2'].alignment = Alignment(horizontal="center", vertical="center")
|
||||||
|
ws['A2'].font = Font(size=16, italic=True)
|
||||||
|
ws['A2'].border = thick_border
|
||||||
|
|
||||||
|
# Nastavení výšky řádků pro nadpis a podnadpis
|
||||||
|
title_row_height = calculate_row_height(title, ws.column_dimensions[get_column_letter(1)].width)
|
||||||
|
detail_row_height = calculate_row_height(detail, ws.column_dimensions[get_column_letter(1)].width)
|
||||||
|
ws.row_dimensions[1].height = title_row_height
|
||||||
|
ws.row_dimensions[2].height = detail_row_height
|
||||||
|
|
||||||
|
data["Datum"] = pd.to_datetime(data["Datum"], format="%d.%m.%Y")
|
||||||
|
data = data.sort_values(by=["Datum", "Zacatek"])
|
||||||
|
|
||||||
|
start_times = data["Zacatek"].apply(lambda x: datetime.strptime(str(x), '%H%M'))
|
||||||
|
end_times = data["Konec"].apply(lambda x: datetime.strptime(str(x), '%H%M'))
|
||||||
|
|
||||||
|
min_time = start_times.min()
|
||||||
|
max_time = end_times.max()
|
||||||
|
|
||||||
|
time_slots = pd.date_range(min_time, max_time, freq='15min').time
|
||||||
|
|
||||||
|
total_columns = len(time_slots) + 1
|
||||||
|
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=total_columns)
|
||||||
|
ws.merge_cells(start_row=2, start_column=1, end_row=2, end_column=total_columns)
|
||||||
|
|
||||||
|
row_offset = 3
|
||||||
|
col_offset = 1
|
||||||
|
cell = ws.cell(row=row_offset, column=col_offset, value="Datum")
|
||||||
|
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
|
||||||
|
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||||||
|
cell.font = Font(bold=True)
|
||||||
|
cell.border = thick_border
|
||||||
|
|
||||||
|
for i, time_slot in enumerate(time_slots, start=col_offset + 1):
|
||||||
|
cell = ws.cell(row=row_offset, column=i, value=time_slot.strftime("%H:%M"))
|
||||||
|
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
|
||||||
|
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||||||
|
cell.font = Font(bold=True)
|
||||||
|
cell.border = thick_border
|
||||||
|
|
||||||
|
current_row = row_offset + 1
|
||||||
|
grouped_data = data.groupby(data['Datum'])
|
||||||
|
|
||||||
|
for date, group in grouped_data:
|
||||||
|
day_name = date.strftime("%A")
|
||||||
|
date_str = date.strftime(f"%d.%m {day_name}")
|
||||||
|
|
||||||
|
cell = ws.cell(row=current_row, column=col_offset, value=date_str)
|
||||||
|
cell.alignment = Alignment(horizontal="center", vertical="center")
|
||||||
|
cell.fill = PatternFill(start_color="D3D3D3", end_color="D3D3D3", fill_type="solid")
|
||||||
|
cell.font = Font(bold=True, size=14)
|
||||||
|
cell.border = thick_border
|
||||||
|
|
||||||
|
for _, row in group.iterrows():
|
||||||
|
start_time = datetime.strptime(str(row["Zacatek"]), '%H%M').time()
|
||||||
|
end_time = datetime.strptime(str(row["Konec"]), '%H%M').time()
|
||||||
|
start_index = list(time_slots).index(start_time) + col_offset + 1
|
||||||
|
end_index = list(time_slots).index(end_time) + col_offset + 1
|
||||||
|
|
||||||
|
cell_value = f"{row['Program']}"
|
||||||
|
if pd.notna(row['Garant']):
|
||||||
|
cell_value += f"\n{row['Garant']}"
|
||||||
|
if pd.notna(row['Poznamka']):
|
||||||
|
cell_value += f"\n\n{row['Poznamka']}"
|
||||||
|
|
||||||
|
ws.merge_cells(start_row=current_row, start_column=start_index, end_row=current_row, end_column=end_index - 1)
|
||||||
|
cell = ws.cell(row=current_row, column=start_index)
|
||||||
|
cell.value = cell_value
|
||||||
|
cell.alignment = Alignment(wrap_text=True, horizontal="center", vertical="center")
|
||||||
|
|
||||||
|
lines = cell_value.split("\n")
|
||||||
|
for idx, line in enumerate(lines):
|
||||||
|
if idx == 0:
|
||||||
|
cell.font = Font(bold=True)
|
||||||
|
elif idx == 1:
|
||||||
|
cell.font = Font(bold=False)
|
||||||
|
elif idx > 1 and pd.notna(row['Poznamka']):
|
||||||
|
cell.font = Font(italic=True)
|
||||||
|
|
||||||
|
cell.fill = PatternFill(start_color=program_colors[row["Typ"]], end_color=program_colors[row["Typ"]], fill_type="solid")
|
||||||
|
cell.border = thick_border
|
||||||
|
|
||||||
|
current_row += 1
|
||||||
|
|
||||||
|
legend_row = current_row + 2
|
||||||
|
legend_max_length = 0
|
||||||
|
ws.cell(row=legend_row, column=1, value="Legenda:").font = Font(bold=True)
|
||||||
|
legend_row += 1
|
||||||
|
for typ, desc in program_descriptions.items():
|
||||||
|
legend_text = f"{desc} ({typ})"
|
||||||
|
legend_cell = ws.cell(row=legend_row, column=1, value=legend_text)
|
||||||
|
legend_cell.fill = PatternFill(start_color=program_colors[typ], fill_type="solid")
|
||||||
|
legend_max_length = max(legend_max_length, calculate_column_width(legend_text))
|
||||||
|
legend_row += 1
|
||||||
|
|
||||||
|
ws.column_dimensions[get_column_letter(col_offset)].width = legend_max_length
|
||||||
|
|
||||||
|
for col in range(2, total_columns + 1):
|
||||||
|
ws.column_dimensions[get_column_letter(col)].width = 15
|
||||||
|
|
||||||
|
for row in ws.iter_rows(min_row=1, max_row=current_row - 1, min_col=1, max_col=total_columns):
|
||||||
|
for cell in row:
|
||||||
|
cell.alignment = Alignment(wrap_text=True, horizontal="center", vertical="center")
|
||||||
|
cell.border = thick_border
|
||||||
|
|
||||||
|
for row in ws.iter_rows(min_row=1, max_row=current_row - 1):
|
||||||
|
max_height = 0
|
||||||
|
for cell in row:
|
||||||
|
if cell.value:
|
||||||
|
height = calculate_row_height(cell.value, ws.column_dimensions[get_column_letter(cell.column)].width)
|
||||||
|
if height > max_height:
|
||||||
|
max_height = height
|
||||||
|
ws.row_dimensions[row[0].row].height = max_height
|
||||||
|
|
||||||
|
return wb
|
||||||
|
|
||||||
|
def calculate_column_width(text):
|
||||||
|
max_length = max(len(line) for line in text.split('\n'))
|
||||||
|
return max_length * 1.2
|
||||||
|
|
||||||
|
data = read_csv_from_string(csv_content)
|
||||||
|
wb = create_timetable(data, title, detail, program_descriptions, program_colors)
|
||||||
|
filename = f"{title}.xlsx"
|
||||||
|
file_path = f"/var/www/htdocs/{filename}"
|
||||||
|
wb.save(file_path)
|
||||||
|
|
||||||
|
print(f'<a href="/{filename}" download>Stahnout scenar pro {title} ZDE</a>')
|
||||||
|
|
||||||
Reference in New Issue
Block a user