基础的切片和质量控制
This commit is contained in:
132
app/templates/files.html
Normal file
132
app/templates/files.html
Normal file
@@ -0,0 +1,132 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-4 border-bottom">
|
||||
<h1 class="h2"><i class="bi bi-files me-2 text-warning"></i>{{ _('My Files') }}</h1>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-sm border-0">
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-striped mb-0 align-middle">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th class="ps-4 fw-semibold text-secondary">{{ _('Date Uploaded') }}</th>
|
||||
<th class="fw-semibold text-secondary">{{ _('Original Name') }}</th>
|
||||
<th class="fw-semibold text-secondary">{{ _('Status') }}</th>
|
||||
<th class="pe-4 fw-semibold text-secondary">{{ _('Actions') }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for file in files %}
|
||||
<tr id="file-row-{{ file.id }}" data-status="{{ file.status }}">
|
||||
<td class="ps-4 text-muted"><i class="bi bi-clock me-1"></i>{{ file.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</td>
|
||||
<td class="fw-medium">{{ file.original_filename }}</td>
|
||||
<td id="status-{{ file.id }}">
|
||||
{% if file.status == 'waiting' or file.status == 'uploaded' %}
|
||||
<span class="badge bg-info text-dark rounded-pill fw-normal px-2" title="{{ _('Waiting in queue for slicing') }}"><i class="bi bi-hourglass-split me-1"></i>{{ _('Waiting') }}...</span>
|
||||
{% elif file.status == 'slicing' %}
|
||||
<span class="badge bg-warning text-dark rounded-pill fw-normal px-2"><i class="bi bi-gear-wide-connected bi-spin me-1"></i>{{ _('Slicing') }}...</span>
|
||||
{% elif file.status == 'sliced' %}
|
||||
<span class="badge bg-success rounded-pill fw-normal px-2"><i class="bi bi-check-circle me-1"></i>{{ _('Sliced') }}</span>
|
||||
{% elif file.status == 'failed' %}
|
||||
<span class="badge bg-danger rounded-pill fw-normal px-2"><i class="bi bi-x-circle me-1"></i>{{ _('Failed') }}</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td class="pe-4">
|
||||
<div class="d-flex gap-2" id="actions-container-{{ file.id }}">
|
||||
{% if file.status == 'sliced' %}
|
||||
<a href="{{ url_for('main.download_gcode', file_id=file.id) }}" class="btn btn-sm btn-outline-primary shadow-sm" title="{{ _('Download GCode') }}"><i class="bi bi-download"></i></a>
|
||||
<a href="{{ url_for('main.preview_gcode', file_id=file.id) }}" class="btn btn-sm btn-outline-info shadow-sm" title="{{ _('GCode Preview') }}"><i class="bi bi-eye"></i></a>
|
||||
{% endif %}
|
||||
<form action="{{ url_for('main.delete_file', file_id=file.id) }}" method="POST" onsubmit="return confirm('{{ _('Are you sure you want to delete this file?') }}');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger shadow-sm" title="{{ _('Delete') }}"><i class="bi bi-trash3"></i></button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% else %}
|
||||
<tr>
|
||||
<td colspan="4" class="text-center text-muted py-5">
|
||||
<i class="bi bi-folder-x display-4 d-block mb-3 opacity-50"></i>
|
||||
{{ _('No files uploaded yet.') }}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const checkInterval = 1000;
|
||||
let pollTimer = null;
|
||||
|
||||
function fetchStatus() {
|
||||
fetch(`{{ url_for('main.files_status') }}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
let hasPending = false;
|
||||
for (const [id, status] of Object.entries(data)) {
|
||||
const tr = document.getElementById('file-row-' + id);
|
||||
if (!tr) continue;
|
||||
|
||||
const currentStatus = tr.getAttribute('data-status');
|
||||
if (currentStatus !== status) {
|
||||
// Change DOM state
|
||||
tr.setAttribute('data-status', status);
|
||||
const statusTd = document.getElementById('status-' + id);
|
||||
const actionsTd = document.getElementById('actions-container-' + id);
|
||||
|
||||
// Update Status Badge HTML correctly preserving translations
|
||||
if (status === 'waiting' || status === 'uploaded') statusTd.innerHTML = '<span class="badge bg-info text-dark rounded-pill fw-normal px-2" title="{{ _("Waiting in queue for slicing") }}"><i class="bi bi-hourglass-split me-1"></i>{{ _("Waiting") }}...</span>';
|
||||
else if (status === 'slicing') statusTd.innerHTML = '<span class="badge bg-warning text-dark rounded-pill fw-normal px-2"><i class="bi bi-gear-wide-connected bi-spin me-1"></i>{{ _("Slicing") }}...</span>';
|
||||
else if (status === 'sliced') statusTd.innerHTML = '<span class="badge bg-success rounded-pill fw-normal px-2"><i class="bi bi-check-circle me-1"></i>{{ _("Sliced") }}</span>';
|
||||
else if (status === 'failed') statusTd.innerHTML = '<span class="badge bg-danger rounded-pill fw-normal px-2"><i class="bi bi-x-circle me-1"></i>{{ _("Failed") }}</span>';
|
||||
|
||||
// Update Actions HTML
|
||||
let actionsHtml = '';
|
||||
if (status === 'sliced') {
|
||||
const downloadUrl = `{{ url_for('main.download_gcode', file_id=999999999) }}`.replace('999999999', id);
|
||||
const previewUrl = `{{ url_for('main.preview_gcode', file_id=999999999) }}`.replace('999999999', id);
|
||||
actionsHtml += `<a href="${downloadUrl}" class="btn btn-sm btn-outline-primary shadow-sm" title="{{ _('Download GCode') }}"><i class="bi bi-download"></i></a>\n`;
|
||||
actionsHtml += `<a href="${previewUrl}" class="btn btn-sm btn-outline-info shadow-sm" title="{{ _('GCode Preview') }}"><i class="bi bi-eye"></i></a>\n`;
|
||||
}
|
||||
const deleteUrl = `{{ url_for('main.delete_file', file_id=999999999) }}`.replace('999999999', id);
|
||||
actionsHtml += `<form action="${deleteUrl}" method="POST" onsubmit="return confirm('{{ _('Are you sure you want to delete this file?') }}');">
|
||||
<button type="submit" class="btn btn-sm btn-outline-danger shadow-sm" title="{{ _('Delete') }}"><i class="bi bi-trash3"></i></button>
|
||||
</form>`;
|
||||
actionsTd.innerHTML = actionsHtml;
|
||||
}
|
||||
|
||||
if (status === 'waiting' || status === 'uploaded' || status === 'slicing') {
|
||||
hasPending = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Stop polling if there are no more pending files in the user's scope
|
||||
if (!hasPending && pollTimer) {
|
||||
clearInterval(pollTimer);
|
||||
pollTimer = null;
|
||||
}
|
||||
})
|
||||
.catch(error => console.error('Error fetching file statuses:', error));
|
||||
}
|
||||
|
||||
// Check initially if we have any pending slices
|
||||
let needsPolling = false;
|
||||
document.querySelectorAll('tr[id^="file-row-"]').forEach(row => {
|
||||
const st = row.getAttribute('data-status');
|
||||
if (st === 'waiting' || st === 'uploaded' || st === 'slicing') {
|
||||
needsPolling = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (needsPolling) {
|
||||
pollTimer = setInterval(fetchStatus, checkInterval);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user