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

94 lines
6.9 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 id="modal" class="modal-overlay" style="display:none">
<div class="card" style="max-width:500px;width:90%;max-height:80vh;overflow-y:auto;position:relative">
<button class="btn ghost" type="button" onclick="closeModal()" style="position:absolute;top:8px;right:8px;font-size:16px;padding:2px 8px;line-height:1">&times;</button>
<div id="modal-body"></div>
</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 class="actions compact">
<button class="btn secondary" type="button" onclick="showImport()">批量导入</button>
<button class="btn" type="button" onclick="showAdd()">新增人员</button>
</div>
</div>
{{if .FaceGalleryPersons}}
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:16px;margin-top:12px">
{{range .FaceGalleryPersons}}
<div class="card" style="padding:8px;max-width:200px">
<div class="photo-viewer" data-photos='[{{range $i,$p := .Photos}}{{if $i}},{{end}}"/ui/face-photo/{{$p}}"{{end}}]' style="width:100%;aspect-ratio:3/4;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;display:flex;justify-content:space-between;align-items:center">
<div><span style="font-weight:500;font-size:13px">{{.Name}}</span> <span class="muted small">{{.PhotoCount}}张</span></div>
<div class="actions compact" style="gap:2px">
<button class="btn ghost" type="button" style="font-size:12px;padding:0;width:22px;height:22px;min-height:auto;gap:0" title="编辑" onclick="showEdit({{.ID}},'{{.Name}}',[{{range $i,$p := .Photos}}{{if $i}},{{end}}'/ui/face-photo/{{$p}}'{{end}}])">&#9998;</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:12px;padding:0;width:22px;height:22px;min-height:auto;gap:0" title="删除">&#10005;</button>
</form>
</div>
</div>
</div>
{{end}}
</div>
{{else}}
<div class="empty-state"><div class="empty-title">人脸库为空</div></div>
{{end}}
</div>
<script>
var photoData={};
document.querySelectorAll('.photo-viewer').forEach(function(el){
var p=JSON.parse(el.dataset.photos);
var id=el.querySelector('img')?el.querySelector('img').id.replace('img-',''):'';
if(id)photoData[id]={photos:p,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 showImport(){
document.getElementById('modal-body').innerHTML='<h3 style="margin-bottom:12px">批量导入</h3><div class="form-hint" style="margin-bottom:12px">选择按姓名分目录的照片根目录。</div><form method="post" action="/ui/face-gallery/import" enctype="multipart/form-data"><label class="full" style="margin-bottom:12px;display:block"><span>选择照片目录</span><input type="file" name="photos" webkitdirectory multiple required /></label><div class="actions"><button class="btn" type="submit">导入</button></div></form>';
document.getElementById('modal').style.display='flex';
}
function showAdd(){
document.getElementById('modal-body').innerHTML='<h3 style="margin-bottom:12px">新增人员</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" 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>';
document.getElementById('modal').style.display='flex';
}
function showEdit(id,name,photos){
document.getElementById('modal-body').innerHTML='<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" value="'+id+'"><label style="flex:1;margin:0"><span class="small muted" style="display:block;margin-bottom:4px">姓名</span><input type="text" name="name" value="'+esc(name)+'" required /></label>'+
'<button class="btn" type="submit" style="margin-bottom:1px">保存</button></form>'+
'<div style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px">'+photos.map(function(p){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('')+'</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" value="'+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>';
document.getElementById('modal').style.display='flex';
}
function closeModal(){document.getElementById('modal').style.display='none';}
function esc(s){return(s||'').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
</script>
<style>
.modal-overlay{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}
</style>
{{end}}