feat: 人员识别与管理模块 - MediaPipe人脸检测、人脸识别、人员库管理
This commit is contained in:
@@ -405,6 +405,96 @@ function closeSettingsModal() {
|
||||
document.getElementById('settings-modal').classList.remove('active');
|
||||
}
|
||||
|
||||
// Persons Management
|
||||
function openPersonsModal() {
|
||||
loadPersonsList();
|
||||
document.getElementById('persons-modal').classList.add('active');
|
||||
}
|
||||
|
||||
function closePersonsModal() {
|
||||
document.getElementById('persons-modal').classList.remove('active');
|
||||
}
|
||||
|
||||
function loadPersonsList() {
|
||||
fetch(API_BASE + '/api/persons')
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(data) {
|
||||
var statsDiv = document.getElementById('persons-stats');
|
||||
var listDiv = document.getElementById('persons-list');
|
||||
|
||||
// 统计信息
|
||||
statsDiv.innerHTML = '<div class="stats-summary">' +
|
||||
'<span>Total: ' + data.stats.total_persons + '</span>' +
|
||||
'<span>Detected: ' + data.stats.total_detections + '</span>' +
|
||||
'<span>Known: ' + data.stats.known_persons_detected + '</span>' +
|
||||
'<span>New: ' + data.stats.new_persons_added + '</span>' +
|
||||
'</div>';
|
||||
|
||||
// 人员列表
|
||||
if (data.persons.length === 0) {
|
||||
listDiv.innerHTML = '<p style="color:#888;text-align:center;">No persons recorded yet</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
listDiv.innerHTML = '';
|
||||
data.persons.forEach(function(person) {
|
||||
var item = document.createElement('div');
|
||||
item.className = 'person-item';
|
||||
|
||||
var firstSeen = new Date(person.first_seen).toLocaleDateString();
|
||||
var lastSeen = new Date(person.last_seen).toLocaleDateString();
|
||||
|
||||
item.innerHTML = '<div class="person-info">' +
|
||||
'<span class="person-name">' + person.name + '</span>' +
|
||||
'<span class="person-id">' + person.person_id + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="person-stats">' +
|
||||
'<span>Visits: ' + person.visit_count + '</span>' +
|
||||
'<span>First: ' + firstSeen + '</span>' +
|
||||
'<span>Last: ' + lastSeen + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="person-actions">' +
|
||||
'<button onclick="renamePerson(\'' + person.person_id + '\')" class="btn-small">Rename</button>' +
|
||||
'<button onclick="deletePerson(\'' + person.person_id + '\')" class="btn-small btn-danger">Delete</button>' +
|
||||
'</div>';
|
||||
|
||||
listDiv.appendChild(item);
|
||||
});
|
||||
})
|
||||
.catch(function(e) { console.error('Load persons failed:', e); });
|
||||
}
|
||||
|
||||
function renamePerson(personId) {
|
||||
var newName = prompt('Enter new name:');
|
||||
if (!newName) return;
|
||||
|
||||
fetch(API_BASE + '/api/persons/' + personId + '/rename?name=' + encodeURIComponent(newName), {
|
||||
method: 'POST'
|
||||
})
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(data) {
|
||||
if (data.success) {
|
||||
showToast('Renamed to ' + newName, 1500);
|
||||
loadPersonsList();
|
||||
}
|
||||
})
|
||||
.catch(function(e) { showToast('Error: ' + e.message, 3000); });
|
||||
}
|
||||
|
||||
function deletePerson(personId) {
|
||||
if (!confirm('Delete this person?')) return;
|
||||
|
||||
fetch(API_BASE + '/api/persons/' + personId, {method: 'DELETE'})
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(data) {
|
||||
if (data.success) {
|
||||
showToast('Person deleted', 1500);
|
||||
loadPersonsList();
|
||||
}
|
||||
})
|
||||
.catch(function(e) { showToast('Error: ' + e.message, 3000); });
|
||||
}
|
||||
|
||||
function loadSettingsForm() {
|
||||
fetch(API_BASE + '/api/config')
|
||||
.then(function(res) { return res.json(); })
|
||||
|
||||
@@ -29,6 +29,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel-section">
|
||||
<h3>👥 人员库</h3>
|
||||
<button onclick="openPersonsModal()" class="btn-settings">查看人员库</button>
|
||||
</div>
|
||||
|
||||
<div class="panel-section">
|
||||
<h3>⚙️ 系统设置</h3>
|
||||
<button onclick="openSettingsModal()" class="btn-settings">🔧 设置参数</button>
|
||||
@@ -155,6 +160,22 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 人员库模态框 -->
|
||||
<div class="modal" id="persons-modal" onclick="closeModalOnBackground(event, 'persons-modal')">
|
||||
<div class="modal-content settings-modal-content" onclick="event.stopPropagation()">
|
||||
<span class="modal-close" onclick="closePersonsModal()">×</span>
|
||||
<h2>👥 人员库管理</h2>
|
||||
|
||||
<div class="persons-stats" id="persons-stats">
|
||||
<!-- 统计信息 -->
|
||||
</div>
|
||||
|
||||
<div class="persons-list" id="persons-list">
|
||||
<!-- 人员列表 -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 图片详情模态框 -->
|
||||
<div class="modal" id="image-modal" onclick="closeModalOnBackground(event, 'image-modal')">
|
||||
<div class="modal-content" onclick="event.stopPropagation()">
|
||||
|
||||
@@ -582,6 +582,73 @@ button {
|
||||
}
|
||||
|
||||
/* 响应式 */
|
||||
.settings-actions {
|
||||
margin-top: 20px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 人员库样式 */
|
||||
.persons-stats {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-summary {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
justify-content: center;
|
||||
padding: 15px;
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.stats-summary span {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
.persons-list {
|
||||
max-height: 400px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.person-item {
|
||||
background: #f9f9f9;
|
||||
padding: 15px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #2196F3;
|
||||
}
|
||||
|
||||
.person-info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.person-name {
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.person-id {
|
||||
color: #888;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.person-stats {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
color: #555;
|
||||
font-size: 13px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.person-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.control-panel {
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user