576 lines
27 KiB
HTML
Executable File
576 lines
27 KiB
HTML
Executable File
{% extends "base.html" %}
|
||
{% block content %}
|
||
<div style="max-width: 600px; margin: 40px auto; padding: 32px; background: #fff; border-radius: 12px; box-shadow: 0 2px 12px #0002;">
|
||
<h2>QZ Tray Pairing Key Management</h2>
|
||
<form id="pairing-form" method="POST" action="/generate_pairing_key" style="margin-bottom: 32px;">
|
||
<label for="printer_name">Printer Name:</label>
|
||
<input type="text" id="printer_name" name="printer_name" required style="margin: 0 8px 0 8px;">
|
||
<button type="submit">Generate Pairing Key</button>
|
||
</form>
|
||
<div id="pairing-result">
|
||
{% if pairing_key %}
|
||
<div style="margin-bottom: 16px;">
|
||
<strong>Pairing Key:</strong> <span style="font-family: monospace;">{{ pairing_key }}</span><br>
|
||
<strong>Printer Name:</strong> {{ printer_name }}<br>
|
||
<strong>Valid Until:</strong> {{ warranty_until }}
|
||
</div>
|
||
{% endif %}
|
||
</div>
|
||
<h3>Active Pairing Keys</h3>
|
||
<table style="width:100%; border-collapse:collapse;">
|
||
<thead>
|
||
<tr style="background:#f0f0f0;">
|
||
<th style="padding:8px; border:1px solid #ccc;">Printer Name</th>
|
||
<th style="padding:8px; border:1px solid #ccc;">Pairing Key</th>
|
||
<th style="padding:8px; border:1px solid #ccc;">Valid Until</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{% for key in pairing_keys %}
|
||
<tr>
|
||
<td style="padding:8px; border:1px solid #ccc;">{{ key.printer_name }}</td>
|
||
<td style="padding:8px; border:1px solid #ccc; font-family:monospace;">{{ key.pairing_key }}</td>
|
||
<td style="padding:8px; border:1px solid #ccc;">{{ key.warranty_until }}</td>
|
||
</tr>
|
||
{% endfor %}
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<script>
|
||
// Optionally add AJAX for key generation if you want dynamic updates
|
||
</script>
|
||
<ul>
|
||
<li>⚡ <strong>Silent Printing</strong> - No user interaction needed</li>
|
||
<li><EFBFBD>️ <strong>Direct Printer Access</strong> - System-level printing</li>
|
||
<li>🏢 <strong>Enterprise Ready</strong> - Service auto-recovery</li>
|
||
<li><EFBFBD> <strong>Advanced Features</strong> - Multiple print methods</li>
|
||
<li>🛡️ <strong>Self-Contained</strong> - Zero external dependencies</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Download Cards Row -->
|
||
<div class="row justify-content-center">
|
||
<!-- Chrome Extension Card -->
|
||
<div class="col-md-6 mb-4">
|
||
<div class="card h-100 border-success">
|
||
<div class="card-header bg-success text-white text-center">
|
||
<h4 class="mb-0">🌐 Chrome Extension</h4>
|
||
<small>Browser-based printing solution</small>
|
||
</div>
|
||
<div class="card-body d-flex flex-column">
|
||
<div class="alert alert-success">
|
||
<strong>📋 RECOMMENDED:</strong> Easy setup, works everywhere!
|
||
</div>
|
||
|
||
<h5>🎯 Key Features:</h5>
|
||
<ul>
|
||
<li>🖨️ Opens PDF in hidden browser tab and triggers print dialog</li>
|
||
<li>🔍 Automatic extension detection on web page</li>
|
||
<li>📊 Print status feedback and error handling</li>
|
||
<li>🔄 Graceful fallback to PDF download</li>
|
||
<li>⚙️ Works with any printer Chrome can access</li>
|
||
<li>🌍 Cross-platform (Windows, Mac, Linux)</li>
|
||
</ul>
|
||
|
||
<h5>🚀 Quick Install (3 steps):</h5>
|
||
<ol>
|
||
<li>Download and extract the extension files</li>
|
||
<li>Open Chrome → <code>chrome://extensions/</code></li>
|
||
<li>Enable <strong>"Developer mode"</strong> → Click <strong>"Load unpacked"</strong> → Select folder</li>
|
||
</ol>
|
||
|
||
<div class="text-center mt-auto">
|
||
<button class="btn btn-success btn-lg mb-3" id="download-extension-btn">
|
||
📥 Download Chrome Extension
|
||
</button>
|
||
<br>
|
||
<small class="text-muted">Extension package (~10KB)</small>
|
||
|
||
<hr>
|
||
<div class="text-center">
|
||
<small class="text-muted">Individual files for inspection:</small><br>
|
||
<a href="{{ url_for('main.extension_files', filename='manifest.json') }}" target="_blank" class="btn btn-sm btn-outline-secondary">manifest.json</a>
|
||
<a href="{{ url_for('main.extension_files', filename='background.js') }}" target="_blank" class="btn btn-sm btn-outline-secondary">background.js</a>
|
||
<a href="{{ url_for('main.extension_files', filename='content.js') }}" target="_blank" class="btn btn-sm btn-outline-secondary">content.js</a>
|
||
<a href="{{ url_for('main.extension_files', filename='popup.html') }}" target="_blank" class="btn btn-sm btn-outline-secondary">popup.html</a>
|
||
<a href="{{ url_for('main.extension_files', filename='popup.js') }}" target="_blank" class="btn btn-sm btn-outline-secondary">popup.js</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Windows Service Card -->
|
||
<div class="col-md-6 mb-4">
|
||
<div class="card h-100 border-primary">
|
||
<div class="card-header bg-primary text-white text-center">
|
||
<h4 class="mb-0">🔧 Windows Print Service</h4>
|
||
<small>Enterprise-grade silent printing with Error 1053 fixes</small>
|
||
</div>
|
||
<div class="card-body d-flex flex-column">
|
||
<div class="alert alert-primary">
|
||
<strong>🏢 ENTERPRISE:</strong> Silent printing with no user interaction!
|
||
</div>
|
||
|
||
<div class="alert alert-success" style="background-color: #d1f2eb; border-color: #a3e4d7; color: #0e6b49;">
|
||
<strong>🆕 NEW: Error 1053 FIXED!</strong><br>
|
||
<small>✅ Multiple installation methods with automatic fallback<br>
|
||
✅ Enhanced Windows Service Communication<br>
|
||
✅ Comprehensive diagnostic and troubleshooting tools</small>
|
||
</div>
|
||
|
||
<h5>🎯 Key Features:</h5>
|
||
<ul>
|
||
<li>⚡ Silent printing - no print dialogs</li>
|
||
<li>🖨️ Direct system printer access</li>
|
||
<li>🔄 Multiple print methods (Adobe, SumatraPDF, PowerShell)</li>
|
||
<li>🛡️ Windows service with auto-recovery</li>
|
||
<li>📦 Self-contained - zero dependencies</li>
|
||
<li>🏢 Perfect for production environments</li>
|
||
<li><strong style="color: #dc3545;">🔧 Error 1053 fixes included</strong></li>
|
||
</ul>
|
||
|
||
<h5>🚀 Quick Install (3 steps):</h5>
|
||
<ol>
|
||
<li>Download and extract the enhanced service package</li>
|
||
<li>Run <code>install_service_ENHANCED.bat</code> as Administrator</li>
|
||
<li>Install Chrome extension (included in package)</li>
|
||
</ol>
|
||
|
||
<div class="text-center mt-auto">
|
||
<div class="btn-group-vertical mb-3" role="group">
|
||
<button class="btn btn-primary btn-lg" id="download-service-btn">
|
||
📥 Download Enhanced Windows Service
|
||
</button>
|
||
<small class="text-muted mb-2">🆕 Includes Error 1053 fixes & multiple installation methods</small>
|
||
</div>
|
||
|
||
<div class="alert alert-info">
|
||
<small>
|
||
<strong>🆕 Enhanced Package (~11MB):</strong> Embedded Python 3.11.9 + Error 1053 fixes<br>
|
||
<strong>✅ Features:</strong> 4 installation methods, diagnostic tools, zero dependencies
|
||
</small>
|
||
</div>
|
||
|
||
<div class="alert alert-warning">
|
||
<small>⚠️ <strong>Windows Only:</strong> Requires Administrator privileges for service installation</small>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Documentation Section -->
|
||
<div class="row justify-content-center mb-4">
|
||
<div class="col-md-10">
|
||
<div class="card border-warning">
|
||
<div class="card-header bg-warning text-dark">
|
||
<h4 class="mb-0">📚 Documentation & Support</h4>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row">
|
||
<div class="col-md-4">
|
||
<div class="card h-100">
|
||
<div class="card-header bg-success text-white text-center">
|
||
<h6 class="mb-0">⚡ Quick Setup Guide</h6>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<p class="card-text">2-minute installation guide with visual steps and troubleshooting tips.</p>
|
||
<a href="/static/documentation/QUICK_SETUP.md" target="_blank" class="btn btn-success">
|
||
📖 Quick Setup
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<div class="card h-100">
|
||
<div class="card-header bg-primary text-white text-center">
|
||
<h6 class="mb-0">📋 Complete Guide</h6>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<p class="card-text">Comprehensive installation documentation with troubleshooting and API reference.</p>
|
||
<a href="/static/documentation/INSTALLATION_GUIDE.md" target="_blank" class="btn btn-primary">
|
||
📚 Full Documentation
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-md-4">
|
||
<div class="card h-100">
|
||
<div class="card-header bg-info text-white text-center">
|
||
<h6 class="mb-0">🛠️ Technical Reference</h6>
|
||
</div>
|
||
<div class="card-body text-center">
|
||
<p class="card-text">Developer documentation with API specs and customization examples.</p>
|
||
<a href="/static/documentation/README.md" target="_blank" class="btn btn-info">
|
||
🔧 Developer Docs
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- System Requirements -->
|
||
<div class="row justify-content-center mb-4">
|
||
<div class="col-md-10">
|
||
<div class="card border-secondary">
|
||
<div class="card-header bg-secondary text-white">
|
||
<h4 class="mb-0">⚙️ System Requirements & Information</h4>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="row">
|
||
<div class="col-md-6">
|
||
<h5>💻 Requirements:</h5>
|
||
<ul>
|
||
<li><strong>Browser:</strong> Google Chrome (any recent version)</li>
|
||
<li><strong>OS:</strong> Windows, Mac, or Linux</li>
|
||
<li><strong>Privileges:</strong> None required (standard user)</li>
|
||
<li><strong>Internet:</strong> Not required (works offline)</li>
|
||
<li><strong>Installation:</strong> Just load extension in Chrome</li>
|
||
</ul>
|
||
</div>
|
||
<div class="col-md-6">
|
||
<h5>🔍 How It Works:</h5>
|
||
<div class="alert alert-light">
|
||
<ol class="mb-0">
|
||
<li>🌐 Web page detects Chrome extension</li>
|
||
<li>🖨️ <strong>Extension Available</strong> → Green "Print Labels (Extension)" button</li>
|
||
<li>📄 <strong>Extension Unavailable</strong> → Blue "Generate PDF" button</li>
|
||
<li>🔄 Extension opens PDF in hidden tab → triggers print dialog</li>
|
||
<li>✅ User selects printer and confirms → automatic cleanup</li>
|
||
</ol>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Action Buttons -->
|
||
<div class="row justify-content-center mb-5">
|
||
<div class="col-md-10 text-center">
|
||
<div class="card border-dark">
|
||
<div class="card-body">
|
||
<h5>🚀 Ready to Test?</h5>
|
||
<p class="text-muted">Installation takes ~2 minutes • Zero maintenance required</p>
|
||
|
||
<!-- Test Extension Button -->
|
||
<div class="alert alert-info">
|
||
<h6>🧪 Test the Extension</h6>
|
||
<p class="mb-2">After installing the extension, click below to test if the print module detects it correctly:</p>
|
||
<button class="btn btn-info mb-2" id="test-extension-btn">
|
||
🔍 Test Extension Detection
|
||
</button>
|
||
<div id="test-results" class="mt-2" style="display: none;"></div>
|
||
</div>
|
||
|
||
<div class="btn-group-vertical btn-group-lg" role="group">
|
||
<a href="{{ url_for('main.print_module') }}" class="btn btn-success btn-lg">
|
||
🖨️ Go to Print Module
|
||
</a>
|
||
<button class="btn btn-secondary" onclick="window.close()">
|
||
↩️ Close Window
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Chrome Extension Download Handler
|
||
document.getElementById('download-extension-btn').addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
// Show loading state
|
||
const originalText = this.innerHTML;
|
||
this.innerHTML = '⏳ Preparing Chrome Extension Package...';
|
||
this.disabled = true;
|
||
|
||
// Create the extension package
|
||
fetch('/create_extension_package', {method: 'POST'})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// Start download
|
||
window.location.href = data.download_url;
|
||
|
||
// Show success message
|
||
setTimeout(() => {
|
||
this.innerHTML = '✅ Download Started!';
|
||
}, 500);
|
||
|
||
// Reset button
|
||
setTimeout(() => {
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
}, 3000);
|
||
} else {
|
||
alert('Error creating extension package: ' + data.error);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
}
|
||
})
|
||
.catch(error => {
|
||
alert('Error: ' + error.message);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
});
|
||
});
|
||
|
||
// Windows Service Download Handler
|
||
document.getElementById('download-service-btn').addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
// Show loading state
|
||
const originalText = this.innerHTML;
|
||
this.innerHTML = '⏳ Preparing Enhanced Service Package...';
|
||
this.disabled = true;
|
||
|
||
// Create the service package
|
||
fetch('/create_service_package', {method: 'POST'})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// Start download
|
||
window.location.href = data.download_url;
|
||
|
||
// Show enhanced success message with features
|
||
const features = data.features ? data.features.join('\n• ') : 'Error 1053 fixes and enhanced installation';
|
||
setTimeout(() => {
|
||
this.innerHTML = '✅ Enhanced Package Downloaded!';
|
||
|
||
// Show feature alert
|
||
if (data.package_type) {
|
||
alert(`✅ ${data.package_type} Downloaded!\n\n🆕 Features included:\n• ${features}\n\n📦 Size: ${(data.zip_size / 1024 / 1024).toFixed(1)} MB\n🔧 Installation methods: ${data.installation_methods || 'Multiple'}\n\n📋 Next: Extract and run install_service_ENHANCED.bat as Administrator`);
|
||
}
|
||
}, 500);
|
||
|
||
// Reset button
|
||
setTimeout(() => {
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
}, 5000);
|
||
} else {
|
||
alert('Error creating service package: ' + data.error);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
}
|
||
})
|
||
.catch(error => {
|
||
alert('Error: ' + error.message);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
});
|
||
});
|
||
|
||
// Zero Dependencies Service Download Handler
|
||
document.getElementById('download-zero-deps-btn').addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
// Show loading state
|
||
const originalText = this.innerHTML;
|
||
this.innerHTML = '⏳ Creating Zero-Dependency Package (may take 1-2 minutes)...';
|
||
this.disabled = true;
|
||
|
||
// Show progress info
|
||
const progressInfo = document.createElement('div');
|
||
progressInfo.className = 'alert alert-info mt-2';
|
||
progressInfo.innerHTML = '📥 Downloading Python embedded distribution and creating complete package...';
|
||
this.parentElement.appendChild(progressInfo);
|
||
|
||
// Create the zero-dependency service package
|
||
fetch('/create_zero_dependency_service_package', {method: 'POST'})
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
if (data.success) {
|
||
// Start download
|
||
window.location.href = data.download_url;
|
||
|
||
// Show success message
|
||
setTimeout(() => {
|
||
this.innerHTML = `✅ Download Started! (${data.estimated_size_mb}MB)`;
|
||
progressInfo.innerHTML = `🎉 Complete package created with ${data.files_included} files including Python ${data.python_version}!`;
|
||
progressInfo.className = 'alert alert-success mt-2';
|
||
}, 500);
|
||
|
||
// Reset button
|
||
setTimeout(() => {
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
progressInfo.remove();
|
||
}, 5000);
|
||
} else {
|
||
alert('Error creating zero-dependency package: ' + data.error);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
progressInfo.remove();
|
||
}
|
||
})
|
||
.catch(error => {
|
||
alert('Error: ' + error.message);
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
progressInfo.remove();
|
||
});
|
||
});
|
||
|
||
// Extension Test Functionality
|
||
document.getElementById('test-extension-btn').addEventListener('click', function(e) {
|
||
e.preventDefault();
|
||
|
||
const testResults = document.getElementById('test-results');
|
||
const originalText = this.innerHTML;
|
||
|
||
this.innerHTML = '🔍 Testing...';
|
||
this.disabled = true;
|
||
testResults.style.display = 'block';
|
||
testResults.innerHTML = '<div class="spinner-border spinner-border-sm" role="status"></div> Checking Chrome extension...';
|
||
|
||
// Test extension detection (same logic as print module)
|
||
testExtensionConnection()
|
||
.then(result => {
|
||
if (result.success) {
|
||
testResults.innerHTML = `
|
||
<div class="alert alert-success">
|
||
<strong>✅ Extension Test Successful!</strong><br>
|
||
Extension ID: ${result.extensionId || 'Detected'}<br>
|
||
Version: ${result.version || 'Unknown'}<br>
|
||
Status: Ready for printing<br>
|
||
<small class="text-muted">The print module will show the green "Print Labels (Extension)" button</small>
|
||
</div>
|
||
`;
|
||
} else {
|
||
testResults.innerHTML = `
|
||
<div class="alert alert-warning">
|
||
<strong>❌ Extension Not Detected</strong><br>
|
||
Reason: ${result.error}<br>
|
||
<small class="text-muted">
|
||
Make sure you've:<br>
|
||
1. Downloaded and extracted the extension<br>
|
||
2. Loaded it in Chrome at chrome://extensions/<br>
|
||
3. Enabled "Developer mode" first<br>
|
||
4. Refreshed this page after installation
|
||
</small>
|
||
</div>
|
||
`;
|
||
}
|
||
})
|
||
.catch(error => {
|
||
testResults.innerHTML = `
|
||
<div class="alert alert-danger">
|
||
<strong>❌ Test Failed</strong><br>
|
||
Error: ${error.message}<br>
|
||
<small class="text-muted">Chrome extension communication failed</small>
|
||
</div>
|
||
`;
|
||
})
|
||
.finally(() => {
|
||
this.innerHTML = originalText;
|
||
this.disabled = false;
|
||
});
|
||
});
|
||
|
||
// Test extension connection function
|
||
async function testExtensionConnection() {
|
||
return new Promise((resolve) => {
|
||
// Try to get extension ID from injected DOM element or use fallback
|
||
const extensionElement = document.getElementById('chrome-extension-id');
|
||
const extensionId = extensionElement ?
|
||
extensionElement.getAttribute('data-extension-id') :
|
||
'cifcoidplhgclhcnlcgdkjbaoempjmdl'; // Fallback
|
||
|
||
if (!window.chrome || !window.chrome.runtime) {
|
||
resolve({ success: false, error: 'Chrome runtime not available' });
|
||
return;
|
||
}
|
||
|
||
try {
|
||
chrome.runtime.sendMessage(extensionId, { action: 'ping' }, function(response) {
|
||
if (chrome.runtime.lastError) {
|
||
resolve({
|
||
success: false,
|
||
error: chrome.runtime.lastError.message,
|
||
extensionId: extensionId
|
||
});
|
||
} else if (response && response.success) {
|
||
resolve({
|
||
success: true,
|
||
extensionId: extensionId,
|
||
version: response.extension_version,
|
||
message: response.message
|
||
});
|
||
} else {
|
||
resolve({
|
||
success: false,
|
||
error: 'Extension ping failed - no response',
|
||
extensionId: extensionId
|
||
});
|
||
}
|
||
});
|
||
} catch (error) {
|
||
resolve({
|
||
success: false,
|
||
error: 'Exception: ' + error.message,
|
||
extensionId: extensionId
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
// Show installation tips
|
||
function showInstallationTips() {
|
||
const tips = [
|
||
'💡 Tip: Chrome Extension is recommended for most users - cross-platform and easy!',
|
||
'💡 Tip: Windows Service is perfect for enterprise environments requiring silent printing',
|
||
'💡 Tip: Both solutions work with the same web interface and automatically detected',
|
||
'💡 Tip: The system gracefully falls back to PDF downloads if neither is available'
|
||
];
|
||
|
||
let tipIndex = 0;
|
||
const tipContainer = document.createElement('div');
|
||
tipContainer.className = 'alert alert-info position-fixed';
|
||
tipContainer.style.cssText = 'bottom: 20px; right: 20px; max-width: 300px; z-index: 1000;';
|
||
|
||
function showNextTip() {
|
||
if (tipIndex < tips.length) {
|
||
tipContainer.innerHTML = `
|
||
<button type="button" class="btn-close float-end" onclick="this.parentElement.remove()"></button>
|
||
${tips[tipIndex]}
|
||
`;
|
||
|
||
if (!document.body.contains(tipContainer)) {
|
||
document.body.appendChild(tipContainer);
|
||
}
|
||
|
||
tipIndex++;
|
||
setTimeout(showNextTip, 8000); // Show next tip after 8 seconds
|
||
} else {
|
||
setTimeout(() => {
|
||
if (document.body.contains(tipContainer)) {
|
||
tipContainer.remove();
|
||
}
|
||
}, 5000);
|
||
}
|
||
}
|
||
|
||
// Start showing tips after 3 seconds
|
||
setTimeout(showNextTip, 3000);
|
||
}
|
||
|
||
// Initialize tips when page loads
|
||
document.addEventListener('DOMContentLoaded', showInstallationTips);
|
||
</script>
|
||
{% endblock %} |