bump project
This commit is contained in:
46
app/templates/people/detail.html
Normal file
46
app/templates/people/detail.html
Normal file
@@ -0,0 +1,46 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}{{ person.full_name }} · Face Attendance{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<p class="eyebrow">Person profile</p>
|
||||
<h1>{{ person.full_name }}</h1>
|
||||
<p class="text-secondary mb-0">{{ person.employee_id }} · {{ "Active" if person.active else "Inactive" }}</p>
|
||||
</div>
|
||||
<a class="btn btn-outline-secondary" href="{{ url_for('people.index') }}">Back</a>
|
||||
</div>
|
||||
|
||||
<div class="detail-grid">
|
||||
<section class="content-section">
|
||||
<h2>Profile</h2>
|
||||
<dl class="detail-list">
|
||||
<dt>Employee ID</dt>
|
||||
<dd>{{ person.employee_id }}</dd>
|
||||
<dt>Face samples</dt>
|
||||
<dd>{{ person.face_encodings|length }}</dd>
|
||||
<dt>Last presence</dt>
|
||||
<dd>{{ presence_summary }}</dd>
|
||||
<dt>Notes</dt>
|
||||
<dd>{{ person.notes or "No notes" }}</dd>
|
||||
</dl>
|
||||
</section>
|
||||
|
||||
<section class="content-section">
|
||||
<h2>Recent events</h2>
|
||||
{% if events %}
|
||||
<div class="event-list">
|
||||
{% for event in events %}
|
||||
<div class="event-row">
|
||||
<span class="badge text-bg-{{ 'success' if event.event_type == 'check_in' else 'warning' }}">{{ event.type_label }}</span>
|
||||
<span>{{ event.occurred_at.strftime("%Y-%m-%d %H:%M") }}</span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">No attendance events for this person.</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
</div>
|
||||
{% endblock %}
|
||||
39
app/templates/people/form.html
Normal file
39
app/templates/people/form.html
Normal file
@@ -0,0 +1,39 @@
|
||||
{% extends "base.html" %}
|
||||
{% from "macros/forms.html" import render_field, render_textarea %}
|
||||
|
||||
{% block title %}Enroll person · Face Attendance{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<p class="eyebrow">Enrollment</p>
|
||||
<h1>Enroll person</h1>
|
||||
</div>
|
||||
<a class="btn btn-outline-secondary" href="{{ url_for('people.index') }}">Back</a>
|
||||
</div>
|
||||
|
||||
<section class="form-section">
|
||||
<form method="post" enctype="multipart/form-data" novalidate>
|
||||
{{ form.hidden_tag() }}
|
||||
<div class="row g-3">
|
||||
<div class="col-md-6">{{ render_field(form.full_name) }}</div>
|
||||
<div class="col-md-6">{{ render_field(form.employee_id) }}</div>
|
||||
<div class="col-12">{{ render_textarea(form.notes, 3) }}</div>
|
||||
</div>
|
||||
|
||||
<div class="upload-grid">
|
||||
{% for field in [form.photo_1, form.photo_2, form.photo_3, form.photo_4] %}
|
||||
<div>
|
||||
{{ field.label(class="form-label") }}
|
||||
{{ field(class="form-control", accept="image/png,image/jpeg") }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<p class="form-help">Upload one to four clear single-face photos. More samples usually improve recognition quality.</p>
|
||||
<div class="form-actions">
|
||||
{{ form.submit(class="btn btn-primary") }}
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
53
app/templates/people/index.html
Normal file
53
app/templates/people/index.html
Normal file
@@ -0,0 +1,53 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}People · Face Attendance{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<p class="eyebrow">Enrollment</p>
|
||||
<h1>People</h1>
|
||||
</div>
|
||||
{% if current_user.can_operate %}
|
||||
<a class="btn btn-primary" href="{{ url_for('people.new_person') }}">Enroll person</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<section class="content-section">
|
||||
{% if people %}
|
||||
<div class="table-responsive">
|
||||
<table class="table align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Employee ID</th>
|
||||
<th>Face samples</th>
|
||||
<th>Status</th>
|
||||
<th class="text-end">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for person in people %}
|
||||
<tr>
|
||||
<td><a href="{{ url_for('people.detail', person_id=person.id) }}">{{ person.full_name }}</a></td>
|
||||
<td>{{ person.employee_id }}</td>
|
||||
<td>{{ person.face_encodings|length }}</td>
|
||||
<td><span class="badge text-bg-{{ 'success' if person.active else 'secondary' }}">{{ "Active" if person.active else "Inactive" }}</span></td>
|
||||
<td class="text-end">
|
||||
{% if current_user.can_operate %}
|
||||
<form method="post" action="{{ url_for('people.toggle_person', person_id=person.id) }}" class="d-inline">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button class="btn btn-outline-secondary btn-sm" type="submit">{{ "Deactivate" if person.active else "Activate" }}</button>
|
||||
</form>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="empty-state">No people have been enrolled yet.</div>
|
||||
{% endif %}
|
||||
</section>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user