第一次提交
This commit is contained in:
167
static/css/custom.css
Normal file
167
static/css/custom.css
Normal file
@@ -0,0 +1,167 @@
|
||||
/* 自定义样式 */
|
||||
.main-content {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.card-stats {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 仪表盘卡片标题字体颜色改为黑色 */
|
||||
.card-stats .card-title {
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
background-color: #495057;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* 删除确认弹窗样式优化 - 增强特异性 */
|
||||
.modal-content.custom-modal-content,
|
||||
div.modal-content.custom-modal-content {
|
||||
border: none !important;
|
||||
border-radius: 0.5rem !important;
|
||||
box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important;
|
||||
}
|
||||
|
||||
.modal-header.custom-modal-header,
|
||||
div.modal-header.custom-modal-header {
|
||||
background-color: #f8f9fa !important;
|
||||
border-bottom: 1px solid #e9ecef !important;
|
||||
border-radius: 0.5rem 0.5rem 0 0 !important;
|
||||
padding: 1rem 1.5rem !important;
|
||||
}
|
||||
|
||||
.modal-title.custom-modal-title,
|
||||
div.modal-title.custom-modal-title {
|
||||
font-weight: 600 !important;
|
||||
color: #495057 !important;
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
|
||||
.modal-body.custom-modal-body,
|
||||
div.modal-body.custom-modal-body {
|
||||
padding: 1.5rem !important;
|
||||
font-size: 1rem !important;
|
||||
line-height: 1.5 !important;
|
||||
}
|
||||
|
||||
.modal-footer.custom-modal-footer,
|
||||
div.modal-footer.custom-modal-footer {
|
||||
background-color: #f8f9fa !important;
|
||||
border-top: 1px solid #e9ecef !important;
|
||||
border-radius: 0 0 0.5rem 0.5rem !important;
|
||||
padding: 1rem 1.5rem !important;
|
||||
}
|
||||
|
||||
.btn-close.custom-btn-close,
|
||||
button.btn-close.custom-btn-close {
|
||||
box-sizing: content-box !important;
|
||||
width: 1em !important;
|
||||
height: 1em !important;
|
||||
padding: 0.25em 0.25em !important;
|
||||
color: #000 !important;
|
||||
background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat !important;
|
||||
border: 0 !important;
|
||||
border-radius: 0.375rem !important;
|
||||
opacity: 0.5 !important;
|
||||
}
|
||||
|
||||
.btn-close.custom-btn-close:hover,
|
||||
button.btn-close.custom-btn-close:hover {
|
||||
opacity: 0.75 !important;
|
||||
}
|
||||
|
||||
/* 按钮样式 */
|
||||
.btn-secondary.custom-btn-secondary,
|
||||
button.btn-secondary.custom-btn-secondary {
|
||||
background-color: #6c757d !important;
|
||||
border-color: #6c757d !important;
|
||||
color: #fff !important;
|
||||
padding: 0.375rem 0.75rem !important;
|
||||
font-size: 0.875rem !important;
|
||||
border-radius: 0.25rem !important;
|
||||
border: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
.btn-secondary.custom-btn-secondary:hover,
|
||||
button.btn-secondary.custom-btn-secondary:hover {
|
||||
background-color: #5a6268 !important;
|
||||
border-color: #545b62 !important;
|
||||
}
|
||||
|
||||
.btn-danger.custom-btn-danger,
|
||||
button.btn-danger.custom-btn-danger {
|
||||
background-color: #dc3545 !important;
|
||||
border-color: #dc3545 !important;
|
||||
color: #fff !important;
|
||||
padding: 0.375rem 0.75rem !important;
|
||||
font-size: 0.875rem !important;
|
||||
border-radius: 0.25rem !important;
|
||||
border: 1px solid transparent !important;
|
||||
}
|
||||
|
||||
.btn-danger.custom-btn-danger:hover,
|
||||
button.btn-danger.custom-btn-danger:hover {
|
||||
background-color: #c82333 !important;
|
||||
border-color: #bd2130 !important;
|
||||
}
|
||||
|
||||
/* 警告消息样式 */
|
||||
.alert-warning.custom-alert-warning,
|
||||
div.alert-warning.custom-alert-warning {
|
||||
background-color: #fff3cd !important;
|
||||
border-color: #ffeaa7 !important;
|
||||
color: #856404 !important;
|
||||
border-radius: 0.375rem !important;
|
||||
padding: 0.75rem 1.25rem !important;
|
||||
margin-top: 1rem !important;
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.alert-warning.custom-alert-warning:hover,
|
||||
div.alert-warning.custom-alert-warning:hover {
|
||||
background-color: #ffefba !important;
|
||||
}
|
||||
|
||||
.alert-warning.custom-alert-warning::before,
|
||||
div.alert-warning.custom-alert-warning::before {
|
||||
content: "ℹ️ " !important;
|
||||
margin-right: 0.5rem !important;
|
||||
}
|
||||
|
||||
/* 强制删除按钮样式 */
|
||||
.btn-warning {
|
||||
background-color: #ffc107 !important;
|
||||
border-color: #ffc107 !important;
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.btn-warning:hover {
|
||||
background-color: #ffb300 !important;
|
||||
border-color: #ffb300 !important;
|
||||
}
|
||||
|
||||
.icon icon-shape bg-white text-info rounded-circle shadow{
|
||||
width: 1050px;
|
||||
}
|
||||
1
static/images/product-default.png
Normal file
1
static/images/product-default.png
Normal file
@@ -0,0 +1 @@
|
||||
This is a placeholder for the default product image file. Please replace this with an actual image file.
|
||||
BIN
static/images/taiyiagi.png
Normal file
BIN
static/images/taiyiagi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
1
static/images/wechat-qrcode.jpg
Normal file
1
static/images/wechat-qrcode.jpg
Normal file
@@ -0,0 +1 @@
|
||||
This is a placeholder for the WeChat QR code image.
|
||||
70
static/js/custom.js
Normal file
70
static/js/custom.js
Normal file
@@ -0,0 +1,70 @@
|
||||
// 自定义JavaScript函数
|
||||
|
||||
// 设置前端域名全局变量
|
||||
if (typeof FRONTEND_DOMAIN !== 'undefined') {
|
||||
window.FRONTEND_DOMAIN = FRONTEND_DOMAIN;
|
||||
}
|
||||
|
||||
// 显示加载动画
|
||||
function showLoading() {
|
||||
const loadingElement = document.getElementById('loading');
|
||||
if (loadingElement) {
|
||||
loadingElement.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏加载动画
|
||||
function hideLoading() {
|
||||
const loadingElement = document.getElementById('loading');
|
||||
if (loadingElement) {
|
||||
loadingElement.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
// 格式化日期
|
||||
function formatDate(dateString) {
|
||||
if (!dateString) return '-';
|
||||
const date = new Date(dateString);
|
||||
return date.toLocaleDateString('zh-CN') + ' ' + date.toLocaleTimeString('zh-CN');
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
function formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
const k = 1024;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 显示通知 - 统一的消息弹窗函数
|
||||
function showNotification(message, type = 'info') {
|
||||
// 创建通知元素
|
||||
const alertDiv = document.createElement('div');
|
||||
const alertType = type === 'error' ? 'danger' : type;
|
||||
alertDiv.className = `alert alert-${alertType} alert-dismissible fade show`;
|
||||
alertDiv.innerHTML = `
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
`;
|
||||
alertDiv.style.marginBottom = '10px';
|
||||
|
||||
// 插入到通知容器中
|
||||
const container = document.getElementById('notification-container') || document.querySelector('main');
|
||||
if (container) {
|
||||
container.insertBefore(alertDiv, container.firstChild);
|
||||
|
||||
// 自动隐藏
|
||||
setTimeout(() => {
|
||||
if (alertDiv.parentNode) {
|
||||
alertDiv.remove();
|
||||
}
|
||||
}, 5000);
|
||||
} else {
|
||||
// 如果找不到容器,使用console输出作为备选方案
|
||||
console.log(`[${type.toUpperCase()}] ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
// API请求函数 - 添加认证支持 - REMOVED DUPLICATE
|
||||
// This function is now defined in base.html to avoid duplication
|
||||
134
static/js/pagination.js
Normal file
134
static/js/pagination.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* 公共分页工具函数
|
||||
*/
|
||||
|
||||
// 渲染分页导航
|
||||
function renderPagination(pagination, pageChangeCallback) {
|
||||
const paginationEl = document.getElementById('pagination');
|
||||
if (!paginationEl) return;
|
||||
|
||||
// 验证分页数据
|
||||
if (!pagination || typeof pagination !== 'object' ||
|
||||
!Number.isFinite(pagination.total_pages) || pagination.total_pages <= 1) {
|
||||
paginationEl.innerHTML = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let html = '';
|
||||
|
||||
// 上一页
|
||||
if (pagination.has_prev) {
|
||||
html += `<li class="page-item">
|
||||
<a class="page-link" href="#" data-page="${pagination.current_page - 1}">上一页</a>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
// 页码
|
||||
const startPage = Math.max(1, pagination.current_page - 2);
|
||||
const endPage = Math.min(pagination.total_pages, pagination.current_page + 2);
|
||||
|
||||
if (startPage > 1) {
|
||||
html += `<li class="page-item"><a class="page-link" href="#" data-page="1">1</a></li>`;
|
||||
if (startPage > 2) {
|
||||
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = startPage; i <= endPage; i++) {
|
||||
html += `<li class="page-item ${i === pagination.current_page ? 'active' : ''}">
|
||||
<a class="page-link" href="#" data-page="${i}">${i}</a>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
if (endPage < pagination.total_pages) {
|
||||
if (endPage < pagination.total_pages - 1) {
|
||||
html += `<li class="page-item disabled"><span class="page-link">...</span></li>`;
|
||||
}
|
||||
html += `<li class="page-item"><a class="page-link" href="#" data-page="${pagination.total_pages}">${pagination.total_pages}</a></li>`;
|
||||
}
|
||||
|
||||
// 下一页
|
||||
if (pagination.has_next) {
|
||||
html += `<li class="page-item">
|
||||
<a class="page-link" href="#" data-page="${pagination.current_page + 1}">下一页</a>
|
||||
</li>`;
|
||||
}
|
||||
|
||||
paginationEl.innerHTML = html;
|
||||
|
||||
// 绑定分页点击事件
|
||||
paginationEl.querySelectorAll('.page-link').forEach(link => {
|
||||
link.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
const page = parseInt(this.dataset.page);
|
||||
if (page && page !== pagination.current_page) {
|
||||
if (typeof pageChangeCallback === 'function') {
|
||||
pageChangeCallback(page);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 获取URL参数
|
||||
function getUrlParameter(name) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get(name);
|
||||
}
|
||||
|
||||
// 设置URL参数
|
||||
function setUrlParameter(param, value) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
if (value === null || value === '') {
|
||||
urlParams.delete(param);
|
||||
} else {
|
||||
urlParams.set(param, value);
|
||||
}
|
||||
window.history.replaceState({}, '', `${window.location.pathname}?${urlParams.toString()}`);
|
||||
}
|
||||
|
||||
// 批量更新复选框状态
|
||||
function setupBatchSelection(selectAllId, itemCheckboxClass, selectedCountId, batchButtons) {
|
||||
const selectAll = document.getElementById(selectAllId);
|
||||
if (!selectAll) return;
|
||||
|
||||
// 全选/取消全选
|
||||
selectAll.addEventListener('change', function() {
|
||||
const checkboxes = document.querySelectorAll(itemCheckboxClass);
|
||||
checkboxes.forEach(checkbox => {
|
||||
checkbox.checked = this.checked;
|
||||
});
|
||||
updateBatchButtons(selectedCountId, batchButtons);
|
||||
});
|
||||
|
||||
// 单个复选框事件
|
||||
document.querySelectorAll(itemCheckboxClass).forEach(checkbox => {
|
||||
checkbox.addEventListener('change', () => {
|
||||
updateBatchButtons(selectedCountId, batchButtons);
|
||||
});
|
||||
});
|
||||
|
||||
// 初始状态
|
||||
updateBatchButtons(selectedCountId, batchButtons);
|
||||
}
|
||||
|
||||
// 更新批量操作按钮状态
|
||||
function updateBatchButtons(selectedCountId, batchButtons) {
|
||||
const selectedCount = document.querySelectorAll('.license-checkbox:checked, .product-checkbox:checked, .device-checkbox:checked').length;
|
||||
|
||||
if (selectedCountId) {
|
||||
const countElement = document.getElementById(selectedCountId);
|
||||
if (countElement) {
|
||||
countElement.textContent = `已选择 ${selectedCount} 项`;
|
||||
}
|
||||
}
|
||||
|
||||
if (batchButtons) {
|
||||
batchButtons.forEach(buttonId => {
|
||||
const button = document.getElementById(buttonId);
|
||||
if (button) {
|
||||
button.style.display = selectedCount > 0 ? 'inline-block' : 'none';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
static/producepic/4529023624ad43b28b248c746ee28206.jpg
Normal file
BIN
static/producepic/4529023624ad43b28b248c746ee28206.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 148 KiB |
BIN
static/producepic/5cd2f3c2b40a41119705654146a15a38.png
Normal file
BIN
static/producepic/5cd2f3c2b40a41119705654146a15a38.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
static/producepic/bd79df36a0114b96babd382bfc87ec6d.jpg
Normal file
BIN
static/producepic/bd79df36a0114b96babd382bfc87ec6d.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
Reference in New Issue
Block a user