Files
SignatureSystem/templates/db_manager.html
2026-07-20 13:16:17 +08:00

276 lines
13 KiB
HTML

{% extends "base.html" %}
{% block title %}自动签名系统 - 数据库管理{% endblock %}
{% block content %}
<div class="main-content">
<div class="two-col">
<div class="col-left" style="max-width:360px;flex-shrink:0;">
<div class="card-section">
<h6><i class="bi bi-search"></i> 搜索</h6>
<div class="input-group input-group-sm">
<input class="form-control" type="text" id="searchKeyword" placeholder="人员ID或姓名">
<button class="btn btn-primary" id="btnSearch"><i class="bi bi-search"></i></button>
</div>
</div>
<div class="card-section">
<h6><i class="bi bi-plus-circle"></i> 新增记录</h6>
<div class="mb-2">
<label class="form-label">人员ID</label>
<input class="form-control form-control-sm" type="text" id="addUserId" placeholder="仅字母和数字">
</div>
<div class="mb-2">
<label class="form-label">人员姓名</label>
<input class="form-control form-control-sm" type="text" id="addUserName" placeholder="中文或英文">
</div>
<div class="mb-2">
<label class="form-label">签章图片</label>
<input class="form-control form-control-sm" type="file" id="addSignImage" accept="image/png,image/jpeg">
</div>
<div class="mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="addIsSignature">
<label class="form-check-label" for="addIsSignature" style="font-size:12px;">手写签字(预览时执行黑白二值化)</label>
</div>
</div>
<button class="btn btn-primary btn-sm w-100" id="btnAddRecord"><i class="bi bi-plus"></i> 新增</button>
</div>
<div class="card-section">
<h6><i class="bi bi-upload"></i> 批量导入</h6>
<div class="mb-2">
<input class="form-control form-control-sm" type="file" id="batchFiles" multiple accept="image/png,image/jpeg">
<small class="text-muted">文件名自动作为人员姓名</small>
</div>
<div class="mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="batchAutoId">
<label class="form-check-label" for="batchAutoId" style="font-size:12px;">自动生成ID</label>
</div>
</div>
<div class="mb-2">
<input class="form-control form-control-sm" type="text" id="batchIdPrefix" placeholder="ID前缀(默认USER)" value="USER">
</div>
<div class="mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="batchIsSignature">
<label class="form-check-label" for="batchIsSignature" style="font-size:12px;">手写签字</label>
</div>
</div>
<button class="btn btn-success btn-sm w-100" id="btnBatchImport"><i class="bi bi-upload"></i> 批量导入</button>
</div>
<div class="card-section" id="editSection" style="display:none;">
<h6><i class="bi bi-pencil"></i> 编辑记录</h6>
<div class="mb-2">
<label class="form-label">人员ID</label>
<input class="form-control form-control-sm" type="text" id="editUserId" readonly>
</div>
<div class="mb-2">
<label class="form-label">人员姓名</label>
<input class="form-control form-control-sm" type="text" id="editUserName">
</div>
<div class="mb-2">
<label class="form-label">签章图片(留空不修改)</label>
<input class="form-control form-control-sm" type="file" id="editSignImage" accept="image/png,image/jpeg">
</div>
<div class="mb-2">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="editIsSignature">
<label class="form-check-label" for="editIsSignature" style="font-size:12px;">手写签字</label>
</div>
</div>
<div class="d-grid gap-2">
<button class="btn btn-primary btn-sm" id="btnUpdateRecord"><i class="bi bi-check"></i> 保存</button>
<button class="btn btn-outline-secondary btn-sm" id="btnCancelEdit"><i class="bi bi-x"></i> 取消</button>
</div>
</div>
<div class="card-section" id="previewSection" style="display:none;">
<h6><i class="bi bi-eye"></i> 图片预览</h6>
<div class="preview-container">
<div>
<div class="preview-box"><img id="previewOriginal" src="" alt="原图"></div>
<div class="label">原图</div>
</div>
<div>
<div class="preview-box"><img id="previewProcessed" src="" alt="效果图"></div>
<div class="label" id="previewLabel">抠图效果</div>
</div>
</div>
</div>
</div>
<div class="col-right">
<div class="card-section">
<h6><i class="bi bi-table"></i> 签章数据</h6>
<div id="dataTableArea"></div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
let currentPage = 1;
const pageSize = 20;
function loadRecords(page) {
currentPage = page || 1;
const keyword = document.getElementById('searchKeyword').value;
fetch(`/api/db/list?page=${currentPage}&page_size=${pageSize}&keyword=${encodeURIComponent(keyword)}`)
.then(r => r.json())
.then(data => {
if (data.success) {
renderTable(data.data);
} else {
alert('加载列表失败: ' + data.message);
}
})
.catch(err => alert('请求失败: ' + err.message));
}
function renderTable(pageData) {
const area = document.getElementById('dataTableArea');
const totalPages = Math.ceil(pageData.total / pageData.page_size);
let html = `
<table class="table table-hover table-sm">
<thead>
<tr><th>人员ID</th><th>人员姓名</th><th>图片属性</th><th>创建时间</th><th>操作</th></tr>
</thead>
<tbody>
`;
pageData.data.forEach(row => {
const sigLabel = row.is_signature ? '<span class="badge bg-info">手写签字</span>' : '<span class="badge bg-secondary">普通签章</span>';
html += `
<tr>
<td>${escapeHtml(row.user_id)}</td>
<td>${escapeHtml(row.user_name)}</td>
<td>${sigLabel}</td>
<td>${row.create_time || '-'}</td>
<td>
<button class="btn btn-outline-primary btn-sm" onclick="previewRecord('${escapeHtml(row.user_id)}')"><i class="bi bi-eye"></i></button>
<button class="btn btn-outline-warning btn-sm" onclick="editRecord('${escapeHtml(row.user_id)}')"><i class="bi bi-pencil"></i></button>
<button class="btn btn-outline-danger btn-sm" onclick="deleteRecord('${escapeHtml(row.user_id)}')"><i class="bi bi-trash"></i></button>
</td>
</tr>
`;
});
html += '</tbody></table>';
html += `<div class="pagination-area">`;
if (currentPage > 1) html += `<button class="btn btn-sm btn-outline-primary" onclick="loadRecords(${currentPage - 1})">上一页</button>`;
html += `<span style="padding:4px 12px;font-size:13px;">第 ${currentPage}/${totalPages} 页 (共${pageData.total}条)</span>`;
if (currentPage < totalPages) html += `<button class="btn btn-sm btn-outline-primary" onclick="loadRecords(${currentPage + 1})">下一页</button>`;
html += `</div>`;
area.innerHTML = html;
}
function previewRecord(userId) {
document.getElementById('previewSection').style.display = '';
document.getElementById('previewOriginal').src = `/api/db/image/${encodeURIComponent(userId)}?t=${Date.now()}`;
document.getElementById('previewProcessed').src = `/api/db/preview/${encodeURIComponent(userId)}?t=${Date.now()}`;
}
function editRecord(userId) {
fetch(`/api/db/get/${encodeURIComponent(userId)}`)
.then(r => r.json())
.then(data => {
if (data.success) {
const row = data.data;
document.getElementById('editUserId').value = row.user_id;
document.getElementById('editUserName').value = row.user_name;
document.getElementById('editIsSignature').checked = row.is_signature;
document.getElementById('editSection').style.display = '';
}
});
}
function deleteRecord(userId) {
if (!confirm(`确定删除人员 ${userId} 的记录?`)) return;
fetch(`/api/db/delete/${encodeURIComponent(userId)}`, { method: 'DELETE' })
.then(r => r.json())
.then(data => {
if (data.success) {
loadRecords(currentPage);
} else {
alert('删除失败: ' + data.message);
}
});
}
document.getElementById('btnSearch').addEventListener('click', () => loadRecords(1));
document.getElementById('searchKeyword').addEventListener('keypress', e => { if (e.key === 'Enter') loadRecords(1); });
document.getElementById('btnAddRecord').addEventListener('click', function() {
const formData = new FormData();
formData.append('user_id', document.getElementById('addUserId').value);
formData.append('user_name', document.getElementById('addUserName').value);
formData.append('sign_image', document.getElementById('addSignImage').files[0]);
formData.append('is_signature', document.getElementById('addIsSignature').checked ? '1' : '0');
fetch('/api/db/add', { method: 'POST', body: formData })
.then(r => r.json())
.then(data => {
if (data.success) {
document.getElementById('addUserId').value = '';
document.getElementById('addUserName').value = '';
document.getElementById('addSignImage').value = '';
document.getElementById('addIsSignature').checked = false;
loadRecords(1);
} else {
alert('新增失败: ' + data.message);
}
})
.catch(err => alert('请求失败: ' + err.message));
});
document.getElementById('btnUpdateRecord').addEventListener('click', function() {
const userId = document.getElementById('editUserId').value;
const formData = new FormData();
formData.append('user_name', document.getElementById('editUserName').value);
formData.append('is_signature', document.getElementById('editIsSignature').checked ? '1' : '0');
const imgFile = document.getElementById('editSignImage').files[0];
if (imgFile) formData.append('sign_image', imgFile);
fetch(`/api/db/update/${encodeURIComponent(userId)}`, { method: 'PUT', body: formData })
.then(r => r.json())
.then(data => {
if (data.success) {
document.getElementById('editSection').style.display = 'none';
loadRecords(currentPage);
} else {
alert('更新失败: ' + data.message);
}
});
});
document.getElementById('btnCancelEdit').addEventListener('click', function() {
document.getElementById('editSection').style.display = 'none';
});
document.getElementById('btnBatchImport').addEventListener('click', function() {
const formData = new FormData();
const files = document.getElementById('batchFiles').files;
for (let f of files) formData.append('files', f);
formData.append('auto_id', document.getElementById('batchAutoId').checked ? '1' : '0');
formData.append('id_prefix', document.getElementById('batchIdPrefix').value || 'USER');
formData.append('is_signature', document.getElementById('batchIsSignature').checked ? '1' : '0');
fetch('/api/db/batch_import', { method: 'POST', body: formData })
.then(r => r.json())
.then(data => {
if (data.success) {
const d = data.data;
alert(`批量导入完成: 成功${d.success}条, 失败${d.fail}`);
loadRecords(1);
} else {
alert('批量导入失败: ' + data.message);
}
});
});
loadRecords(1);
</script>
{% endblock %}