整理文件夹及架构,加入打印机页面,octo反代有问题

This commit is contained in:
2026-04-14 00:11:00 +08:00
parent 1de35f21d7
commit 570af7c225
54 changed files with 939 additions and 292 deletions

View File

@@ -21,8 +21,18 @@
.card { border: none; border-radius: 0.75rem; overflow: hidden; }
.card-header { border-bottom: 1px solid rgba(0,0,0,.05); background-color: transparent; }
.toast-container { margin-bottom: 20px; margin-right: 20px; }
.toast { border-radius: 0.5rem; box-shadow: 0 0.5rem 1rem rgba(0,0,0,.15); opacity: 0.95; }
.toast-container { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); z-index: 1055; width: auto; max-width: 90%; pointer-events: none; }
.toast { border-radius: 0.5rem; box-shadow: 0 0.5rem 1rem rgba(0,0,0,.25); opacity: 1 !important; pointer-events: auto; }
/* 页面切换动画 Page Transition */
@keyframes pageFadeInSlide {
0% { opacity: 0; transform: translateY(10px); }
100% { opacity: 1; transform: translateY(0); }
}
main { animation: pageFadeInSlide 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; }
/* 提升 Accordion 折叠栏动画更平滑 */
.collapsing { transition: height 0.35s cubic-bezier(0.25, 0.8, 0.25, 1) !important; }
</style>
</head>
<body>
@@ -150,12 +160,12 @@
<main class="col-md-9 ms-sm-auto col-lg-10 px-md-4 mt-4 bg-light min-vh-100 pb-5">
<!-- Toast Notification Container -->
<div class="toast-container position-fixed bottom-0 end-0 p-3" style="z-index: 1055;">
<div class="toast-container" id="global-toast-container">
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
{% for category, message in messages %}
{% set toast_class = 'bg-success text-white' if category == 'success' else 'bg-danger text-white' if category == 'danger' else 'bg-warning text-dark' if category == 'warning' else 'bg-primary text-white' %}
<div class="toast align-items-center border-0 {{ toast_class }}" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast align-items-center border-0 {{ toast_class }} mb-2" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body fw-medium">
{{ message }}
@@ -173,6 +183,41 @@
</div>
</div>
<!-- Global Custom Alert Modal -->
<div class="modal fade" id="globalAlertModal" tabindex="-1" aria-hidden="true" style="z-index: 1060;">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-warning text-dark py-2">
<h6 class="modal-title fw-bold" id="globalAlertTitle"><i class="bi bi-exclamation-triangle-fill me-2"></i>{{ _('Notice') }}</h6>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 text-center py-4 text-break" id="globalAlertMessage">
</div>
<div class="modal-footer border-0 p-2 justify-content-center bg-light">
<button type="button" class="btn btn-warning px-4 rounded-pill fw-bold" data-bs-dismiss="modal">{{ _('OK') }}</button>
</div>
</div>
</div>
</div>
<!-- Global Custom Confirm Modal -->
<div class="modal fade" id="globalConfirmModal" tabindex="-1" aria-hidden="true" style="z-index: 1060;">
<div class="modal-dialog modal-dialog-centered modal-sm">
<div class="modal-content border-0 shadow">
<div class="modal-header bg-primary text-white py-2">
<h6 class="modal-title fw-bold"><i class="bi bi-question-circle-fill me-2"></i>{{ _('Confirm') }}</h6>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body fs-6 text-center py-4 text-break" id="globalConfirmMessage">
</div>
<div class="modal-footer border-0 p-2 justify-content-center bg-light">
<button type="button" class="btn btn-outline-secondary px-4 rounded-pill" data-bs-dismiss="modal">{{ _('Cancel') }}</button>
<button type="button" class="btn btn-primary px-4 rounded-pill fw-bold" id="globalConfirmBtn">{{ _('Yes') }}</button>
</div>
</div>
</div>
</div>
<script src="{{ url_for('static', filename='js/bootstrap.bundle.min.js') }}"></script>
<script>
// Initialize Toasts automatically
@@ -182,6 +227,53 @@
return new bootstrap.Toast(toastEl, { delay: 3000 }).show()
});
});
// Global Utility: Show Toast dynamically
window.showToast = function(msg, type='success', duration=3000) {
const container = document.getElementById('global-toast-container');
const toastClass = type === 'success' ? 'bg-success text-white' :
type === 'danger' ? 'bg-danger text-white' :
type === 'warning' ? 'bg-warning text-dark' : 'bg-primary text-white';
const html = `
<div class="toast align-items-center border-0 ${toastClass} mb-2" role="alert" aria-live="assertive" aria-atomic="true">
<div class="d-flex">
<div class="toast-body fw-medium">${msg}</div>
<button type="button" class="btn-close ${type==='warning'?'':'btn-close-white'} me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
</div>
`;
container.insertAdjacentHTML('beforeend', html);
const ts = container.lastElementChild;
new bootstrap.Toast(ts, { autohide: true, delay: duration }).show();
ts.addEventListener('hidden.bs.toast', () => { ts.remove(); });
};
// Override default alert
window.customAlert = function(msg, title) {
document.getElementById('globalAlertMessage').innerHTML = String(msg).replace(/\n/g, '<br>');
if(title) document.getElementById('globalAlertTitle').innerHTML = '<i class="bi bi-info-circle-fill me-2"></i>' + title;
else document.getElementById('globalAlertTitle').innerHTML = '<i class="bi bi-exclamation-triangle-fill me-2"></i>Notice';
new bootstrap.Modal(document.getElementById('globalAlertModal')).show();
};
// Override default confirm
window.customConfirm = function(msg, onConfirm) {
document.getElementById('globalConfirmMessage').innerHTML = String(msg).replace(/\n/g, '<br>');
const modalEl = document.getElementById('globalConfirmModal');
const modal = new bootstrap.Modal(modalEl);
// Clear previous event listener bindings
const elClone = document.getElementById('globalConfirmBtn').cloneNode(true);
document.getElementById('globalConfirmBtn').parentNode.replaceChild(elClone, document.getElementById('globalConfirmBtn'));
document.getElementById('globalConfirmBtn').addEventListener('click', function() {
modal.hide();
if(onConfirm) onConfirm();
});
modal.show();
};
</script>
</body>
</html>