safesight-control/internal/web/ui/templates/face_gallery.html

112 lines
6.6 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{define "face_gallery"}}
<div class="detail-grid">
<div class="card">
<h3 class="title-with-icon">{{icon "overview"}}<span>批量导入</span></h3>
<form method="post" action="/ui/face-gallery/import" enctype="multipart/form-data">
<div class="field-grid">
<label class="full"><span>选择照片目录</span><input type="file" name="photos" webkitdirectory multiple required /></label>
</div>
<div class="actions" style="margin-top:12px">
<button class="btn" type="submit">批量导入</button>
</div>
</form>
</div>
<div class="card">
<h3 class="title-with-icon">{{icon "edit"}}<span>新增人员</span></h3>
<form method="post" action="/ui/face-gallery/add" enctype="multipart/form-data">
<div class="field-grid">
<label><span>姓名</span><input type="text" name="name" placeholder="例如:张三" required /></label>
<label><span>照片</span><input type="file" name="photo" accept="image/*" required /></label>
</div>
<div class="actions" style="margin-top:12px">
<button class="btn" type="submit">新增</button>
</div>
</form>
</div>
</div>
<div class="card">
<div class="section-title">
<div>
<h3 class="title-with-icon">{{icon "profile"}}<span>人员列表</span></h3>
<span class="muted small">{{len .FaceGalleryPersons}} 人</span>
</div>
</div>
{{if .FaceGalleryPersons}}
<div style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:16px;margin-top:12px">
{{range .FaceGalleryPersons}}
<div class="card" style="padding:8px">
<div class="photo-viewer" data-photos='[{{range $i,$p := .Photos}}{{if $i}},{{end}}"/ui/face-photo/{{$p}}"{{end}}]' style="width:100%;height:220px;background:var(--surface-soft);border-radius:var(--radius);overflow:hidden;position:relative">
{{if .Photos}}
<img src="/ui/face-photo/{{index .Photos 0}}" style="width:100%;height:100%;object-fit:cover" id="img-{{.ID}}" />
{{if gt .PhotoCount 1}}
<button class="btn ghost nav-btn" id="prev-{{.ID}}" style="position:absolute;left:2px;top:50%;transform:translateY(-50%);padding:2px 4px;font-size:10px;opacity:0.7;display:none" onclick="navPhoto({{.ID}},-1)"></button>
<button class="btn ghost nav-btn" id="next-{{.ID}}" style="position:absolute;right:2px;top:50%;transform:translateY(-50%);padding:2px 4px;font-size:10px;opacity:0.7" onclick="navPhoto({{.ID}},1)"></button>
{{end}}
{{else}}
<div class="muted" style="display:flex;align-items:center;justify-content:center;height:100%">无照片</div>
{{end}}
</div>
<div style="margin-top:6px">
<div style="font-weight:500;font-size:13px">{{.Name}} <span class="muted small">{{.PhotoCount}}张</span></div>
<div class="actions compact" style="margin-top:4px">
<button class="btn ghost" type="button" style="font-size:11px;padding:2px 6px" onclick="editPerson({{.ID}},'{{.Name}}',[{{range $i,$p := .Photos}}{{if $i}},{{end}}'/ui/face-photo/{{$p}}'{{end}}])">编辑</button>
<form method="post" action="/ui/face-gallery/delete" style="display:inline" onsubmit="return confirm('确定删除 {{.Name}}')">
<input type="hidden" name="id" value="{{.ID}}">
<button class="btn ghost" type="submit" style="color:var(--danger-soft-text);font-size:11px;padding:2px 6px">删除</button>
</form>
</div>
</div>
</div>
{{end}}
</div>
{{else}}
<div class="empty-state"><div class="empty-title">人脸库为空</div></div>
{{end}}
</div>
<div id="edit-modal" style="display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:1000;align-items:center;justify-content:center">
<div class="card" style="max-width:500px;width:90%;max-height:80vh;overflow-y:auto;position:relative">
<button class="btn ghost" type="button" onclick="closeEdit()" style="position:absolute;top:8px;right:8px;font-size:16px;padding:2px 8px;line-height:1">&times;</button>
<h3 style="margin-bottom:8px">编辑人员</h3>
<form method="post" action="/ui/face-gallery/rename" style="margin-bottom:12px;display:flex;gap:8px;align-items:flex-end">
<input type="hidden" name="id" id="edit-id">
<label style="flex:1;margin:0"><span class="small muted" style="display:block;margin-bottom:4px">姓名</span><input type="text" name="name" id="edit-name" required /></label>
<button class="btn" type="submit" style="margin-bottom:1px">保存</button>
</form>
<div id="edit-photos" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px"></div>
<form method="post" action="/ui/face-gallery/add-photo" enctype="multipart/form-data" style="display:flex;gap:8px;align-items:flex-end">
<input type="hidden" name="id" id="add-photo-id">
<label style="flex:1;margin:0"><span class="small muted" style="display:block;margin-bottom:4px">添加照片</span><input type="file" name="photo" accept="image/*" /></label>
<button class="btn ghost" type="submit" style="margin-bottom:1px">上传</button>
</form>
</div>
</div>
<script>
var photoData = {};
document.querySelectorAll('.photo-viewer').forEach(function(el) {
var photos = JSON.parse(el.dataset.photos);
var id = el.querySelector('img') ? el.querySelector('img').id.replace('img-','') : '';
if (id) photoData[id] = {photos: photos, idx: 0};
});
function navPhoto(id, dir) {
var d = photoData[id]; if (!d || d.photos.length<2) return;
d.idx = (d.idx + dir + d.photos.length) % d.photos.length;
document.getElementById('img-'+id).src = d.photos[d.idx];
document.getElementById('prev-'+id).style.display = d.idx === 0 ? 'none' : '';
document.getElementById('next-'+id).style.display = d.idx === d.photos.length-1 ? 'none' : '';
}
function editPerson(id, name, photos) {
document.getElementById('edit-id').value = id;
document.getElementById('edit-name').value = name;
document.getElementById('add-photo-id').value = id;
var ph = document.getElementById('edit-photos');
ph.innerHTML = photos.map(function(p,i) { return '<div style="position:relative;width:80px;height:100px"><img src="'+p+'" style="width:100%;height:100%;object-fit:cover;border-radius:4px"><button class="btn ghost" style="position:absolute;top:2px;right:2px;font-size:10px;padding:1px 3px;color:red;background:rgba(0,0,0,0.5)" onclick="if(confirm(\'删除这张照片?\')) this.parentElement.remove()">&times;</button></div>'; }).join('');
document.getElementById('edit-modal').style.display = 'flex';
}
function closeEdit() { document.getElementById('edit-modal').style.display = 'none'; }
</script>
{{end}}