nordabiz/templates/admin/zopk_knowledge_entities.html
Maciej Pienczyn 6d1f75bce5 fix(admin): Naprawiono błędne nazwy endpointów w breadcrumbs
Zmieniono admin_dashboard i admin_zopk_dashboard na admin_zopk

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 09:03:01 +01:00

447 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{% extends "base.html" %}
{% block title %}Encje - Baza Wiedzy ZOPK{% endblock %}
{% block extra_css %}
<style>
.page-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-xl);
flex-wrap: wrap;
gap: var(--spacing-md);
}
.page-header h1 {
font-size: var(--font-size-2xl);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.breadcrumb {
display: flex;
align-items: center;
gap: var(--spacing-xs);
font-size: var(--font-size-sm);
color: var(--text-secondary);
margin-bottom: var(--spacing-md);
}
.breadcrumb a {
color: var(--text-secondary);
text-decoration: none;
}
.breadcrumb a:hover {
color: var(--primary);
}
.filters {
display: flex;
gap: var(--spacing-md);
margin-bottom: var(--spacing-lg);
flex-wrap: wrap;
align-items: center;
background: var(--surface);
padding: var(--spacing-md);
border-radius: var(--radius);
}
.filter-btn {
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius);
border: 1px solid var(--border);
background: var(--surface);
text-decoration: none;
color: var(--text-secondary);
font-size: var(--font-size-sm);
transition: var(--transition);
cursor: pointer;
}
.filter-btn:hover {
background: var(--background);
color: var(--text-primary);
}
.filter-btn.active {
background: var(--primary);
border-color: var(--primary);
color: white;
}
.table-wrapper {
overflow-x: auto;
background: var(--surface);
border-radius: var(--radius-lg);
box-shadow: var(--shadow);
}
.data-table {
width: 100%;
min-width: 800px;
}
.data-table th,
.data-table td {
padding: var(--spacing-md);
text-align: left;
border-bottom: 1px solid var(--border);
}
.data-table th {
background: var(--background);
font-weight: 600;
font-size: var(--font-size-sm);
color: var(--text-secondary);
}
.data-table tr:hover {
background: var(--background);
}
.entity-name {
font-weight: 600;
}
.entity-description {
font-size: var(--font-size-xs);
color: var(--text-secondary);
margin-top: var(--spacing-xs);
max-width: 300px;
}
.entity-aliases {
font-size: var(--font-size-xs);
color: var(--text-tertiary);
margin-top: var(--spacing-xs);
}
.entity-type-badge {
padding: 2px 8px;
border-radius: var(--radius-sm);
font-size: var(--font-size-xs);
font-weight: 500;
}
.entity-type-company { background: #dbeafe; color: #1e40af; }
.entity-type-person { background: #fce7f3; color: #be185d; }
.entity-type-place { background: #d1fae5; color: #065f46; }
.entity-type-organization { background: #fef3c7; color: #92400e; }
.entity-type-project { background: #e0e7ff; color: #3730a3; }
.entity-type-technology { background: #f3e8ff; color: #7c3aed; }
.entity-type-event { background: #fce7f3; color: #be185d; }
.mentions-count {
font-weight: 600;
font-size: var(--font-size-lg);
color: var(--primary);
}
.mentions-bar {
width: 100px;
height: 6px;
background: var(--border);
border-radius: 3px;
margin-top: var(--spacing-xs);
overflow: hidden;
}
.mentions-bar-fill {
height: 100%;
background: var(--primary);
border-radius: 3px;
}
.status-badge {
display: inline-block;
padding: 2px 8px;
border-radius: var(--radius-sm);
font-size: var(--font-size-xs);
font-weight: 500;
}
.status-verified { background: #d1fae5; color: #065f46; }
.status-pending { background: #fef3c7; color: #92400e; }
.action-btn {
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--radius-sm);
border: none;
cursor: pointer;
font-size: var(--font-size-xs);
transition: var(--transition);
margin-right: var(--spacing-xs);
}
.action-btn-verify {
background: #d1fae5;
color: #065f46;
}
.action-btn-verify:hover {
background: #065f46;
color: white;
}
.action-btn-link {
background: #dbeafe;
color: #1e40af;
text-decoration: none;
}
.action-btn-link:hover {
background: #1e40af;
color: white;
}
.pagination {
display: flex;
justify-content: center;
gap: var(--spacing-xs);
padding: var(--spacing-lg);
}
.pagination a,
.pagination span {
padding: var(--spacing-sm) var(--spacing-md);
border-radius: var(--radius);
text-decoration: none;
font-size: var(--font-size-sm);
border: 1px solid var(--border);
background: var(--surface);
color: var(--text-primary);
}
.pagination a:hover {
background: var(--primary);
border-color: var(--primary);
color: white;
}
.pagination .current {
background: var(--primary);
border-color: var(--primary);
color: white;
}
.pagination .disabled {
opacity: 0.5;
pointer-events: none;
}
.stats-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: var(--spacing-md);
background: var(--background);
border-radius: var(--radius);
margin-bottom: var(--spacing-md);
font-size: var(--font-size-sm);
}
.entity-dates {
font-size: var(--font-size-xs);
color: var(--text-tertiary);
}
</style>
{% endblock %}
{% block content %}
<div class="container">
<div class="breadcrumb">
<a href="{{ url_for('admin_zopk') }}">Panel Admina</a>
<span></span>
<a href="{{ url_for('admin_zopk') }}">ZOP Kaszubia</a>
<span></span>
<a href="{{ url_for('admin_zopk_knowledge_dashboard') }}">Baza Wiedzy</a>
<span></span>
<span>Encje</span>
</div>
<div class="page-header">
<h1>🏢 Encje (rozpoznane byty)</h1>
</div>
<!-- Filters -->
<div class="filters">
<span style="color: var(--text-secondary); font-size: var(--font-size-sm);">Typ encji:</span>
<a href="{{ url_for('admin_zopk_knowledge_entities') }}"
class="filter-btn {{ 'active' if current_entity_type is none else '' }}">
Wszystkie
</a>
{% for etype in entity_types %}
<a href="{{ url_for('admin_zopk_knowledge_entities', entity_type=etype) }}"
class="filter-btn {{ 'active' if current_entity_type == etype else '' }}">
{% if etype == 'company' %}🏢{% elif etype == 'person' %}👤{% elif etype == 'place' %}📍{% elif etype == 'organization' %}🏛️{% elif etype == 'project' %}🚀{% elif etype == 'technology' %}💻{% else %}📋{% endif %}
{{ etype }}
</a>
{% endfor %}
<span style="margin-left: 20px; color: var(--text-secondary); font-size: var(--font-size-sm);">Status:</span>
<a href="{{ url_for('admin_zopk_knowledge_entities', is_verified='true', entity_type=current_entity_type) }}"
class="filter-btn {{ 'active' if is_verified == true else '' }}">
✓ Zweryfikowane
</a>
<a href="{{ url_for('admin_zopk_knowledge_entities', is_verified='false', entity_type=current_entity_type) }}"
class="filter-btn {{ 'active' if is_verified == false else '' }}">
⏳ Oczekujące
</a>
<span style="margin-left: 20px; color: var(--text-secondary); font-size: var(--font-size-sm);">Min. wzmianek:</span>
<a href="{{ url_for('admin_zopk_knowledge_entities', min_mentions=5, entity_type=current_entity_type) }}"
class="filter-btn {{ 'active' if min_mentions == 5 else '' }}">
5+
</a>
<a href="{{ url_for('admin_zopk_knowledge_entities', min_mentions=10, entity_type=current_entity_type) }}"
class="filter-btn {{ 'active' if min_mentions == 10 else '' }}">
10+
</a>
<a href="{{ url_for('admin_zopk_knowledge_entities', min_mentions=20, entity_type=current_entity_type) }}"
class="filter-btn {{ 'active' if min_mentions == 20 else '' }}">
20+
</a>
</div>
<!-- Stats Bar -->
<div class="stats-bar">
<span>Pokazuję {{ entities|length }} z {{ total }} encji (strona {{ page }} z {{ pages }})</span>
<span>Posortowane według liczby wzmianek (malejąco)</span>
</div>
<!-- Table -->
<div class="table-wrapper">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>Nazwa</th>
<th>Typ</th>
<th>Wzmianki</th>
<th>Status</th>
<th>Daty</th>
<th>Akcje</th>
</tr>
</thead>
<tbody>
{% set max_mentions = entities[0].mentions_count if entities else 1 %}
{% for entity in entities %}
<tr id="entity-row-{{ entity.id }}">
<td>#{{ entity.id }}</td>
<td>
<div class="entity-name">{{ entity.name }}</div>
{% if entity.short_description %}
<div class="entity-description">{{ entity.short_description }}</div>
{% endif %}
{% if entity.aliases and entity.aliases|length %}
<div class="entity-aliases">
Aliasy: {{ entity.aliases|join(', ') }}
</div>
{% endif %}
</td>
<td>
<span class="entity-type-badge entity-type-{{ entity.entity_type }}">
{% if entity.entity_type == 'company' %}🏢{% elif entity.entity_type == 'person' %}👤{% elif entity.entity_type == 'place' %}📍{% elif entity.entity_type == 'organization' %}🏛️{% elif entity.entity_type == 'project' %}🚀{% elif entity.entity_type == 'technology' %}💻{% else %}📋{% endif %}
{{ entity.entity_type }}
</span>
</td>
<td>
<div class="mentions-count">{{ entity.mentions_count }}</div>
<div class="mentions-bar">
<div class="mentions-bar-fill" style="width: {{ (entity.mentions_count / max_mentions * 100)|round }}%"></div>
</div>
</td>
<td>
{% if entity.is_verified %}
<span class="status-badge status-verified">✓ Zweryfikowana</span>
{% else %}
<span class="status-badge status-pending">⏳ Oczekuje</span>
{% endif %}
{% if entity.company_id %}
<br><a href="{{ url_for('company_detail', slug=entity.company_id) }}" class="action-btn-link" style="font-size: 10px;">→ Firma Norda</a>
{% endif %}
</td>
<td class="entity-dates">
{% if entity.first_mentioned_at %}
<div>Pierwsza: {{ entity.first_mentioned_at[:10] }}</div>
{% endif %}
{% if entity.last_mentioned_at %}
<div>Ostatnia: {{ entity.last_mentioned_at[:10] }}</div>
{% endif %}
</td>
<td>
<button class="action-btn action-btn-verify" onclick="toggleVerify({{ entity.id }}, {{ 'false' if entity.is_verified else 'true' }})">
{{ '✗' if entity.is_verified else '✓' }}
</button>
{% if entity.external_url %}
<a href="{{ entity.external_url }}" target="_blank" class="action-btn action-btn-link">🔗</a>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="7" style="text-align: center; padding: var(--spacing-xl); color: var(--text-secondary);">
Brak encji do wyświetlenia
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<!-- Pagination -->
{% if pages > 1 %}
<div class="pagination">
{% if page > 1 %}
<a href="{{ url_for('admin_zopk_knowledge_entities', page=page-1, entity_type=current_entity_type, is_verified=is_verified, min_mentions=min_mentions) }}"> Poprzednia</a>
{% else %}
<span class="disabled"> Poprzednia</span>
{% endif %}
{% for p in range(1, pages + 1) %}
{% if p == page %}
<span class="current">{{ p }}</span>
{% elif p <= 3 or p >= pages - 2 or (p >= page - 1 and p <= page + 1) %}
<a href="{{ url_for('admin_zopk_knowledge_entities', page=p, entity_type=current_entity_type, is_verified=is_verified, min_mentions=min_mentions) }}">{{ p }}</a>
{% elif p == 4 or p == pages - 3 %}
<span>...</span>
{% endif %}
{% endfor %}
{% if page < pages %}
<a href="{{ url_for('admin_zopk_knowledge_entities', page=page+1, entity_type=current_entity_type, is_verified=is_verified, min_mentions=min_mentions) }}">Następna </a>
{% else %}
<span class="disabled">Następna </span>
{% endif %}
</div>
{% endif %}
</div>
{% endblock %}
{% block extra_js %}
async function toggleVerify(id, newState) {
try {
const response = await fetch(`/api/zopk/knowledge/entities/${id}/verify`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': '{{ csrf_token() }}'
},
body: JSON.stringify({ is_verified: newState })
});
const data = await response.json();
if (data.success) {
location.reload();
} else {
alert('Błąd: ' + data.error);
}
} catch (error) {
alert('Błąd: ' + error.message);
}
}
{% endblock %}