405 lines
9.9 KiB
HTML
405 lines
9.9 KiB
HTML
{% extends "base_authenticated.html" %}
|
|
{% block title %}Time Attendance Dashboard - {{ COMPANY_NAME }}{% endblock %}
|
|
|
|
{% block extra_head %}
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/time_attendance.css') }}">
|
|
{% endblock %}
|
|
|
|
{% block page_title %}Time Attendance{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="time-attendance-page">
|
|
<!-- Page Header -->
|
|
<div class="time-attendance-header">
|
|
<div class="header-navigation">
|
|
<a href="{{ url_for('dashboard') }}" class="back-button">
|
|
<i class="fas fa-arrow-left"></i>
|
|
Back to Dashboard
|
|
</a>
|
|
</div>
|
|
|
|
<div class="header-content">
|
|
<h1>
|
|
<i class="fas fa-clock"></i>
|
|
Time Attendance Management
|
|
</h1>
|
|
<p class="header-description">
|
|
Import, manage, and analyze employee time attendance data from Excel files
|
|
</p>
|
|
</div>
|
|
|
|
<div class="header-actions">
|
|
{% if session.role == 'admin' %}
|
|
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
|
|
<i class="fas fa-upload"></i>
|
|
Import Excel Data
|
|
</a>
|
|
{% endif %}
|
|
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-secondary">
|
|
<i class="fas fa-list"></i>
|
|
View Records
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Grid -->
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-icon records">
|
|
<i class="fas fa-database"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3>{{ "{:,}".format(total_records) }}</h3>
|
|
<p>Total Records</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stat-card">
|
|
<div class="stat-icon employees">
|
|
<i class="fas fa-users"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3>{{ "{:,}".format(unique_employees) }}</h3>
|
|
<p>Unique Employees</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stat-card">
|
|
<div class="stat-icon locations">
|
|
<i class="fas fa-map-marker-alt"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3>{{ "{:,}".format(unique_locations) }}</h3>
|
|
<p>Locations</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="stat-card">
|
|
<div class="stat-icon imports">
|
|
<i class="fas fa-file-import"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3>{{ "{:,}".format(recent_imports|length) }}</h3>
|
|
<p>Recent Imports</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Actions Section -->
|
|
<div class="import-section">
|
|
<div class="import-header">
|
|
<h2>
|
|
<i class="fas fa-bolt"></i>
|
|
Quick Actions
|
|
</h2>
|
|
</div>
|
|
<div class="import-body">
|
|
<div class="form-grid">
|
|
<div class="action-card">
|
|
<h3>
|
|
<i class="fas fa-search"></i>
|
|
Search Records
|
|
</h3>
|
|
<p>Find specific attendance records by employee, date, or location</p>
|
|
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-primary">
|
|
<i class="fas fa-search"></i>
|
|
Search Now
|
|
</a>
|
|
</div>
|
|
|
|
{% if session.role == 'admin' %}
|
|
<div class="action-card">
|
|
<h3>
|
|
<i class="fas fa-upload"></i>
|
|
Import Excel File
|
|
</h3>
|
|
<p>Upload and import time attendance data from Excel spreadsheets</p>
|
|
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-success">
|
|
<i class="fas fa-file-excel"></i>
|
|
Import Data
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<div class="action-card">
|
|
<h3>
|
|
<i class="fas fa-chart-bar"></i>
|
|
Generate Reports
|
|
</h3>
|
|
<p>Create detailed attendance reports and analytics</p>
|
|
<a href="#" class="btn btn-warning">
|
|
<i class="fas fa-chart-line"></i>
|
|
View Reports
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Recent Imports Section -->
|
|
{% if recent_imports %}
|
|
<div class="records-section">
|
|
<div class="records-header">
|
|
<h2>
|
|
<i class="fas fa-history"></i>
|
|
Recent Imports
|
|
</h2>
|
|
<div class="records-meta">
|
|
Last {{ recent_imports|length }} import batches
|
|
</div>
|
|
</div>
|
|
|
|
<div class="records-table-container">
|
|
<table class="records-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Import Date</th>
|
|
<th>Source</th>
|
|
<th>Records</th>
|
|
<th>Batch ID</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for import_batch in recent_imports %}
|
|
<tr>
|
|
<td class="datetime-cell">
|
|
{{ import_batch.import_date.strftime('%Y-%m-%d %H:%M') if import_batch.import_date else 'Unknown' }}
|
|
</td>
|
|
<td>
|
|
<div class="source-info">
|
|
<i class="fas fa-file-excel text-success"></i>
|
|
{{ import_batch.import_source or 'Excel Import' }}
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<span class="record-count">
|
|
{{ "{:,}".format(import_batch.record_count) }} records
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<code class="batch-id">{{ import_batch.import_batch_id[:8] }}...</code>
|
|
</td>
|
|
<td class="actions-cell">
|
|
<a href="{{ url_for('time_attendance_records', import_batch=import_batch.import_batch_id) }}"
|
|
class="action-btn view">
|
|
<i class="fas fa-eye"></i>
|
|
View
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Employee Quick Access -->
|
|
{% if employees %}
|
|
<div class="records-section">
|
|
<div class="records-header">
|
|
<h2>
|
|
<i class="fas fa-users"></i>
|
|
Employee Quick Access
|
|
</h2>
|
|
<div class="records-meta">
|
|
Click to view employee attendance records
|
|
</div>
|
|
</div>
|
|
|
|
<div class="employee-grid">
|
|
{% for employee in employees[:12] %}
|
|
<div class="employee-card">
|
|
<div class="employee-avatar">
|
|
{{ employee.employee_name[0].upper() if employee.employee_name else employee.employee_id[0].upper() }}
|
|
</div>
|
|
<div class="employee-info">
|
|
<div class="employee-name">{{ employee.employee_name }}</div>
|
|
<div class="employee-id">ID: {{ employee.employee_id }}</div>
|
|
</div>
|
|
<a href="{{ url_for('time_attendance_records', employee_id=employee.employee_id) }}"
|
|
class="btn btn-sm btn-outline">
|
|
<i class="fas fa-eye"></i>
|
|
View Records
|
|
</a>
|
|
</div>
|
|
{% endfor %}
|
|
|
|
{% if employees|length > 12 %}
|
|
<div class="employee-card view-all">
|
|
<div class="view-all-content">
|
|
<i class="fas fa-plus-circle"></i>
|
|
<span>{{ employees|length - 12 }} more employees</span>
|
|
<a href="{{ url_for('time_attendance_records') }}" class="btn btn-sm btn-primary">
|
|
View All
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Empty State -->
|
|
{% if total_records == 0 %}
|
|
<div class="empty-state">
|
|
<div class="empty-icon">
|
|
<i class="fas fa-clock"></i>
|
|
</div>
|
|
<h3>No Time Attendance Data</h3>
|
|
<p>
|
|
Get started by importing your first Excel file with time attendance data.
|
|
The system supports various Excel formats and will automatically process your data.
|
|
</p>
|
|
{% if session.role == 'admin' %}
|
|
<a href="{{ url_for('import_time_attendance') }}" class="btn btn-primary">
|
|
<i class="fas fa-upload"></i>
|
|
Import Your First File
|
|
</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<style>
|
|
.action-card {
|
|
background: #f8fafc;
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 0.75rem;
|
|
padding: 1.5rem;
|
|
text-align: center;
|
|
transition: all 0.2s ease-in-out;
|
|
}
|
|
|
|
.action-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 25px 0 rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.action-card h3 {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
gap: 0.5rem;
|
|
font-size: 1.125rem;
|
|
font-weight: 600;
|
|
color: #0f172a;
|
|
margin-bottom: 0.5rem;
|
|
}
|
|
|
|
.action-card p {
|
|
color: #64748b;
|
|
font-size: 0.875rem;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.source-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.text-success {
|
|
color: #10b981;
|
|
}
|
|
|
|
.record-count {
|
|
font-weight: 600;
|
|
color: #0f172a;
|
|
}
|
|
|
|
.batch-id {
|
|
background: #f1f5f9;
|
|
padding: 0.25rem 0.5rem;
|
|
border-radius: 0.25rem;
|
|
font-family: monospace;
|
|
font-size: 0.75rem;
|
|
color: #475569;
|
|
}
|
|
|
|
.employee-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
gap: 1rem;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.employee-card {
|
|
background: #f8fafc;
|
|
border: 1px solid #e2e8f0;
|
|
border-radius: 0.5rem;
|
|
padding: 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
transition: all 0.2s ease-in-out;
|
|
}
|
|
|
|
.employee-card:hover {
|
|
background: #ffffff;
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.employee-card.view-all {
|
|
background: #8b5cf6;
|
|
border-color: #8b5cf6;
|
|
color: #ffffff;
|
|
justify-content: center;
|
|
text-align: center;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.view-all-content {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
}
|
|
|
|
.view-all-content i {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 0.25rem;
|
|
}
|
|
|
|
.employee-card .employee-avatar {
|
|
width: 40px;
|
|
height: 40px;
|
|
background: linear-gradient(135deg, #8b5cf6, #7c3aed);
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: #ffffff;
|
|
font-size: 0.875rem;
|
|
font-weight: 600;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.employee-card .employee-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.employee-card .employee-name {
|
|
font-weight: 600;
|
|
color: #0f172a;
|
|
margin-bottom: 0.125rem;
|
|
}
|
|
|
|
.employee-card .employee-id {
|
|
color: #64748b;
|
|
font-size: 0.75rem;
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.employee-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.form-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %} |