328 lines
8.5 KiB
HTML
328 lines
8.5 KiB
HTML
{% extends "base.html" %}
|
|
{% block content %}
|
|
|
|
<style>
|
|
/* QZ Pairing Key Management Card */
|
|
.qz-pairing-card {
|
|
max-width: 800px;
|
|
margin: 40px auto;
|
|
padding: 32px;
|
|
background: var(--card-bg, #fff);
|
|
border-radius: 12px;
|
|
box-shadow: 0 2px 12px rgba(0,0,0,0.1);
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.qz-pairing-card h2 {
|
|
color: var(--text-color, #333);
|
|
margin-bottom: 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
|
|
.qz-pairing-card h3 {
|
|
color: var(--text-color, #333);
|
|
margin-top: 32px;
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.qz-form-group {
|
|
margin-bottom: 24px;
|
|
}
|
|
|
|
.qz-form-group label {
|
|
display: inline-block;
|
|
font-weight: 600;
|
|
color: var(--label-color, #555);
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.qz-form-group input[type="text"] {
|
|
padding: 8px 12px;
|
|
border: 1px solid var(--input-border, #ddd);
|
|
border-radius: 6px;
|
|
background: var(--input-bg, #fff);
|
|
color: var(--text-color, #333);
|
|
font-size: 1em;
|
|
min-width: 250px;
|
|
}
|
|
|
|
.qz-form-group input[type="text"]:focus {
|
|
outline: none;
|
|
border-color: #2196f3;
|
|
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
|
|
}
|
|
|
|
.qz-form-group select {
|
|
padding: 8px 12px;
|
|
border: 1px solid var(--input-border, #ddd);
|
|
border-radius: 6px;
|
|
background: var(--input-bg, #fff);
|
|
color: var(--text-color, #333);
|
|
font-size: 1em;
|
|
min-width: 150px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.qz-form-group select:focus {
|
|
outline: none;
|
|
border-color: #2196f3;
|
|
box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.1);
|
|
}
|
|
|
|
.qz-form-group button {
|
|
padding: 8px 20px;
|
|
background: #4caf50;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 6px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.qz-form-group button:hover {
|
|
background: #388e3c;
|
|
}
|
|
|
|
.btn-delete {
|
|
padding: 4px 12px;
|
|
background: #dc3545;
|
|
color: white;
|
|
border: none;
|
|
border-radius: 4px;
|
|
font-size: 0.875em;
|
|
cursor: pointer;
|
|
transition: background 0.2s;
|
|
}
|
|
|
|
.btn-delete:hover {
|
|
background: #c82333;
|
|
}
|
|
|
|
.form-row {
|
|
display: flex;
|
|
gap: 12px;
|
|
align-items: flex-end;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.form-field {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.qz-result {
|
|
margin-top: 20px;
|
|
padding: 16px;
|
|
background: var(--result-bg, #e8f5e9);
|
|
border-left: 4px solid #4caf50;
|
|
border-radius: 6px;
|
|
}
|
|
|
|
.qz-result strong {
|
|
color: var(--result-label, #2e7d32);
|
|
}
|
|
|
|
.qz-result span {
|
|
font-family: 'Courier New', monospace;
|
|
background: var(--code-bg, #c8e6c9);
|
|
padding: 2px 6px;
|
|
border-radius: 3px;
|
|
color: var(--code-text, #1b5e20);
|
|
}
|
|
|
|
.qz-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
margin-top: 16px;
|
|
}
|
|
|
|
.qz-table thead tr {
|
|
background: var(--table-header-bg, #f0f0f0);
|
|
}
|
|
|
|
.qz-table th {
|
|
padding: 12px;
|
|
border: 1px solid var(--table-border, #ccc);
|
|
text-align: left;
|
|
font-weight: 600;
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.qz-table td {
|
|
padding: 12px;
|
|
border: 1px solid var(--table-border, #ccc);
|
|
color: var(--text-color, #333);
|
|
}
|
|
|
|
.qz-table tbody tr:hover {
|
|
background: var(--table-hover, #f5f5f5);
|
|
}
|
|
|
|
.qz-table-code {
|
|
font-family: 'Courier New', monospace;
|
|
background: var(--code-bg, #f5f5f5);
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
color: var(--code-text, #333);
|
|
}
|
|
|
|
/* Dark Mode Support */
|
|
body.dark-mode .qz-pairing-card {
|
|
background: #2d2d2d;
|
|
color: #e0e0e0;
|
|
--card-bg: #2d2d2d;
|
|
--text-color: #e0e0e0;
|
|
}
|
|
|
|
body.dark-mode .qz-form-group label {
|
|
color: #bbb;
|
|
--label-color: #bbb;
|
|
}
|
|
|
|
body.dark-mode .qz-form-group input[type="text"],
|
|
body.dark-mode .qz-form-group select {
|
|
background: #3a3a3a;
|
|
border-color: #555;
|
|
color: #e0e0e0;
|
|
--input-bg: #3a3a3a;
|
|
--input-border: #555;
|
|
}
|
|
|
|
body.dark-mode .qz-result {
|
|
background: #1b5e20;
|
|
--result-bg: #1b5e20;
|
|
}
|
|
|
|
body.dark-mode .qz-result strong {
|
|
color: #a5d6a7;
|
|
--result-label: #a5d6a7;
|
|
}
|
|
|
|
body.dark-mode .qz-result span {
|
|
background: #2e7d32;
|
|
color: #c8e6c9;
|
|
--code-bg: #2e7d32;
|
|
--code-text: #c8e6c9;
|
|
}
|
|
|
|
body.dark-mode .qz-table thead tr {
|
|
background: #3a3a3a;
|
|
--table-header-bg: #3a3a3a;
|
|
}
|
|
|
|
body.dark-mode .qz-table th,
|
|
body.dark-mode .qz-table td {
|
|
border-color: #555;
|
|
color: #e0e0e0;
|
|
--table-border: #555;
|
|
}
|
|
|
|
body.dark-mode .qz-table tbody tr:hover {
|
|
background: #3a3a3a;
|
|
--table-hover: #3a3a3a;
|
|
}
|
|
|
|
body.dark-mode .qz-table-code {
|
|
background: #3a3a3a;
|
|
color: #90caf9;
|
|
--code-bg: #3a3a3a;
|
|
--code-text: #90caf9;
|
|
}
|
|
</style>
|
|
|
|
<div class="qz-pairing-card">
|
|
<h2>🔐 QZ Tray Pairing Key Management</h2>
|
|
|
|
<form id="pairing-form" method="POST" action="/generate_pairing_key" class="qz-form-group">
|
|
<div class="form-row">
|
|
<div class="form-field">
|
|
<label for="printer_name">Printer Name:</label>
|
|
<input type="text" id="printer_name" name="printer_name" required placeholder="Enter printer name">
|
|
</div>
|
|
|
|
<div class="form-field">
|
|
<label for="validity_days">Validity Period:</label>
|
|
<select id="validity_days" name="validity_days">
|
|
<option value="30">30 Days</option>
|
|
<option value="60">60 Days</option>
|
|
<option value="90" selected>90 Days (Default)</option>
|
|
<option value="180">180 Days (6 Months)</option>
|
|
<option value="365">365 Days (1 Year)</option>
|
|
<option value="730">730 Days (2 Years)</option>
|
|
<option value="1825">1825 Days (5 Years)</option>
|
|
</select>
|
|
</div>
|
|
|
|
<button type="submit">🔑 Generate Pairing Key</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div id="pairing-result">
|
|
{% if pairing_key %}
|
|
<div class="qz-result">
|
|
<div style="margin-bottom: 8px;">
|
|
<strong>🔑 Pairing Key:</strong> <span>{{ pairing_key }}</span>
|
|
</div>
|
|
<div style="margin-bottom: 8px;">
|
|
<strong>🖨️ Printer Name:</strong> {{ printer_name }}
|
|
</div>
|
|
<div>
|
|
<strong>⏰ Valid Until:</strong> {{ warranty_until }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<h3>📋 Active Pairing Keys</h3>
|
|
<table class="qz-table">
|
|
<thead>
|
|
<tr>
|
|
<th>🖨️ Printer Name</th>
|
|
<th>🔑 Pairing Key</th>
|
|
<th>⏰ Valid Until</th>
|
|
<th>🛠️ Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for key in pairing_keys %}
|
|
<tr>
|
|
<td>{{ key.printer_name }}</td>
|
|
<td><span class="qz-table-code">{{ key.pairing_key }}</span></td>
|
|
<td>{{ key.warranty_until }}</td>
|
|
<td>
|
|
<button class="btn-delete" onclick="deletePairingKey('{{ key.pairing_key }}', '{{ key.printer_name }}')">
|
|
🗑️ Delete
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script>
|
|
function deletePairingKey(pairingKey, printerName) {
|
|
if (confirm(`Are you sure you want to delete the pairing key for "${printerName}"?\n\nKey: ${pairingKey}\n\nThis action cannot be undone.`)) {
|
|
// Create a form and submit it
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '/delete_pairing_key';
|
|
|
|
const keyInput = document.createElement('input');
|
|
keyInput.type = 'hidden';
|
|
keyInput.name = 'pairing_key';
|
|
keyInput.value = pairingKey;
|
|
|
|
form.appendChild(keyInput);
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
}
|
|
</script>
|
|
|
|
{% endblock %}
|