refactor: modal dialogs for face gallery, unified pattern

This commit is contained in:
tian 2026-05-08 11:32:57 +08:00
parent 5c8ca581f4
commit 5cc7396663

View File

@ -1,28 +1,8 @@
{{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 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>
@ -32,6 +12,10 @@
<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(4,minmax(0,1fr));gap:16px;margin-top:12px">
@ -51,7 +35,7 @@
<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>
<button class="btn ghost" type="button" style="font-size:11px;padding:2px 6px" onclick="showEdit({{.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>
@ -66,46 +50,44 @@
{{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};
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 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 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 closeEdit() { document.getElementById('edit-modal').style.display = 'none'; }
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}}