165 lines
6.8 KiB
HTML
165 lines
6.8 KiB
HTML
{{define "models"}}
|
|
{{$board := .ModelStatusBoard}}
|
|
<div class="card">
|
|
<div class="section-title">
|
|
<div>
|
|
<h2 class="title-with-icon">{{icon "assets"}}<span>模型概览</span></h2>
|
|
<div class="form-hint">统一维护标准模型目录,设备页只看当前生效状态,更新动作统一走任务。</div>
|
|
</div>
|
|
<div class="actions compact">
|
|
<button class="btn secondary" type="button" onclick="showUpload()">上传新模型</button>
|
|
<form method="post" action="/models/sync">
|
|
{{if $board}}{{range $board.Rows}}{{if .NeedsSync}}<input type="hidden" name="device_id" value="{{.DeviceID}}">{{end}}{{end}}{{end}}
|
|
<input type="hidden" name="action" value="model_sync_all">
|
|
<button class="btn" type="submit">更新全部模型</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="stats">
|
|
<div class="stat accent-teal">
|
|
<div class="k metric-label">{{icon "template"}}<span>标准模型总数</span></div>
|
|
<div class="v">{{if $board}}{{$board.Summary.StandardModels}}{{else}}0{{end}}</div>
|
|
</div>
|
|
<div class="stat accent-teal">
|
|
<div class="k metric-label">{{icon "assets"}}<span>完整设备数</span></div>
|
|
<div class="v">{{if $board}}{{$board.Summary.CompleteDevices}}{{else}}0{{end}}</div>
|
|
</div>
|
|
<div class="stat accent-amber">
|
|
<div class="k metric-label">{{icon "warn"}}<span>缺失设备数</span></div>
|
|
<div class="v">{{if $board}}{{$board.Summary.MissingDevices}}{{else}}0{{end}}</div>
|
|
</div>
|
|
<div class="stat accent-amber">
|
|
<div class="k metric-label">{{icon "service"}}<span>版本不一致设备数</span></div>
|
|
<div class="v">{{if $board}}{{$board.Summary.MismatchDevices}}{{else}}0{{end}}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="section-title">
|
|
<div>
|
|
<h2 class="title-with-icon">{{icon "template"}}<span>标准模型</span></h2>
|
|
<div class="form-hint">版本号用于展示,设备一致性以模型哈希校验。</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table>
|
|
<thead>
|
|
<tr><th>模型名</th><th>分类</th><th>文件名</th><th>版本</th><th>哈希</th><th>大小</th></tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .StandardModels}}
|
|
<tr>
|
|
<td><span class="mono table-key">{{.Name}}</span></td>
|
|
<td>{{modelTypeLabel .ModelType}}</td>
|
|
<td class="mono">{{.FileName}}</td>
|
|
<td>{{if .Version}}{{.Version}}{{else}}auto{{end}}</td>
|
|
<td class="mono">{{shortHash .SHA256}}</td>
|
|
<td>{{.SizeBytes}}</td>
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="6" class="muted">标准模型目录为空。</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="section-title">
|
|
<div>
|
|
<h2 class="title-with-icon">{{icon "devices"}}<span>设备模型状态</span></h2>
|
|
<div class="form-hint">按标准模型逐项比对设备已安装状态,缺失和不一致会直接标出。</div>
|
|
</div>
|
|
</div>
|
|
<div class="table-wrap">
|
|
<table class="models-status-table">
|
|
<thead>
|
|
<tr>
|
|
<th>设备</th>
|
|
{{range .StandardModels}}<th class="model-status-col" title="{{.Name}}"><span class="model-status-label">{{modelTypeLabel .ModelType}}</span></th>{{end}}
|
|
<th class="model-extra-col">非标准模型</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{if and $board (gt (len $board.Rows) 0)}}
|
|
{{range $board.Rows}}
|
|
<tr>
|
|
<td>
|
|
<div class="table-key">{{.DeviceName}}</div>
|
|
<div class="muted small mono">{{.DeviceID}}</div>
|
|
</td>
|
|
{{range .Cells}}
|
|
<td>
|
|
{{if eq .Status "ok"}}<span class="pill ok">一致</span>
|
|
{{else if eq .Status "mismatch"}}<span class="pill warn">不一致</span>
|
|
{{else if eq .Status "na"}}<span class="pill muted-pill">不适用</span>
|
|
{{else}}<span class="pill bad">缺失</span>{{end}}
|
|
</td>
|
|
{{end}}
|
|
<td>
|
|
{{if gt .ExtraModelCount 0}}
|
|
<details class="mini-details">
|
|
<summary>{{.ExtraModelCount}} 个 · 更多</summary>
|
|
<div class="mini-details-body">
|
|
{{range .ExtraModels}}
|
|
<div class="mini-details-item mono">{{.FileName}}</div>
|
|
{{end}}
|
|
</div>
|
|
</details>
|
|
{{else}}
|
|
<span class="muted">0</span>
|
|
{{end}}
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
{{else}}
|
|
<tr><td colspan="99" class="muted">暂无设备模型状态。</td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="modal" class="modal-overlay" style="display:none">
|
|
<div class="card" style="max-width:480px;width:90%;position:relative">
|
|
<span class="btn-icon ghost" style="position:absolute;top:8px;right:8px" onclick="closeModal()">×</span>
|
|
<div id="modal-body"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function showUpload(){
|
|
document.getElementById('modal-body').innerHTML=
|
|
'<h3>上传新模型</h3>'+
|
|
'<form method="post" action="/models/upload" enctype="multipart/form-data">'+
|
|
'<div class="field-grid">'+
|
|
'<label><span>模型名称</span><input type="text" name="name" required placeholder="如 face_det_v2" /></label>'+
|
|
'<label><span>模型类型</span><select name="model_type">'+
|
|
'<option value="face_detection">人脸检测</option>'+
|
|
'<option value="face_recognition">人脸识别</option>'+
|
|
'<option value="ppe_detection">PPE检测</option>'+
|
|
'<option value="shoe_detection">工鞋检测</option>'+
|
|
'<option value="object_detection">通用检测</option>'+
|
|
'<option value="other">其他</option>'+
|
|
'</select></label>'+
|
|
'<label><span>版本号 <span class="muted small">(可选,留空自动生成)</span></span><input type="text" name="version" placeholder="自动生成" /></label>'+
|
|
'<label><span>描述 <span class="muted small">(可选)</span></span><input type="text" name="description" placeholder="" /></label>'+
|
|
'<label><span>模型文件 (.rknn)</span><input type="file" name="file" accept=".rknn" required /></label>'+
|
|
'</div>'+
|
|
'<label style="display:flex;align-items:center;gap:8px;margin:12px 0">'+
|
|
'<input type="checkbox" name="auto_sync" value="1" checked />'+
|
|
'<span class="small">上传后自动分发到所有在线设备</span>'+
|
|
'</label>'+
|
|
'<div class="actions"><button class="btn" type="submit">上传</button></div>'+
|
|
'</form>';
|
|
document.getElementById('modal').style.display='flex';
|
|
}
|
|
function closeModal(){document.getElementById('modal').style.display='none';}
|
|
</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}}
|