у меня есть календарь сделай мне красивым его и рабочим
фласк код
from flask import Flask, render_template, request, redirect, make_response, jsonify, send_file, Response
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime, timedelta
import pandas as pd
from io import BytesIO
import json
import queue

app = Flask(__name__)

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///table_data.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)



class TableRow(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.String(10), nullable=False)
    row_number = db.Column(db.String(10))
    timestamp = db.Column(db.String(50))
    number = db.Column(db.String(50))
    serial = db.Column(db.String(50))
    dl_number = db.Column(db.String(50))
    worker_name = db.Column(db.String(100))
    pack_time = db.Column(db.String(50))
    last_graf = db.Column(db.String(50))


class DLCounter(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    date = db.Column(db.String(10), unique=True, nullable=False)
    counter = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return f'<DLCounter {self.date}: {self.counter}>'


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    login_history = db.relationship('LoginHistory', backref='user', lazy=True)

class LoginHistory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    login_date = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)



tables = {}
table = [['№', 'Время отправки', 'Номер ', 'Serial', 'Графа', 'Имя отправителя', 'Время упаковки', 'last_graf']]
# Добавляем счетчик для номеров записей
row_counter = 1
# Создаем очередь для событий
update_queue = queue.Queue()



@app.route('/stream')
def stream():
    def event_stream():
        while True:
            message = update_queue.get()  # Блокирует до получения сообщения
            yield f"data: {message}\n\n"
    
    return Response(event_stream(), content_type='text/event-stream')


@app.route('/get_table_data')
def get_table_data():
    date = request.args.get('date')
    rows = TableRow.query.filter_by(date=date).all()
    data = []
    numbers = {}
    serials = {}

    for row in rows:
        data.append([
            row.row_number,
            row.timestamp,
            row.number,
            row.serial,
            row.dl_number,
            row.worker_name,
            row.pack_time,
            row.last_graf
        ])

        # Собираем информацию о дубликатах
        if row.number:
            clean_number = ''.join(filter(str.isdigit, row.number))
            if clean_number in numbers:
                numbers[clean_number].append(len(data) - 1)  # Индекс строки
            else:
                numbers[clean_number] = [len(data) - 1]

        if row.serial:
            clean_serial = ''.join(filter(str.isdigit, row.serial))
            if clean_serial in serials:
                serials[clean_serial].append(len(data) - 1)  # Индекс строки
            else:
                serials[clean_serial] = [len(data) - 1]

    # Фильтруем только реальные дубликаты
    duplicate_numbers = {k: v for k, v in numbers.items() if len(v) > 1}
    duplicate_serials = {k: v for k, v in serials.items() if len(v) > 1}

    return jsonify({
        "data": data,
        "duplicates": {
            "numbers": duplicate_numbers,
            "serials": duplicate_serials
        }
    })




@app.route('/update_table', methods=['POST'])
def update_table():
    data = request.json
    date = data['date']
    
    # Получаем количество существующих записей для этой даты
    row_count = TableRow.query.filter_by(date=date).count() + 1
    
    new_row = TableRow(
        date=date,
        row_number=str(row_count),
        timestamp=data['timestamp'],
        number=data['number'],
        serial=data['serial'],
        worker_name=data['worker_name'],
        last_graf=data.get('last_graf', '')
    )
    
    db.session.add(new_row)
    db.session.commit()
    
    # Отправляем сообщение в очередь для обновления клиентов
    update_queue.put(json.dumps({"type": "update", "date": date}))
    
    return jsonify({"status": "success"})

@app.route('/update_number', methods=['POST'])
def update_number():
    try:
        data = request.json
        row_index = int(data['row_index'])
        new_value = data['new_value']
        date = data['date']
        
        rows = TableRow.query.filter_by(date=date).all()
        if 0 <= row_index < len(rows):
            row = rows[row_index]
            row.number = new_value
            db.session.commit()
            return jsonify({"status": "success"})
        return jsonify({"status": "error", "message": "Invalid row index"})
    except Exception as e:
        db.session.rollback()
        return jsonify({"status": "error", "message": str(e)})

@app.route('/pack_item', methods=['POST'])
def pack_item():
    try:
        data = request.json
        row_index = data['row_index']
        date = data['date']
        
        print(f"Received date: {date}")  # Отладочный вывод
        print(f"Received row_index: {row_index}")  # Отладочный вывод
        
        row = TableRow.query.filter_by(date=date).offset(row_index).first()
        if row:
            pack_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            row.pack_time = pack_time
            db.session.commit()
            return jsonify({"status": "success", "pack_time": pack_time})
        
        return jsonify({"status": "error", "message": "Row not found"})
    except Exception as e:
        print(f"Error in pack_item: {str(e)}")  # Отладочный вывод
        return jsonify({"status": "error", "message": str(e)})


@app.route('/set_initial_dl', methods=['POST'])
def set_initial_dl():
    try:
        data = request.json
        if not data:
            return jsonify({"status": "error", "message": "No data received"})

        date = data.get('date')
        initial_number = data.get('initial_number')

        if not date or not initial_number:
            return jsonify({
                "status": "error", 
                "message": "Missing required fields",
                "received": {"date": date, "initial_number": initial_number}
            })

        try:
            initial_number = int(initial_number)
        except ValueError:
            return jsonify({
                "status": "error",
                "message": "Initial number must be an integer"
            })

        print(f"Setting initial DL for date {date}: {initial_number}")  # Отладочный вывод

        dl_counter = DLCounter.query.filter_by(date=date).first()
        if dl_counter:
            dl_counter.counter = initial_number
            print(f"Updated existing counter for {date}")  # Отладочный вывод
        else:
            dl_counter = DLCounter(date=date, counter=initial_number)
            db.session.add(dl_counter)
            print(f"Created new counter for {date}")  # Отладочный вывод

        db.session.commit()
        return jsonify({
            "status": "success",
            "message": f"DL counter set to {initial_number} for date {date}"
        })

    except Exception as e:
        print(f"Error in set_initial_dl: {str(e)}")  # Отладочный вывод
        db.session.rollback()
        return jsonify({
            "status": "error",
            "message": str(e)
        })



    
@app.route('/generate_dl', methods=['POST'])
def generate_dl():
    try:
        data = request.json
        row_index = data['row_index']
        date = data['date']
        
        # Получаем или создаем счетчик DL для данной даты
        dl_counter = DLCounter.query.filter_by(date=date).first()
        if not dl_counter:
            return jsonify({"status": "error", "message": "DL counter not initialized"})
        
        # Генерируем новый DL номер
        dl_number = f"DL{dl_counter.counter:06d}"
        
        # Находим и обновляем нужную запись
        row = TableRow.query.filter_by(date=date).offset(row_index).first()
        if row:
            row.dl_number = dl_number
            dl_counter.counter += 1  # Увеличиваем счетчик
            db.session.commit()
            return jsonify({"status": "success", "dl_number": dl_number})
        
        return jsonify({"status": "error", "message": "Row not found"})
    except Exception as e:
        return jsonify({"status": "error", "message": str(e)})

    

@app.route('/get_statistics')
def get_statistics():
    try:
        date = request.args.get('date')
        current_time = datetime.now()
        hour_ago = current_time - timedelta(hours=1)
        
        # Общее количество упакованных записей
        total_records = TableRow.query.filter_by(date=date).filter(TableRow.pack_time.isnot(None)).count()
        
        # Количество записей за последний час
        last_hour_records = TableRow.query.filter_by(date=date)\
            .filter(TableRow.pack_time.isnot(None))\
            .filter(TableRow.pack_time >= hour_ago.strftime("%Y-%m-%d %H:%M:%S"))\
            .count()
        
        return jsonify({
            "total_records": total_records,
            "last_hour_records": last_hour_records
        })
    except Exception as e:
        return jsonify({
            "total_records": 0,
            "last_hour_records": 0,
            "error": str(e)
        })



@app.route('/export_excel')
def export_excel():
    try:
        date = request.args.get('date')
        sort_column = request.args.get('sort_column')
        sort_order = request.args.get('sort_order')
        
        if not date:
            return jsonify({"error": "Date parameter is required"}), 400
        
        # Получаем все записи для выбранной даты
        query = TableRow.query.filter_by(date=date)
        
        # Применяем сортировку, если указана
        if sort_column and sort_order:
            column_mapping = {
                '0': TableRow.row_number,
                '1': TableRow.timestamp,  # Добавляем поддержку сортировки по времени отправки
                '2': TableRow.number,
                '3': TableRow.serial,
                '4': TableRow.dl_number,
                '5': TableRow.worker_name,
                '6': TableRow.pack_time,
                '7': TableRow.last_graf
            }
            if sort_column in column_mapping:
                column = column_mapping[sort_column]
                if sort_order == 'desc':
                    query = query.order_by(column.desc())
                else:
                    query = query.order_by(column.asc())
        
        rows = query.all()
        
        # Создаем DataFrame
        data = []
        for row in rows:
            data.append({
                '№': row.row_number,
                'Время отправки': row.timestamp,
                'Номер': row.number,
                'Serial': row.serial,
                'Графа': row.dl_number,
                'Имя отправителя': row.worker_name,
                'Время упаковки': row.pack_time,
                'last_graf': row.last_graf
            })
        
        df = pd.DataFrame(data)
        
        # Создаем Excel файл
        output = BytesIO()
        with pd.ExcelWriter(output, engine='xlsxwriter') as writer:
            df.to_excel(writer, index=False, sheet_name='Sheet1')
            
            # Настраиваем форматирование
            workbook = writer.book
            worksheet = writer.sheets['Sheet1']
            
            # Автоматическая ширина столбцов
            for idx, col in enumerate(df.columns):
                series = df[col]
                max_len = max(
                    series.astype(str).map(len).max(),
                    len(str(col))
                ) + 2
                worksheet.set_column(idx, idx, max_len)
        
        output.seek(0)
        
        return send_file(
            output,
            mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            as_attachment=True,
            download_name=f'export_{date}.xlsx'
        )
    
    except Exception as e:
        print(f"Export error: {str(e)}")
        return jsonify({"error": str(e)}), 500



@app.route('/update_serial', methods=['POST'])
def update_serial():
    try:
        data = request.json
        row_index = int(data['row_index'])
        new_value = data['new_value']
        date = data['date']
        
        rows = TableRow.query.filter_by(date=date).all()
        if 0 <= row_index < len(rows):
            row = rows[row_index]
            row.serial = new_value
            db.session.commit()
            return jsonify({"status": "success"})
        return jsonify({"status": "error", "message": "Invalid row index"})
    except Exception as e:
        db.session.rollback()
        return jsonify({"status": "error", "message": str(e)})
    

def initialize_table_for_date(date):
    # Проверяем, существуют ли уже записи для этой даты
    existing = TableRow.query.filter_by(date=date).first()
    if not existing:
        # Создаем первую запись с заголовками
        first_row = TableRow(
            date=date,
            row_number="№",
            timestamp="Время отправки",
            number="Номер",
            serial="Serial",
            dl_number="Графа",
            worker_name="Имя отправителя",
            pack_time="Время упаковки",
            last_graf="last_graf"
        )
        db.session.add(first_row)
        db.session.commit()



@app.route('/', methods=['GET', 'POST'])
def main():
    if request.method == 'POST':
        worker = request.form.get('worker')
        name = request.form.get('name')
        
        # Сохраняем информацию о входе
        user = User.query.filter_by(username=name).first()
        if not user:
            user = User(username=name)
            db.session.add(user)
        
        login_history = LoginHistory(user=user)
        db.session.add(login_history)
        db.session.commit()
        
        resp = make_response(redirect('/welcome'))
        resp.set_cookie('worker', worker)
        resp.set_cookie('name', name)
        return resp

    return render_template('main.html')


@app.route('/welcome')
def welcome():
    worker = request.cookies.get('worker')
    name = request.cookies.get('name')
    
    if not worker or not name:
        return redirect('/')
    
    return render_template('welcome.html', name=name, worker=worker, table=table)



@app.route('/logout')
def logout():
    resp = make_response(redirect('/'))
    resp.delete_cookie('worker')
    resp.delete_cookie('name')
    return resp

if __name__ == '__main__':
    with app.app_context():
        db.create_all()

    app.debug = True
    app.run(host='0.0.0.0', port=80, debug=True)
html
<!DOCTYPE html>
<html lang="ru">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Рабочая таблица</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='styles_welcome.css') }}">
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="{{ url_for('static', filename='js/utils.js') }}"></script>
    <script src="{{ url_for('static', filename='js/table.js') }}"></script>
    <script src="{{ url_for('static', filename='js/date.js') }}"></script>
    <script src="{{ url_for('static', filename='js/statistics.js') }}"></script>
</head>
<body>
    <div class="header">
        <h1>Рабочая таблица</h1>
        <div class="user-info">
            <span>Пользователь: {{ name }}</span>
            <a href="/logout" class="logout-button">Выход</a>
        </div>
    </div>

    <div class="content-wrapper">
        <div class="date-selector">
            <select id="day">
             
            </select>
            <select id="month">
                <option value="01">Январь</option>
                <option value="02">Февраль</option>
                <option value="03">Март</option>
                <option value="04">Апрель</option>
                <option value="05">Май</option>
                <option value="06">Июнь</option>
                <option value="07">Июль</option>
                <option value="08">Август</option>
                <option value="09">Сентябрь</option>
                <option value="10">Октябрь</option>
                <option value="11">Ноябрь</option>
                <option value="12">Декабрь</option>
            </select>
            <select id="year">
                <!-- JavaScript заполнит годы -->
            </select>
        </div>
        
        <div class="search-container">
            <input type="text" id="searchInput" placeholder="Поиск по номеру...">
            <button id="searchButton">Найти</button>
        </div>

        <div class="statistics-container">
            <div class="stat-box">
                <span class="stat-label">Всего записей:</span>
                <span class="stat-value" id="totalRecords">0</span>
            </div>
            <div class="stat-box">
                <span class="stat-label">Записей за последний час:</span>
                <span class="stat-value" id="lastHourRecords">0</span>
            </div>
        </div>
        
        <div class="table-container">
            <table border="1" id="dataTable">
                <thead>
                    <tr>
                        {% for header in table[0] %}
                            {% if header in ["Имя отправителя", "Время создания", "Время упаковки"] %}
                                <th class="sortable" data-column="{{ loop.index0 }}">{{ header }}</th>
                            {% elif loop.index0 == 1 %}
                                <th class="sortable" data-column="1">{{ header }}</th>
                            {% elif loop.index0 == 2 %}
                                <th class="sortable" data-column="2">{{ header }}</th>
                            {% elif loop.index0 == 6 %}  <!-- Индекс столбца "Время упаковки" -->
                                <th class="sortable" data-column="6">{{ header }}</th>
                            {% else %}
                                <th>{{ header }}</th>
                            {% endif %}
                        {% endfor %}
                    </tr>
                </thead>
                
                
                
                <tbody id="tableBody">
                    {% for row in table[1:] %}
                        <tr>
                            {% for cell in row %}
                                <td class="{% if loop.index0 == 2 %}editable{% endif %}">{{ cell }}</td>
                            {% endfor %}
                        </tr>
                    {% endfor %}
                </tbody>
            </table>
        </div>

        <div class="controls-container">
            <div class="dl-control">
                <label for="initial-dl">Начать DL:</label>
                <input type="text" id="initial-dl">
                <button onclick="setInitialDL()">Установить</button>
            </div>
            <div class="export-container">
                <button class="export-button">Экспорт в Excel</button>
            </div>
            
        </div>
    </div>
</body>
</html>
css