Files
ucvl-home-vision/web/devices.js
T

61 lines
7.5 KiB
JavaScript
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.
'use strict';
let deviceGroups=['type','space'],deviceGroupScope='',deviceViewSignature='';
const deviceDimensions={type:'设备类型',space:'区域空间',manager:'负责人',owner:'所有人',tag:'自定义标签'};
function renderDeviceGrouping(){
$('#device-group-order').innerHTML=deviceGroups.map((g,i)=>`<div class="group-step"><span>${i+1}</span><select data-group-index="${i}" aria-label="第 ${i+1} 分组">${Object.entries(deviceDimensions).map(([key,label])=>`<option value="${key}" ${key===g?'selected':''} ${deviceGroups.includes(key)&&key!==g?'disabled':''}>${label}</option>`).join('')}</select><button class="quiet" data-group-up="${i}" aria-label="第 ${i+1} 分组前移" ${i===0?'disabled':''}>↑</button><button class="quiet" data-group-remove="${i}" aria-label="移除第 ${i+1} 分组">×</button></div>`).join('');
$$('[data-group-preset]').forEach(b=>b.setAttribute('aria-pressed',String(b.dataset.groupPreset===deviceGroups.join(','))));
$('#device-group-add').disabled=deviceGroups.length>=Object.keys(deviceDimensions).length;
}
function videoDeviceActions(d){
if(!['camera','recorder'].includes(d.source))return '';
const channels=state.cameras.filter(c=>d.source==='camera'?c.assetId===d.id:c.recorderId===d.id||c.archiveRecorderId===d.id);
const target=`data-view-device="${esc(d.id)}" data-device-source="${d.source}"`;
return `<div class="camera-actions">${isAdmin()?`<button class="secondary" ${target} data-open-device-tab="cameras">配置镜头</button>`:''}${channels.length?`<button class="quiet" ${target} data-open-device-tab="live">查看画面</button><button class="quiet" ${target} data-open-device-tab="playback">录像回放</button>`:''}</div>${!channels.length?'<p class="description">尚未接入画面,请先配置镜头通道。</p>':''}`;
}
function deviceCard(d){
const location=ZhaoDevices.path(state.sites,d.siteId).map(s=>s.name).join(' / ')||'未指定区域';
const attr=d.source==='camera'?'edit-asset':d.source==='recorder'?'edit-recorder':'edit-device';
const detail=d.source==='camera'?`<div><dt>镜头 / 通道</dt><dd>${d.lensCount} 个镜头 · ${state.cameras.filter(c=>c.assetId===d.id).length} 个已配置通道</dd></div>`:d.source==='recorder'?`<div><dt>关联镜头</dt><dd>${state.cameras.filter(c=>c.recorderId===d.id||c.archiveRecorderId===d.id).length} 个</dd></div>`:'<div><dt>接入状态</dt><dd>仅登记档案,尚未接入控制</dd></div>';
return `<article class="site-card"><div class="site-heading"><span class="badge">${esc(d.deviceType)}</span>${isAdmin()?`<button class="quiet" data-${attr}="${esc(d.id)}">编辑</button>`:''}</div><h3><button class="device-title" data-view-device="${esc(d.id)}" data-device-source="${d.source}">${esc(d.name)} <span aria-hidden="true">›</span></button></h3><dl><div><dt>所在区域</dt><dd>${esc(location)}</dd></div><div><dt>所有人</dt><dd>${esc(d.ownerName||'待指定')}</dd></div><div><dt>负责人</dt><dd>${esc(d.managerName||'待指定')}</dd></div><div><dt>品牌型号</dt><dd>${esc([d.brand,d.model].filter(Boolean).join(' / ')||'待填写')}</dd></div>${detail}</dl>${videoDeviceActions(d)}${d.tags?.length?`<p class="device-tags">${d.tags.map(t=>`<span>${esc(t)}</span>`).join('')}</p>`:''}</article>`;
}
function renderDevices(){
const home=(state.households||[]).find(h=>h.id===state.familyId),saved=home?.deviceGrouping||['type','space'];
const signature=JSON.stringify(saved);
if(deviceGroupScope!==state.familyId||deviceViewSignature!==signature){deviceGroupScope=state.familyId;deviceViewSignature=signature;deviceGroups=[...saved];renderDeviceGrouping();}
$('#device-clear').hidden=!($('#site-filter').value||$('#device-type').value||$('#device-search').value);
const search=$('#device-search').value.trim().toLowerCase();
const all=ZhaoDevices.catalog(state),types=[...new Set(all.map(d=>d.deviceType))].sort();
setOptions($('#device-type'),'<option value="">所有类型</option>'+types.map(type=>`<option value="${esc(type)}">${esc(type)}</option>`).join(''));
const category=$('#device-type').value;
const range=$('#site-filter').value?ZhaoDevices.descendants(state.sites,$('#site-filter').value):null;
const devices=all.filter(d=>(!range||range.has(d.siteId))&&(!category||d.deviceType===category)&&ZhaoDevices.matches(d,search,state.sites));
$('#device-count').textContent=`${devices.length} 台设备 · 按 ${deviceGroups.map(g=>deviceDimensions[g]).join(' → ')||'全部平铺'} 查看`;
$('#asset-list').innerHTML=devices.length?ZhaoDevices.groups(devices,deviceGroups,state.sites).map(group=>`<section class="device-group"><h3>${group.labels.map(esc).join(' <span aria-hidden="true">›</span> ')||'全部设备'} <small>${group.items.length} 台</small></h3><div class="site-grid">${group.items.map(deviceCard).join('')}</div></section>`).join(''):empty('当前条件下没有设备','可以清除筛选,或添加摄像机、录像机、灯、手机等设备档案。');
}
function resetDeviceView(){deviceGroupScope='';deviceViewSignature='';deviceGroups=['type','space'];$('#device-search').value='';$('#device-type').innerHTML='<option value="">所有类型</option>';$('#device-group-order').replaceChildren();}
function responsibilityFields(form,item){for(const key of ['ownerName','managerName'])form.elements[key].value=item?.[key]||'';form.elements.tags.value=(item?.tags||[]).join('、');}
function deviceValues(data){return {...data,tags:(data.tags||'').split(/[,,、\n]+/).map(t=>t.trim()).filter(Boolean)};}
function openDevice(id){
const item=(state.devices||[]).find(d=>d.id===id)||{},f=$('#device-form');
f.elements.siteId.innerHTML='<option value="">未指定区域</option>'+spaceOptions();fillForm(f,item);if(!item.id)f.elements.siteId.value=$('#site-filter').value||'';responsibilityFields(f,item);$('#device-dialog').showModal();
}
function spaceOptions(exclude=''){
const omitted=exclude?ZhaoDevices.descendants(state.sites,exclude):new Set();
return state.sites.filter(s=>!omitted.has(s.id)).map(s=>`<option value="${esc(s.id)}">${esc(siteName(s.id))}</option>`).join('');
}
function clearDeviceFilters(){$('#site-filter').value='';$('#device-type').value='';$('#device-search').value='';renderDevices();}
$('#device-clear').onclick=clearDeviceFilters;
$('#device-search').oninput=renderDevices;$('#device-type').onchange=renderDevices;
$('#device-group-order').addEventListener('change',e=>{if(e.target.dataset.groupIndex!==undefined){deviceGroups[Number(e.target.dataset.groupIndex)]=e.target.value;renderDeviceGrouping();renderDevices();}});
$('#device-group-add').onclick=()=>{const next=Object.keys(deviceDimensions).find(k=>!deviceGroups.includes(k));if(next){deviceGroups.push(next);renderDeviceGrouping();renderDevices();}};
$('#device-view-save').onclick=async()=>{try{await api('/api/device-view',{groups:deviceGroups});await refresh();toast('已保存为本家庭或场所的默认分组');}catch(e){if(!e.stale)toast(e.message);}};
$('#new-device').onclick=()=>openDevice();
handleForm('device-form','/api/devices',deviceValues);
document.addEventListener('click',e=>{
const b=e.target.closest('button');if(!b)return;
if(b.dataset.groupPreset){deviceGroups=b.dataset.groupPreset.split(',');renderDeviceGrouping();renderDevices();}
if(b.dataset.editDevice)openDevice(b.dataset.editDevice);
if(b.dataset.groupRemove!==undefined){deviceGroups.splice(Number(b.dataset.groupRemove),1);renderDeviceGrouping();renderDevices();}
if(b.dataset.groupUp!==undefined){const i=Number(b.dataset.groupUp);if(i>0){[deviceGroups[i-1],deviceGroups[i]]=[deviceGroups[i],deviceGroups[i-1]];renderDeviceGrouping();renderDevices();}}
});