Commit e3b335fb by 久林

feat: 监控点位、整点曲线与环境总览体验优化

设施摄像头三维显隐与通信参数;大屏曲线整点小时;环境总览湿度曲线与房间中文名;全景底栏飞主视图;点位图标缩小。

Co-authored-by: Cursor <cursoragent@cursor.com>
parent e1a7ff5a
import{d as v,j as b,u as y,c,b as e,t,h as n,F as p,x as h,p as S,o as r}from"./index-BssDqbym.js";import{u as k}from"./realtime-lmP-Cubp.js";const x={class:"page-fill",style:{"flex-direction":"row"}},C={class:"panel",style:{flex:"1",overflow:"auto"}},T={class:"panel-head"},w={class:"panel-title"},D={class:"badge"},z={class:"table"},N=["disabled","onClick"],A={style:{"margin-top":"12px","font-size":"12px",color:"var(--label)"}},O={class:"panel",style:{flex:"1",overflow:"auto"}},P={class:"panel-head"},R={class:"panel-title"},B={class:"table"},W=v({__name:"AccessView",setup(E){const{t:s,locale:i}=b(),u=y(),d=k();function f(a){const o=i.value==="zh-CN"?"zh-CN":i.value==="zh-TW"?"zh-TW":i.value==="pt"?"pt-PT":"en-US";return new Date(a).toLocaleString(o,{hour12:!1})}function m(a){return a==="open"?s("pages.doorOpen"):a==="closed"?s("pages.doorClosed"):a==="alarm"?s("doorStatus.alarm"):a==="offline"?s("doorStatus.offline"):a}function _(a){return a==="success"?s("pages.accessSuccess"):a==="denied"?s("pages.accessDenied"):a==="alarm"?s("doorStatus.alarm"):a}async function g(a){if(!u.isAdmin)return;const o=await S("/api/realtime/access/open",{method:"POST",token:u.token,body:JSON.stringify({doorId:a})});alert(o.message)}return(a,o)=>(r(),c("div",x,[e("section",C,[e("div",T,[e("div",w,[o[0]||(o[0]=e("div",{class:"vbar"},null,-1)),e("h3",null,t(n(s)("pages.accessTitle")),1)]),e("div",D,t(n(s)("pages.accessToday",{n:n(d).snapshot.access.todayPassCount})),1)]),e("table",z,[e("thead",null,[e("tr",null,[e("th",null,t(n(s)("pages.accessDoor")),1),e("th",null,t(n(s)("screen.status")),1),e("th",null,t(n(s)("common.action")),1)])]),e("tbody",null,[(r(!0),c(p,null,h(n(d).snapshot.access.doors,l=>(r(),c("tr",{key:l.id},[e("td",null,t(l.name),1),e("td",null,t(m(l.status)),1),e("td",null,[e("button",{class:"btn",disabled:!n(u).isAdmin,onClick:F=>g(l.id)},t(n(s)("pages.accessOpenRemote")),9,N)])]))),128))])]),e("p",A,t(n(s)("pages.accessFoot")),1)]),e("section",O,[e("div",P,[e("div",R,[o[1]||(o[1]=e("div",{class:"vbar"},null,-1)),e("h3",null,t(n(s)("pages.accessEvents")),1)])]),e("table",B,[e("thead",null,[e("tr",null,[e("th",null,t(n(s)("pages.accessTime")),1),e("th",null,t(n(s)("pages.accessDoor")),1),e("th",null,t(n(s)("pages.accessPerson")),1),e("th",null,t(n(s)("pages.accessResult")),1)])]),e("tbody",null,[(r(!0),c(p,null,h(n(d).snapshot.access.recentEvents,l=>(r(),c("tr",{key:l.id},[e("td",null,t(f(l.time)),1),e("td",null,t(l.doorName),1),e("td",null,t(l.person),1),e("td",null,t(_(l.result)),1)]))),128))])])])]))}});export{W as default};
import{d as f,u as h,c as n,b as t,t as e,h as i,F as u,z as c,o,l as b}from"./index-Bs_x-_cK.js";import{u as v}from"./realtime-CI_KLy_N.js";const _={class:"page-fill",style:{"flex-direction":"row"}},y={class:"panel",style:{flex:"1",overflow:"auto"}},k={class:"panel-head"},g={class:"badge"},w={class:"table"},x=["disabled","onClick"],S={class:"panel",style:{flex:"1",overflow:"auto"}},C={class:"table"},B=f({__name:"AccessView",setup(N){const r=h(),d=v();function p(a){return new Date(a).toLocaleString("zh-CN",{hour12:!1})}async function m(a){if(!r.isAdmin)return;const s=await b("/api/realtime/access/open",{method:"POST",token:r.token,body:JSON.stringify({doorId:a})});alert(s.message)}return(a,s)=>(o(),n("div",_,[t("section",y,[t("div",k,[s[0]||(s[0]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"门禁状态")],-1)),t("div",g,"今日通行 "+e(i(d).snapshot.access.todayPassCount),1)]),t("table",w,[s[1]||(s[1]=t("thead",null,[t("tr",null,[t("th",null,"门点"),t("th",null,"状态"),t("th",null,"操作")])],-1)),t("tbody",null,[(o(!0),n(u,null,c(i(d).snapshot.access.doors,l=>(o(),n("tr",{key:l.id},[t("td",null,e(l.name),1),t("td",null,e({open:"开启",closed:"关闭",alarm:"报警",offline:"离线"}[l.status]),1),t("td",null,[t("button",{class:"btn",disabled:!i(r).isAdmin,onClick:A=>m(l.id)},"远程开门",8,x)])]))),128))])]),s[2]||(s[2]=t("p",{style:{"margin-top":"12px","font-size":"12px",color:"var(--label)"}}," 协议:海康 HCNetSDK(Windows 桥接)。一期为 Mock,二期接入桥接服务。 ",-1))]),t("section",S,[s[4]||(s[4]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"通行记录")])],-1)),t("table",C,[s[3]||(s[3]=t("thead",null,[t("tr",null,[t("th",null,"时间"),t("th",null,"门点"),t("th",null,"人员"),t("th",null,"结果")])],-1)),t("tbody",null,[(o(!0),n(u,null,c(i(d).snapshot.access.recentEvents,l=>(o(),n("tr",{key:l.id},[t("td",null,e(p(l.time)),1),t("td",null,e(l.doorName),1),t("td",null,e(l.person),1),t("td",null,e({success:"成功",denied:"拒绝",alarm:"报警"}[l.result]),1)]))),128))])])])]))}});export{B as default};
import{d as z,u as V,c as i,b as s,a as w,t as e,h as r,F as h,z as m,D as B,B as N,i as x,o as a,x as R,E as S,n as D,H as v,K as E}from"./index-Bs_x-_cK.js";import{u as H}from"./useClock-liJ_G-iS.js";const O={class:"tops-root"},I={class:"tops-header"},F={class:"tops-header__chips"},W={class:"tops-chip tops-tone--ok"},$={class:"tops-header__end"},j={class:"tops-clock"},J={class:"tops-body"},K={class:"tops-side","aria-label":"管理菜单"},P={class:"tops-menu"},T={class:"tops-menu__icon","aria-hidden":"true"},U={viewBox:"0 0 18 18",fill:"none",stroke:"currentColor","stroke-width":"1.3"},q=["d"],G={class:"tops-menu__copy"},Q={class:"tops-menu__label"},X={class:"tops-menu__hint"},Y={class:"tops-main"},os=z({__name:"AdminLayout",setup(Z){const n=V(),c=x(),d=E(),{time:b}=H(),k={devices:["M3 4.2h12v9.6H3z","M6.2 15.4h5.6","M7.4 13.8v1.6","M10.6 13.8v1.6"],cameras:["M3.2 6.2h8.2l1.6-1.8h3.2v11.2H3.2z","M9.2 11.2a2.2 2.2 0 1 0 0-4.4 2.2 2.2 0 0 0 0 4.4z"],metering:["M3.2 3.2h11.6v11.6H3.2z","M6 12.2V7.4","M9 12.2V5.6","M12 12.2V8.8"],users:["M6.6 8.6a2.6 2.6 0 1 0 0-5.2 2.6 2.6 0 0 0 0 5.2z","M12.2 8.4a2.1 2.1 0 1 0 0-4.2","M2 15.4c0-2.4 2.1-3.8 4.6-3.8s4.6 1.4 4.6 3.8","M13.6 15.4c0-1.7-.8-2.9-2.2-3.4"],settings:["M9 11.2a2.2 2.2 0 1 0 0-4.4 2.2 2.2 0 0 0 0 4.4z","M9 2.4l1.1 1.8 2.1-.2.9 1.9 1.8 1.1-.2 2.1 1.8 1.1-1.8 1.1.2 2.1-1.8 1.1-.9 1.9-2.1-.2L9 15.6l-1.1 1.8-2.1.2-.9-1.9-1.8-1.1.2-2.1L1.5 11l1.8-1.1-.2-2.1 1.8-1.1.9-1.9 2.1.2L9 2.4z"]},g=N(()=>[{to:"/admin/devices",label:"设备管理",hint:"点位 / 网关",tone:"accent",icon:"devices"},{to:"/admin/cameras",label:"摄像头管理",hint:"列表 / 三维打点",tone:"accent",icon:"cameras"},{to:"/admin/metering",label:"计量计费",hint:"能耗 / 费率 / 报表",tone:"accent",icon:"metering"},{to:"/admin/history",label:"历史曲线",hint:"时序 / 指标",tone:"accent",icon:"devices"},{to:"/admin/users",label:"用户管理",hint:"账号 / 角色",tone:"warn",icon:"users",adminOnly:!0},{to:"/admin/settings",label:"系统设置",hint:"采集 / 模式",tone:"muted",icon:"settings"}].filter(l=>!l.adminOnly||n.isAdmin));function M(l){return d.path===l||d.path.startsWith(`${l}/`)}function f(){n.logout(),c.push("/login")}function u(){c.push("/dashboard")}return(l,t)=>{var p,_;const y=v("RouterLink"),C=v("RouterView");return a(),i("div",O,[s("header",I,[s("div",{class:"tops-brand",onClick:u},[...t[0]||(t[0]=[w('<span class="tops-brand__mark" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 12c0-2.5 2-4.5 4.5-4.5S21 9.4 21 12c0 4.4-3.6 8-8 8-5 0-9-4-9-9 0-5.5 4.5-10 10-10" stroke-linecap="round"></path><circle cx="12" cy="12" r="1.7"></circle></svg></span><span class="tops-brand__copy"><strong>管理后台</strong><small>ADMIN CONSOLE</small></span>',2)])]),s("div",F,[t[3]||(t[3]=s("span",{class:"tops-chip"},[s("small",null,"系统"),s("b",null,"JH-LAB")],-1)),s("span",W,[t[1]||(t[1]=s("span",{class:"tops-dot","aria-hidden":"true"},null,-1)),t[2]||(t[2]=s("small",null,"角色",-1)),s("b",null,e(r(n).isAdmin?"ADMIN":"VIEWER"),1)])]),s("div",$,[s("div",j,[s("small",null,e(((p=r(n).user)==null?void 0:p.displayName)||((_=r(n).user)==null?void 0:_.username))+" · "+e(r(n).isAdmin?"管理员":"只读"),1),s("b",null,e(r(b)),1)]),s("button",{type:"button",class:"tops-logout",onClick:u},"返回大屏"),s("button",{type:"button",class:"tops-logout",onClick:f},"退出")])]),s("div",J,[s("nav",K,[t[4]||(t[4]=s("div",{class:"tops-side__head"},[s("strong",null,"菜单"),s("small",null,"MODULES")],-1)),s("div",P,[(a(!0),i(h,null,m(g.value,o=>(a(),R(y,{key:o.to,to:o.to,class:D(["tops-menu__item",[`tops-tone--${o.tone}`,{"is-on":M(o.to)}]])},{default:S(()=>[s("span",T,[(a(),i("svg",U,[(a(!0),i(h,null,m(k[o.icon],(A,L)=>(a(),i("path",{key:L,d:A,"stroke-linejoin":"round"},null,8,q))),128))]))]),s("span",G,[s("span",Q,e(o.label),1),s("span",X,e(o.hint),1)])]),_:2},1032,["to","class"]))),128))]),t[5]||(t[5]=s("div",{class:"tops-side__foot"},[s("span",{class:"tops-dot tops-tone--ok","aria-hidden":"true"}),s("span",null,"协议点表已接入")],-1))]),s("main",Y,[B(C)])])])}}});export{os as default};
import{d as V,u as w,c as i,b as s,a as z,t as e,h as r,F as h,x as m,H as N,s as x,J as v,i as B,D as O,I as R,n as S,O as D,o as a}from"./index-BssDqbym.js";import{u as H}from"./useClock-BjFim-x6.js";const I={class:"tops-root"},E={class:"tops-header"},F={class:"tops-header__chips"},J={class:"tops-chip tops-tone--ok"},W={class:"tops-header__end"},$={class:"tops-clock"},j={class:"tops-body"},P={class:"tops-side","aria-label":"管理菜单"},T={class:"tops-menu"},U={class:"tops-menu__icon","aria-hidden":"true"},q={viewBox:"0 0 18 18",fill:"none",stroke:"currentColor","stroke-width":"1.3"},G=["d"],K={class:"tops-menu__copy"},Q={class:"tops-menu__label"},X={class:"tops-menu__hint"},Y={class:"tops-main"},os=V({__name:"AdminLayout",setup(Z){const n=w(),c=B(),d=D(),{time:b}=H(),k={devices:["M3 4.2h12v9.6H3z","M6.2 15.4h5.6","M7.4 13.8v1.6","M10.6 13.8v1.6"],cameras:["M3.2 6.2h8.2l1.6-1.8h3.2v11.2H3.2z","M9.2 11.2a2.2 2.2 0 1 0 0-4.4 2.2 2.2 0 0 0 0 4.4z"],metering:["M3.2 3.2h11.6v11.6H3.2z","M6 12.2V7.4","M9 12.2V5.6","M12 12.2V8.8"],users:["M6.6 8.6a2.6 2.6 0 1 0 0-5.2 2.6 2.6 0 0 0 0 5.2z","M12.2 8.4a2.1 2.1 0 1 0 0-4.2","M2 15.4c0-2.4 2.1-3.8 4.6-3.8s4.6 1.4 4.6 3.8","M13.6 15.4c0-1.7-.8-2.9-2.2-3.4"],settings:["M9 11.2a2.2 2.2 0 1 0 0-4.4 2.2 2.2 0 0 0 0 4.4z","M9 2.4l1.1 1.8 2.1-.2.9 1.9 1.8 1.1-.2 2.1 1.8 1.1-1.8 1.1.2 2.1-1.8 1.1-.9 1.9-2.1-.2L9 15.6l-1.1 1.8-2.1.2-.9-1.9-1.8-1.1.2-2.1L1.5 11l1.8-1.1-.2-2.1 1.8-1.1.9-1.9 2.1.2L9 2.4z"]},g=x(()=>[{to:"/admin/devices",label:"数据采集",hint:"设备 / 点位 / 网关",tone:"accent",icon:"devices"},{to:"/admin/sensors",label:"设施管理",hint:"压差 / 照明 / 监控 / 门禁",tone:"accent",icon:"devices"},{to:"/admin/metering",label:"计量计费",hint:"能耗 / 费率 / 报表",tone:"accent",icon:"metering"},{to:"/admin/history",label:"历史曲线",hint:"时序 / 指标",tone:"accent",icon:"devices"},{to:"/admin/users",label:"用户管理",hint:"账号 / 角色",tone:"warn",icon:"users",adminOnly:!0},{to:"/admin/settings",label:"系统设置",hint:"采集 / 模式",tone:"muted",icon:"settings"}].filter(l=>!l.adminOnly||n.isAdmin));function M(l){return d.path===l||d.path.startsWith(`${l}/`)}function f(){n.logout(),c.push("/login")}function u(){c.push("/dashboard")}return(l,t)=>{var p,_;const y=v("RouterLink"),C=v("RouterView");return a(),i("div",I,[s("header",E,[s("div",{class:"tops-brand",onClick:u},[...t[0]||(t[0]=[z('<span class="tops-brand__mark" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 12c0-2.5 2-4.5 4.5-4.5S21 9.4 21 12c0 4.4-3.6 8-8 8-5 0-9-4-9-9 0-5.5 4.5-10 10-10" stroke-linecap="round"></path><circle cx="12" cy="12" r="1.7"></circle></svg></span><span class="tops-brand__copy"><strong>管理后台</strong><small>ADMIN CONSOLE</small></span>',2)])]),s("div",F,[t[3]||(t[3]=s("span",{class:"tops-chip"},[s("small",null,"系统"),s("b",null,"JH-LAB")],-1)),s("span",J,[t[1]||(t[1]=s("span",{class:"tops-dot","aria-hidden":"true"},null,-1)),t[2]||(t[2]=s("small",null,"角色",-1)),s("b",null,e(r(n).isAdmin?"ADMIN":"VIEWER"),1)])]),s("div",W,[s("div",$,[s("small",null,e(((p=r(n).user)==null?void 0:p.displayName)||((_=r(n).user)==null?void 0:_.username))+" · "+e(r(n).isAdmin?"管理员":"只读"),1),s("b",null,e(r(b)),1)]),s("button",{type:"button",class:"tops-logout",onClick:u},"返回大屏"),s("button",{type:"button",class:"tops-logout",onClick:f},"退出")])]),s("div",j,[s("nav",P,[t[4]||(t[4]=s("div",{class:"tops-side__head"},[s("strong",null,"菜单"),s("small",null,"MODULES")],-1)),s("div",T,[(a(!0),i(h,null,m(g.value,o=>(a(),O(y,{key:o.to,to:o.to,class:S(["tops-menu__item",[`tops-tone--${o.tone}`,{"is-on":M(o.to)}]])},{default:R(()=>[s("span",U,[(a(),i("svg",q,[(a(!0),i(h,null,m(k[o.icon],(A,L)=>(a(),i("path",{key:L,d:A,"stroke-linejoin":"round"},null,8,G))),128))]))]),s("span",K,[s("span",Q,e(o.label),1),s("span",X,e(o.hint),1)])]),_:2},1032,["to","class"]))),128))]),t[5]||(t[5]=s("div",{class:"tops-side__foot"},[s("span",{class:"tops-dot tops-tone--ok","aria-hidden":"true"}),s("span",null,"协议点表已接入")],-1))]),s("main",Y,[N(C)])])])}}});export{os as default};
import{d as s,c as i,n,b as e,a as r,f as c,o,_ as d}from"./index-BssDqbym.js";const k=["stroke"],h=s({__name:"AppIcon",props:{name:{},className:{default:""}},setup(t){return(F,l)=>{var a;return t.name==="logo"?(o(),i("svg",{key:0,class:n(["icon",t.className]),viewBox:"0 0 34 34",fill:"none"},[...l[0]||(l[0]=[e("path",{d:"M17 3.4 29.5 10.6v12.8L17 30.6 4.5 23.4V10.6L17 3.4Z",stroke:"#37C8FF","stroke-width":"1.6","stroke-linejoin":"round"},null,-1),e("path",{d:"M17 3.4v13.4M17 16.8 29.5 10.6M17 16.8 4.5 23.4",stroke:"#37C8FF","stroke-width":"1.2",opacity:".7"},null,-1),e("circle",{cx:"17",cy:"16.8",r:"2.8",fill:"#2EE6A8"},null,-1)])],2)):t.name==="panel-env"?(o(),i("svg",{key:1,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[1]||(l[1]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M10 13.8V5a2 2 0 1 1 4 0v8.8a4.5 4.5 0 1 1-4 0Z",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"17",r:"1.6",fill:"#5BD4FF"},null,-1)])],2)):t.name==="panel-vav"?(o(),i("svg",{key:2,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[2]||(l[2]=[r('<rect width="24" height="24" rx="7" fill="#37C8FF" fill-opacity=".14" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="6.25" stroke="#37C8FF" stroke-opacity=".45" data-v-efd0f58c></rect><circle cx="12" cy="12" r="7.4" stroke="#5BD4FF" stroke-width="1.7" data-v-efd0f58c></circle><circle cx="12" cy="12" r="1.7" fill="#5BD4FF" data-v-efd0f58c></circle><path d="M12 10.3V5.2M13.5 12.9l4.4 2.4M10.5 12.9l-4.4 2.4" stroke="#5BD4FF" stroke-width="1.7" stroke-linecap="round" data-v-efd0f58c></path>',5)])],2)):t.name==="panel-cold"?(o(),i("svg",{key:3,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[3]||(l[3]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M12 3.5v17M4.6 7.75l14.8 8.5M19.4 7.75l-14.8 8.5",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-hvac"?(o(),i("svg",{key:4,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[4]||(l[4]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M3 8.5h9a2.2 2.2 0 1 0-2.2-2.2M3 12h13a2.2 2.2 0 1 1-2.2 2.2M3 15.5h6",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-alarm"?(o(),i("svg",{key:5,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[5]||(l[5]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#FF5252","fill-opacity":".12"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#FF5252","stroke-opacity":".45"},null,-1),e("path",{d:"M12 3.5a4.5 4.5 0 0 0-4.5 4.5v2.8L6 13.5h12l-1.5-2.7V8A4.5 4.5 0 0 0 12 3.5Z",stroke:"#FF7B7B","stroke-width":"1.8","stroke-linejoin":"round"},null,-1),e("path",{d:"M10 16.5a2 2 0 0 0 4 0",stroke:"#FF7B7B","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-video"?(o(),i("svg",{key:6,class:n(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[6]||(l[6]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("rect",{x:"3",y:"7",width:"12",height:"10",rx:"2",stroke:"#5BD4FF","stroke-width":"1.8"},null,-1),e("path",{d:"M15 10.8 20 8v8l-5-2.8",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linejoin":"round"},null,-1)])],2)):t.name==="metric-pressure"?(o(),i("svg",{key:7,class:n(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[7]||(l[7]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#2EE6A8","fill-opacity":".10"},null,-1),e("path",{d:"M4.5 15a7.5 7.5 0 0 1 15 0",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("path",{d:"M12 15l3.2-3.8",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"15",r:"1.5",fill:"#2EE6A8"},null,-1)])],2)):t.name==="metric-temp"?(o(),i("svg",{key:8,class:n(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[8]||(l[8]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M10 13.8V5a2 2 0 1 1 4 0v8.8a4.5 4.5 0 1 1-4 0Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"17",r:"1.7",fill:"#5BD4FF"},null,-1)])],2)):t.name==="metric-humidity"?(o(),i("svg",{key:9,class:n(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[9]||(l[9]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M12 3.5s5.6 6.2 5.6 10a5.6 5.6 0 1 1-11.2 0c0-3.8 5.6-10 5.6-10Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linejoin":"round"},null,-1)])],2)):t.name==="metric-air"?(o(),i("svg",{key:10,class:n(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[10]||(l[10]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M4.5 12a7.5 7.5 0 0 1 13-5.1M19.5 12a7.5 7.5 0 0 1-13 5.1",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("path",{d:"M17.5 3.5v3.6h-3.6M6.5 20.5v-3.6h3.6",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="vav-speed"?(o(),i("svg",{key:11,class:n(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[11]||(l[11]=[e("path",{d:"M3 9h9.5a2.4 2.4 0 1 0-2.4-2.4M3 13h13.5a2.4 2.4 0 1 1-2.4 2.4M3 17h6",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round"},null,-1)])],2)):t.name==="vav-sash"?(o(),i("svg",{key:12,class:n(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[12]||(l[12]=[e("path",{d:"M12 3.5v17M8.2 7.2 12 3.5l3.8 3.7M8.2 16.8l3.8 3.7 3.8-3.7",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="vav-valve"?(o(),i("svg",{key:13,class:n(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[13]||(l[13]=[e("circle",{cx:"12",cy:"12",r:"8",stroke:"#5BD4FF","stroke-width":"2.2"},null,-1),e("path",{d:"M12 7v5.2l3.8 2.6",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="fridge"?(o(),i("svg",{key:14,class:n(["icon f-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[e("path",{d:"M12 3.5v17M4.6 7.75l14.8 8.5M19.4 7.75l-14.8 8.5",stroke:(a=t.className)!=null&&a.includes("warn")?"#FFCF5C":"#7FD8FF","stroke-width":"2.4","stroke-linecap":"round"},null,8,k)],2)):t.name==="alarm-warn"?(o(),i("svg",{key:15,class:n(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[14]||(l[14]=[e("path",{d:"M12 3.5 2.8 19.5h18.4L12 3.5Z",stroke:"#FF6B6B","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("path",{d:"M12 9.5v4.5",stroke:"#FF6B6B","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"16.8",r:"1.1",fill:"#FF6B6B"},null,-1)])],2)):t.name==="alarm-amber"?(o(),i("svg",{key:16,class:n(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[15]||(l[15]=[e("path",{d:"M12 3.5 2.8 19.5h18.4L12 3.5Z",stroke:"#FFCF5C","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("path",{d:"M12 9.5v4.5",stroke:"#FFCF5C","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"16.8",r:"1.1",fill:"#FFCF5C"},null,-1)])],2)):t.name==="alarm-ok"?(o(),i("svg",{key:17,class:n(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[16]||(l[16]=[e("circle",{cx:"12",cy:"12",r:"8.3",stroke:"#2EE6A8","stroke-width":"2"},null,-1),e("path",{d:"M8.2 12.4l2.6 2.6 5-5.4",stroke:"#2EE6A8","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="cam-badge"?(o(),i("svg",{key:18,class:n(["icon corner",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[17]||(l[17]=[r('<rect width="24" height="24" rx="6" fill="#04101F" fill-opacity=".6" data-v-efd0f58c></rect><rect x=".5" y=".5" width="23" height="23" rx="5.5" stroke="#37C8FF" stroke-opacity=".45" data-v-efd0f58c></rect><rect x="4.5" y="8" width="10.5" height="8.5" rx="1.6" stroke="#D6ECFF" stroke-width="1.5" data-v-efd0f58c></rect><path d="M15 10.8l4.5-2.3v7.5L15 13.7" stroke="#D6ECFF" stroke-width="1.5" stroke-linejoin="round" data-v-efd0f58c></path><circle cx="8" cy="5.6" r="1.6" fill="#FF5252" data-v-efd0f58c></circle>',5)])],2)):t.name==="pin"?(o(),i("svg",{key:19,class:n(["icon pin",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[18]||(l[18]=[e("path",{d:"M12 21s-6.6-5.7-6.6-10.4a6.6 6.6 0 1 1 13.2 0C18.6 15.3 12 21 12 21Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"10.4",r:"2.3",stroke:"#5BD4FF","stroke-width":"2"},null,-1)])],2)):t.name==="hand"?(o(),i("svg",{key:20,class:n(["icon",t.className]),viewBox:"0 0 24 24",fill:"none",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},[...l[19]||(l[19]=[e("path",{d:"M9 11.5V6.5a1.5 1.5 0 0 1 3 0v4m0-1.5a1.5 1.5 0 0 1 3 0v1m0 0a1.5 1.5 0 0 1 3 0v4.5a6 6 0 0 1-6 6h-.8a6 6 0 0 1-4.9-2.5L4 15.6a1.6 1.6 0 0 1 2.5-2l1.5 1.9v-7a1.5 1.5 0 0 1 3 0"},null,-1)])],2)):t.name==="kpi-power"?(o(),i("svg",{key:21,class:n(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[20]||(l[20]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#FFB400","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#FFB400","stroke-opacity":".40"},null,-1),e("path",{d:"M13 2.5 5.5 13.5H11l-1.5 8L17 10.5h-5.5L13 2.5Z",stroke:"#FFCF5C","stroke-width":"1.8","stroke-linejoin":"round"},null,-1)])],2)):t.name==="kpi-water"?(o(),i("svg",{key:22,class:n(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[21]||(l[21]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#37C8FF","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#37C8FF","stroke-opacity":".35"},null,-1),e("path",{d:"M12 3s6 6.6 6 10.7a6 6 0 1 1-12 0C6 9.6 12 3 12 3Z",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linejoin":"round"},null,-1),e("path",{d:"M9.3 14a2.7 2.7 0 0 0 2.7 2.7",stroke:"#5BD4FF","stroke-width":"1.5","stroke-linecap":"round"},null,-1)])],2)):t.name==="kpi-cool"?(o(),i("svg",{key:23,class:n(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[22]||(l[22]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#67E8F9","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#67E8F9","stroke-opacity":".40"},null,-1),e("path",{d:"M12 2.5v19M3.7 7.25l16.6 9.5M20.3 7.25 3.7 16.75",stroke:"#A5F3FC","stroke-width":"1.7","stroke-linecap":"round"},null,-1)])],2)):t.name==="kpi-device"?(o(),i("svg",{key:24,class:n(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[23]||(l[23]=[r('<rect width="24" height="24" rx="6" fill="#34D399" fill-opacity=".10" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="5.25" stroke="#34D399" stroke-opacity=".40" data-v-efd0f58c></rect><rect x="3" y="4" width="18" height="7" rx="1.8" stroke="#6EE7B7" stroke-width="1.7" data-v-efd0f58c></rect><rect x="3" y="13" width="18" height="7" rx="1.8" stroke="#6EE7B7" stroke-width="1.7" data-v-efd0f58c></rect><circle cx="7" cy="7.5" r="1.3" fill="#34D399" data-v-efd0f58c></circle><circle cx="7" cy="16.5" r="1.3" fill="#34D399" data-v-efd0f58c></circle>',6)])],2)):t.name==="kpi-access"?(o(),i("svg",{key:25,class:n(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[24]||(l[24]=[r('<rect width="24" height="24" rx="6" fill="#A78BFA" fill-opacity=".14" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="5.25" stroke="#A78BFA" stroke-opacity=".5" data-v-efd0f58c></rect><path d="M6.5 4.5h8.2a1.8 1.8 0 0 1 1.8 1.8v11.4a1.8 1.8 0 0 1-1.8 1.8H6.5V4.5Z" stroke="#C4B5FD" stroke-width="1.7" stroke-linejoin="round" data-v-efd0f58c></path><circle cx="13.2" cy="12" r="1.15" fill="#C4B5FD" data-v-efd0f58c></circle><path d="M4.8 8.2h2.2M4.8 12h2.2M4.8 15.8h2.2" stroke="#C4B5FD" stroke-width="1.5" stroke-linecap="round" data-v-efd0f58c></path>',5)])],2)):c("",!0)}}}),v=d(h,[["__scopeId","data-v-efd0f58c"]]);export{v as A};
import{d as s,o as i,c as n,n as o,b as e,a as r,f as c,_ as d}from"./index-Bs_x-_cK.js";const k=["stroke"],h=s({__name:"AppIcon",props:{name:{},className:{default:""}},setup(t){return(F,l)=>{var a;return t.name==="logo"?(i(),n("svg",{key:0,class:o(["icon",t.className]),viewBox:"0 0 34 34",fill:"none"},[...l[0]||(l[0]=[e("path",{d:"M17 3.4 29.5 10.6v12.8L17 30.6 4.5 23.4V10.6L17 3.4Z",stroke:"#37C8FF","stroke-width":"1.6","stroke-linejoin":"round"},null,-1),e("path",{d:"M17 3.4v13.4M17 16.8 29.5 10.6M17 16.8 4.5 23.4",stroke:"#37C8FF","stroke-width":"1.2",opacity:".7"},null,-1),e("circle",{cx:"17",cy:"16.8",r:"2.8",fill:"#2EE6A8"},null,-1)])],2)):t.name==="panel-env"?(i(),n("svg",{key:1,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[1]||(l[1]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M10 13.8V5a2 2 0 1 1 4 0v8.8a4.5 4.5 0 1 1-4 0Z",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"17",r:"1.6",fill:"#5BD4FF"},null,-1)])],2)):t.name==="panel-vav"?(i(),n("svg",{key:2,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[2]||(l[2]=[r('<rect width="24" height="24" rx="7" fill="#37C8FF" fill-opacity=".14" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="6.25" stroke="#37C8FF" stroke-opacity=".45" data-v-efd0f58c></rect><circle cx="12" cy="12" r="7.4" stroke="#5BD4FF" stroke-width="1.7" data-v-efd0f58c></circle><circle cx="12" cy="12" r="1.7" fill="#5BD4FF" data-v-efd0f58c></circle><path d="M12 10.3V5.2M13.5 12.9l4.4 2.4M10.5 12.9l-4.4 2.4" stroke="#5BD4FF" stroke-width="1.7" stroke-linecap="round" data-v-efd0f58c></path>',5)])],2)):t.name==="panel-cold"?(i(),n("svg",{key:3,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[3]||(l[3]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M12 3.5v17M4.6 7.75l14.8 8.5M19.4 7.75l-14.8 8.5",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-hvac"?(i(),n("svg",{key:4,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[4]||(l[4]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("path",{d:"M3 8.5h9a2.2 2.2 0 1 0-2.2-2.2M3 12h13a2.2 2.2 0 1 1-2.2 2.2M3 15.5h6",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-alarm"?(i(),n("svg",{key:5,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[5]||(l[5]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#FF5252","fill-opacity":".12"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#FF5252","stroke-opacity":".45"},null,-1),e("path",{d:"M12 3.5a4.5 4.5 0 0 0-4.5 4.5v2.8L6 13.5h12l-1.5-2.7V8A4.5 4.5 0 0 0 12 3.5Z",stroke:"#FF7B7B","stroke-width":"1.8","stroke-linejoin":"round"},null,-1),e("path",{d:"M10 16.5a2 2 0 0 0 4 0",stroke:"#FF7B7B","stroke-width":"1.8","stroke-linecap":"round"},null,-1)])],2)):t.name==="panel-video"?(i(),n("svg",{key:6,class:o(["icon p-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[6]||(l[6]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".14"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"6.25",stroke:"#37C8FF","stroke-opacity":".45"},null,-1),e("rect",{x:"3",y:"7",width:"12",height:"10",rx:"2",stroke:"#5BD4FF","stroke-width":"1.8"},null,-1),e("path",{d:"M15 10.8 20 8v8l-5-2.8",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linejoin":"round"},null,-1)])],2)):t.name==="metric-pressure"?(i(),n("svg",{key:7,class:o(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[7]||(l[7]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#2EE6A8","fill-opacity":".10"},null,-1),e("path",{d:"M4.5 15a7.5 7.5 0 0 1 15 0",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("path",{d:"M12 15l3.2-3.8",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"15",r:"1.5",fill:"#2EE6A8"},null,-1)])],2)):t.name==="metric-temp"?(i(),n("svg",{key:8,class:o(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[8]||(l[8]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M10 13.8V5a2 2 0 1 1 4 0v8.8a4.5 4.5 0 1 1-4 0Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"17",r:"1.7",fill:"#5BD4FF"},null,-1)])],2)):t.name==="metric-humidity"?(i(),n("svg",{key:9,class:o(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[9]||(l[9]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M12 3.5s5.6 6.2 5.6 10a5.6 5.6 0 1 1-11.2 0c0-3.8 5.6-10 5.6-10Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linejoin":"round"},null,-1)])],2)):t.name==="metric-air"?(i(),n("svg",{key:10,class:o(["icon m-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[10]||(l[10]=[e("rect",{width:"24",height:"24",rx:"7",fill:"#37C8FF","fill-opacity":".12"},null,-1),e("path",{d:"M4.5 12a7.5 7.5 0 0 1 13-5.1M19.5 12a7.5 7.5 0 0 1-13 5.1",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},null,-1),e("path",{d:"M17.5 3.5v3.6h-3.6M6.5 20.5v-3.6h3.6",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="vav-speed"?(i(),n("svg",{key:11,class:o(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[11]||(l[11]=[e("path",{d:"M3 9h9.5a2.4 2.4 0 1 0-2.4-2.4M3 13h13.5a2.4 2.4 0 1 1-2.4 2.4M3 17h6",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round"},null,-1)])],2)):t.name==="vav-sash"?(i(),n("svg",{key:12,class:o(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[12]||(l[12]=[e("path",{d:"M12 3.5v17M8.2 7.2 12 3.5l3.8 3.7M8.2 16.8l3.8 3.7 3.8-3.7",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="vav-valve"?(i(),n("svg",{key:13,class:o(["icon v-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[13]||(l[13]=[e("circle",{cx:"12",cy:"12",r:"8",stroke:"#5BD4FF","stroke-width":"2.2"},null,-1),e("path",{d:"M12 7v5.2l3.8 2.6",stroke:"#5BD4FF","stroke-width":"2.2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="fridge"?(i(),n("svg",{key:14,class:o(["icon f-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[e("path",{d:"M12 3.5v17M4.6 7.75l14.8 8.5M19.4 7.75l-14.8 8.5",stroke:(a=t.className)!=null&&a.includes("warn")?"#FFCF5C":"#7FD8FF","stroke-width":"2.4","stroke-linecap":"round"},null,8,k)],2)):t.name==="alarm-warn"?(i(),n("svg",{key:15,class:o(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[14]||(l[14]=[e("path",{d:"M12 3.5 2.8 19.5h18.4L12 3.5Z",stroke:"#FF6B6B","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("path",{d:"M12 9.5v4.5",stroke:"#FF6B6B","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"16.8",r:"1.1",fill:"#FF6B6B"},null,-1)])],2)):t.name==="alarm-amber"?(i(),n("svg",{key:16,class:o(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[15]||(l[15]=[e("path",{d:"M12 3.5 2.8 19.5h18.4L12 3.5Z",stroke:"#FFCF5C","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("path",{d:"M12 9.5v4.5",stroke:"#FFCF5C","stroke-width":"2","stroke-linecap":"round"},null,-1),e("circle",{cx:"12",cy:"16.8",r:"1.1",fill:"#FFCF5C"},null,-1)])],2)):t.name==="alarm-ok"?(i(),n("svg",{key:17,class:o(["icon a-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[16]||(l[16]=[e("circle",{cx:"12",cy:"12",r:"8.3",stroke:"#2EE6A8","stroke-width":"2"},null,-1),e("path",{d:"M8.2 12.4l2.6 2.6 5-5.4",stroke:"#2EE6A8","stroke-width":"2","stroke-linecap":"round","stroke-linejoin":"round"},null,-1)])],2)):t.name==="cam-badge"?(i(),n("svg",{key:18,class:o(["icon corner",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[17]||(l[17]=[r('<rect width="24" height="24" rx="6" fill="#04101F" fill-opacity=".6" data-v-efd0f58c></rect><rect x=".5" y=".5" width="23" height="23" rx="5.5" stroke="#37C8FF" stroke-opacity=".45" data-v-efd0f58c></rect><rect x="4.5" y="8" width="10.5" height="8.5" rx="1.6" stroke="#D6ECFF" stroke-width="1.5" data-v-efd0f58c></rect><path d="M15 10.8l4.5-2.3v7.5L15 13.7" stroke="#D6ECFF" stroke-width="1.5" stroke-linejoin="round" data-v-efd0f58c></path><circle cx="8" cy="5.6" r="1.6" fill="#FF5252" data-v-efd0f58c></circle>',5)])],2)):t.name==="pin"?(i(),n("svg",{key:19,class:o(["icon pin",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[18]||(l[18]=[e("path",{d:"M12 21s-6.6-5.7-6.6-10.4a6.6 6.6 0 1 1 13.2 0C18.6 15.3 12 21 12 21Z",stroke:"#5BD4FF","stroke-width":"2","stroke-linejoin":"round"},null,-1),e("circle",{cx:"12",cy:"10.4",r:"2.3",stroke:"#5BD4FF","stroke-width":"2"},null,-1)])],2)):t.name==="hand"?(i(),n("svg",{key:20,class:o(["icon",t.className]),viewBox:"0 0 24 24",fill:"none",stroke:"#5BD4FF","stroke-width":"2","stroke-linecap":"round"},[...l[19]||(l[19]=[e("path",{d:"M9 11.5V6.5a1.5 1.5 0 0 1 3 0v4m0-1.5a1.5 1.5 0 0 1 3 0v1m0 0a1.5 1.5 0 0 1 3 0v4.5a6 6 0 0 1-6 6h-.8a6 6 0 0 1-4.9-2.5L4 15.6a1.6 1.6 0 0 1 2.5-2l1.5 1.9v-7a1.5 1.5 0 0 1 3 0"},null,-1)])],2)):t.name==="kpi-power"?(i(),n("svg",{key:21,class:o(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[20]||(l[20]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#FFB400","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#FFB400","stroke-opacity":".40"},null,-1),e("path",{d:"M13 2.5 5.5 13.5H11l-1.5 8L17 10.5h-5.5L13 2.5Z",stroke:"#FFCF5C","stroke-width":"1.8","stroke-linejoin":"round"},null,-1)])],2)):t.name==="kpi-water"?(i(),n("svg",{key:22,class:o(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[21]||(l[21]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#37C8FF","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#37C8FF","stroke-opacity":".35"},null,-1),e("path",{d:"M12 3s6 6.6 6 10.7a6 6 0 1 1-12 0C6 9.6 12 3 12 3Z",stroke:"#5BD4FF","stroke-width":"1.8","stroke-linejoin":"round"},null,-1),e("path",{d:"M9.3 14a2.7 2.7 0 0 0 2.7 2.7",stroke:"#5BD4FF","stroke-width":"1.5","stroke-linecap":"round"},null,-1)])],2)):t.name==="kpi-cool"?(i(),n("svg",{key:23,class:o(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[22]||(l[22]=[e("rect",{width:"24",height:"24",rx:"6",fill:"#67E8F9","fill-opacity":".10"},null,-1),e("rect",{x:".75",y:".75",width:"22.5",height:"22.5",rx:"5.25",stroke:"#67E8F9","stroke-opacity":".40"},null,-1),e("path",{d:"M12 2.5v19M3.7 7.25l16.6 9.5M20.3 7.25 3.7 16.75",stroke:"#A5F3FC","stroke-width":"1.7","stroke-linecap":"round"},null,-1)])],2)):t.name==="kpi-device"?(i(),n("svg",{key:24,class:o(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[23]||(l[23]=[r('<rect width="24" height="24" rx="6" fill="#34D399" fill-opacity=".10" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="5.25" stroke="#34D399" stroke-opacity=".40" data-v-efd0f58c></rect><rect x="3" y="4" width="18" height="7" rx="1.8" stroke="#6EE7B7" stroke-width="1.7" data-v-efd0f58c></rect><rect x="3" y="13" width="18" height="7" rx="1.8" stroke="#6EE7B7" stroke-width="1.7" data-v-efd0f58c></rect><circle cx="7" cy="7.5" r="1.3" fill="#34D399" data-v-efd0f58c></circle><circle cx="7" cy="16.5" r="1.3" fill="#34D399" data-v-efd0f58c></circle>',6)])],2)):t.name==="kpi-access"?(i(),n("svg",{key:25,class:o(["icon k-icon",t.className]),viewBox:"0 0 24 24",fill:"none"},[...l[24]||(l[24]=[r('<rect width="24" height="24" rx="6" fill="#A78BFA" fill-opacity=".14" data-v-efd0f58c></rect><rect x=".75" y=".75" width="22.5" height="22.5" rx="5.25" stroke="#A78BFA" stroke-opacity=".5" data-v-efd0f58c></rect><path d="M6.5 4.5h8.2a1.8 1.8 0 0 1 1.8 1.8v11.4a1.8 1.8 0 0 1-1.8 1.8H6.5V4.5Z" stroke="#C4B5FD" stroke-width="1.7" stroke-linejoin="round" data-v-efd0f58c></path><circle cx="13.2" cy="12" r="1.15" fill="#C4B5FD" data-v-efd0f58c></circle><path d="M4.8 8.2h2.2M4.8 12h2.2M4.8 15.8h2.2" stroke="#C4B5FD" stroke-width="1.5" stroke-linecap="round" data-v-efd0f58c></path>',5)])],2)):c("",!0)}}}),v=d(h,[["__scopeId","data-v-efd0f58c"]]);export{v as A};
.mask[data-v-684cbf61]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;background:#000814b8;display:grid;place-items:center;padding:24px}.dialog[data-v-684cbf61]{width:min(1440px,98vw);height:min(860px,94vh);display:flex;flex-direction:column;background:#071426;border:1px solid rgba(0,247,255,.28);border-radius:8px;overflow:hidden;box-shadow:0 20px 60px #00000073}.head[data-v-684cbf61]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid rgba(0,247,255,.16)}.head h3[data-v-684cbf61]{margin:0;font-size:16px;color:#f4feff;letter-spacing:.06em}.hint[data-v-684cbf61]{margin:0;padding:8px 16px;font-size:12px;color:#7eb6d6;background:#00284859}.body[data-v-684cbf61]{flex:1;min-height:0;display:grid;grid-template-columns:280px 1fr}.icon-pane[data-v-684cbf61]{display:flex;flex-direction:column;min-height:0;border-right:1px solid rgba(0,247,255,.14);background:#001024a6}.icon-head[data-v-684cbf61]{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px;font-size:12px;color:#f4feff;border-bottom:1px solid rgba(0,247,255,.12)}.icon-search[data-v-684cbf61]{width:120px;height:28px;border-radius:4px;border:1px solid rgba(0,247,255,.25);background:#00000059;color:#d7f4ff;padding:0 8px;font-size:12px}.icon-err[data-v-684cbf61]{margin:8px 12px 0;font-size:12px;color:#ffb0b0}.icon-grid[data-v-684cbf61]{flex:1;min-height:0;overflow:auto;padding:8px;display:grid;grid-template-columns:1fr 1fr;gap:6px;align-content:start}.icon-item[data-v-684cbf61]{display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 4px;border-radius:6px;border:1px solid rgba(0,247,255,.16);background:#081c3873;color:#9ec9e0;cursor:pointer;font-size:10px}.icon-item img[data-v-684cbf61]{width:36px;height:36px;object-fit:contain}.icon-item span[data-v-684cbf61]{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.icon-item[data-v-684cbf61]:hover{border-color:#00f7ff73}.icon-item.active[data-v-684cbf61]{border-color:#00f7ff;background:#0064a059;color:#fff;box-shadow:0 0 0 1px #00f7ff40 inset}.icon-current[data-v-684cbf61]{display:flex;align-items:center;gap:8px;padding:8px 12px;border-top:1px solid rgba(0,247,255,.12);font-size:11px;color:#7eb6d6}.icon-current img[data-v-684cbf61]{width:22px;height:22px;object-fit:contain}.icon-current b[data-v-684cbf61]{color:#f4feff;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.frame-wrap[data-v-684cbf61]{min-height:0;background:#000}.frame[data-v-684cbf61]{width:100%;height:100%;border:0;display:block}.foot[data-v-684cbf61]{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-top:1px solid rgba(0,247,255,.16)}.coords[data-v-684cbf61]{font-family:var(--digital-font);font-size:13px;color:var(--accent)}.coords.muted[data-v-684cbf61]{color:var(--panel-muted)}.actions[data-v-684cbf61]{display:flex;gap:8px}.mask[data-v-a26cda54]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:330;background:#000814a6;display:grid;place-items:center;padding:24px;pointer-events:auto}.dialog[data-v-a26cda54]{width:min(960px,92vw);background:#071426;border:1px solid rgba(0,247,255,.28);border-radius:8px;overflow:hidden;box-shadow:0 20px 60px #00000073}.head[data-v-a26cda54]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid rgba(0,247,255,.16)}.head h3[data-v-a26cda54]{margin:0;font-size:16px;color:#f4feff}.body[data-v-a26cda54]{padding:12px;min-height:360px;background:#000}.empty[data-v-a26cda54]{min-height:320px;display:grid;place-items:center;color:#b9d6f08c;font-size:13px}.btn[data-v-a26cda54]{border:1px solid rgba(0,247,255,.28);background:transparent;color:#d7f7ff;border-radius:4px;padding:6px 12px;cursor:pointer;font-size:12px}.btn[data-v-a26cda54]:hover{border-color:#00f7ff8c}.cameras-page[data-v-f516d601]{min-height:0}.list-panel[data-v-f516d601]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.head-actions[data-v-f516d601]{display:flex;gap:8px}.create-row[data-v-f516d601]{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;margin-bottom:12px}.create-row .field[data-v-f516d601]{min-width:120px}.table-wrap[data-v-f516d601]{flex:1;min-height:0;overflow:auto}.ops[data-v-f516d601]{white-space:nowrap}.ops .btn[data-v-f516d601]{margin-right:4px}.mono[data-v-f516d601]{font-family:var(--digital-font);font-size:12px}.st[data-v-f516d601]{display:inline-block;padding:1px 6px;border-radius:2px;font-size:11px;margin-right:4px}.st.online[data-v-f516d601]{background:#52c41a26;color:#7dff9a}.st.offline[data-v-f516d601]{background:#8ea3b826;color:#9bb0c4}.st.alarm[data-v-f516d601]{background:#ff4d4f26;color:#ffb0b0}.st.off[data-v-f516d601]{background:#faad141f;color:#ffd666}.empty[data-v-f516d601]{text-align:center;color:var(--panel-muted);padding:24px}.msg.ok[data-v-f516d601]{color:#7dcea0}.msg.err[data-v-f516d601]{color:#ffb0b0}.tip[data-v-f516d601]{margin-top:10px;font-size:12px;color:var(--panel-muted)}
import{d as O,r as y,q as J,j as W,s as G,c as d,w as B,b as e,t as r,e as T,v as S,f as g,F as X,z as Y,g as K,h as V,B as Z,o as a,n as j,_ as L,x as H,T as Q,u as ee,L as te,D as q,N as ne,l as x}from"./index-Bs_x-_cK.js";import{u as se,d as le,r as oe,p as ie,f as ae}from"./useRtengineBridge-zn3rZLWd.js";import{W as ce}from"./WebRtcPlayer-AsPwoXXX.js";const ue={class:"dialog"},de={class:"head"},re={class:"hint"},ve={class:"body"},pe={class:"icon-pane"},me={class:"icon-head"},fe={key:0,class:"icon-err"},ye={class:"icon-grid"},be=["title","onClick"],ke=["src","alt"],ge={class:"icon-current"},he=["src"],_e={class:"frame-wrap"},$e=["src"],Ce={class:"foot"},we={key:0,class:"coords"},Pe={key:1,class:"coords muted"},xe={class:"actions"},Te=["disabled"],Ee=O({__name:"ScenePickDialog",props:{open:{type:Boolean},title:{},initial:{}},emits:["close","save"],setup(_,{emit:v}){var F;const f=_,k=v,i=le(),h=y(null),s=y(f.initial?{...f.initial}:null),p=y(((F=f.initial)==null?void 0:F.icon)||"cctv-blue.png"),m=y([]),C=y(""),P=y(""),$=y("场景加载后,点击地面拾取摄像头位置"),A=["cctv-blue.png","cctv-green.png","cctv-orange.png","cctv-red.png","cctv.png","ai-camera-blue.png","ai-camera-green.png","ai-camera-orange.png","ai-camera-red.png"],M=Z(()=>{const u=P.value.trim().toLowerCase();let l=m.value.slice();return l.sort((c,n)=>{const t=A.indexOf(c),w=A.indexOf(n);return t>=0||w>=0?(t<0?999:t)-(w<0?999:w):c.localeCompare(n)}),u&&(l=l.filter(c=>c.toLowerCase().includes(u))),l}),b=se({iframeRef:h,cloudUrl:i,onMouseClick:({point:u,markerId:l})=>{u&&(s.value={...u,icon:p.value},$.value=l?`已拾取(对象 ${l})`:`已拾取 X=${u.x.toFixed(6)} Y=${u.y.toFixed(6)} Z=${u.z.toFixed(2)}`)},onReady:()=>{$.value="引擎已就绪 · 正在加载预设图标…",b.setPickMode(!0),b.showScenePresets(),E(!0)}});async function E(u=!1){C.value="";try{if(m.value=u?await ie(void 0,i):await ae(i),!m.value.includes(p.value)&&m.value.length){const l=m.value.find(c=>/cctv|camera/i.test(c));p.value=l||m.value[0]}u&&($.value=`已加载 ${m.value.length} 个场景预设图标 · 点击地面拾取`)}catch(l){C.value=l instanceof Error?l.message:"图标列表加载失败"}}J(()=>f.open,u=>{var l;u?(s.value=f.initial?{...f.initial}:null,p.value=((l=f.initial)==null?void 0:l.icon)||"cctv-blue.png",$.value="场景加载后,点击地面拾取摄像头位置",E(),window.setTimeout(()=>b.setPickMode(!0),1500)):b.setPickMode(!1)}),J(p,u=>{s.value&&(s.value={...s.value,icon:u})}),W(()=>{f.open&&(E(),window.setTimeout(()=>b.setPickMode(!0),1500))}),G(()=>b.setPickMode(!1));function N(){if(!s.value){$.value="请先在场景中点击拾取位置";return}k("save",{...s.value,icon:p.value})}function U(){s.value=null,$.value="已清除,请重新点击拾取"}function D(u){return oe(u,i)}return(u,l)=>_.open?(a(),d("div",{key:0,class:"mask",onClick:l[3]||(l[3]=B(c=>k("close"),["self"]))},[e("div",ue,[e("div",de,[e("h3",null,r(_.title||"三维场景打点"),1),e("button",{class:"btn ghost",type:"button",onClick:l[0]||(l[0]=c=>k("close"))},"关闭")]),e("p",re,r($.value),1),e("div",ve,[e("aside",pe,[e("div",me,[l[4]||(l[4]=e("span",null,"引擎图标",-1)),T(e("input",{"onUpdate:modelValue":l[1]||(l[1]=c=>P.value=c),class:"icon-search",placeholder:"筛选…"},null,512),[[S,P.value]])]),C.value?(a(),d("p",fe,r(C.value),1)):g("",!0),e("div",ye,[(a(!0),d(X,null,Y(M.value,c=>(a(),d("button",{key:c,type:"button",class:j(["icon-item",{active:p.value===c}]),title:c,onClick:n=>p.value=c},[e("img",{src:D(c),alt:c,loading:"lazy"},null,8,ke),e("span",null,r(c.replace(/\.png$/i,"")),1)],10,be))),128))]),e("div",ge,[l[5]||(l[5]=K(" 当前: ",-1)),p.value?(a(),d("img",{key:0,src:D(p.value),alt:""},null,8,he)):g("",!0),e("b",null,r(p.value||"—"),1)])]),e("div",_e,[e("iframe",{ref_key:"iframeRef",ref:h,class:"frame",src:V(i),title:"RTEngine pick",allow:"autoplay; fullscreen; microphone; camera; clipboard-read; clipboard-write; display-capture",allowfullscreen:"",referrerpolicy:"no-referrer-when-downgrade"},null,8,$e)])]),e("div",Ce,[s.value?(a(),d("div",we," X "+r(s.value.x.toFixed(6))+" · Y "+r(s.value.y.toFixed(6))+" · Z "+r(s.value.z.toFixed(2)),1)):(a(),d("div",Pe,"尚未拾取")),e("div",xe,[e("button",{class:"btn ghost",type:"button",onClick:U},"清除"),e("button",{class:"btn ghost",type:"button",onClick:l[2]||(l[2]=c=>k("close"))},"取消"),e("button",{class:"btn",type:"button",disabled:!s.value,onClick:N},"保存点位",8,Te)])])])])):g("",!0)}}),Se=L(Ee,[["__scopeId","data-v-684cbf61"]]),Ve={class:"head"},Ae={class:"body"},De={key:1,class:"empty"},Fe=O({__name:"CameraPlayDialog",props:{open:{type:Boolean},deviceId:{},title:{}},emits:["close"],setup(_,{emit:v}){const f=v;return(k,i)=>(a(),H(Q,{to:"body"},[_.open?(a(),d("div",{key:0,class:"mask",onClick:i[2]||(i[2]=B(h=>f("close"),["self"]))},[e("div",{class:"dialog",onClick:i[1]||(i[1]=B(()=>{},["stop"]))},[e("div",Ve,[e("h3",null,r(_.title||"视频预览"),1),e("button",{class:"btn ghost",type:"button",onClick:i[0]||(i[0]=h=>f("close"))},"关闭")]),e("div",Ae,[_.deviceId?(a(),H(ce,{key:0,"device-id":_.deviceId},null,8,["device-id"])):(a(),d("div",De,"未绑定视频设备"))])])])):g("",!0)]))}}),Ie=L(Fe,[["__scopeId","data-v-a26cda54"]]),Re={class:"page-fill cameras-page"},Me={class:"panel list-panel"},Ne={class:"panel-head"},Ue={class:"panel-title"},Be={class:"badge"},Oe={class:"head-actions"},Le=["disabled"],ze={key:0,class:"msg ok"},Je={key:1,class:"msg err"},He={key:2,class:"create-row"},qe={class:"field"},We={class:"field"},Xe={class:"field"},Ye={class:"field"},Ze={class:"field"},je={class:"table-wrap"},Ge={class:"table"},Ke={key:0},Qe={key:0,class:"st off"},et={class:"mono"},tt={key:0,class:"ops"},nt=["onClick"],st=["onClick"],lt=["onClick"],ot=["onClick"],it=["onClick"],at={key:0},ct=["colspan"],ut=O({__name:"CamerasView",setup(_){const v=ee(),f=y(!1),k=y(""),i=y(""),h=y([]),s=ne({name:"",channel:1,location:"",deviceType:"nvr-ch",ip:"",remark:""}),p=y(!1),m=y(null),C=y(!1),P=y(null),$={online:"在线",offline:"离线",alarm:"报警"},A={ipc:"网络摄像机","nvr-ch":"NVR 通道"},M=Z(()=>h.value.filter(n=>n.scenePoint).length);async function b(){f.value=!0,i.value="";try{const n=await x("/api/video/devices",{token:v.token});h.value=n.devices;const t=h.value.reduce((w,I)=>Math.max(w,I.channel),0);s.channel=t+1}catch(n){i.value=n instanceof Error?n.message:"加载失败"}finally{f.value=!1}}async function E(){if(v.isAdmin){k.value="",i.value="";try{await x("/api/video/devices",{method:"POST",token:v.token,body:JSON.stringify({...s})}),k.value="已新增摄像头",s.name="",s.location="",s.ip="",s.remark="",await b()}catch(n){i.value=n instanceof Error?n.message:"创建失败"}}}async function N(n){if(v.isAdmin)try{await x(`/api/video/devices/${n.id}`,{method:"PATCH",token:v.token,body:JSON.stringify({enabled:!n.enabled})}),await b()}catch(t){i.value=t instanceof Error?t.message:"更新失败"}}async function U(n){if(v.isAdmin&&confirm(`确定删除摄像头「${n.name}」?`))try{await x(`/api/video/devices/${n.id}`,{method:"DELETE",token:v.token}),k.value="已删除",await b()}catch(t){i.value=t instanceof Error?t.message:"删除失败"}}function D(n){m.value=n,p.value=!0}async function F(n){if(m.value)try{await x(`/api/video/devices/${m.value.id}`,{method:"PATCH",token:v.token,body:JSON.stringify({scenePoint:n})}),k.value=`已保存「${m.value.name}」三维点位`,p.value=!1,m.value=null,await b()}catch(t){i.value=t instanceof Error?t.message:"保存点位失败"}}async function u(n){if(v.isAdmin)try{await x(`/api/video/devices/${n.id}`,{method:"PATCH",token:v.token,body:JSON.stringify({scenePoint:null})}),k.value=`已清除「${n.name}」点位`,await b()}catch(t){i.value=t instanceof Error?t.message:"清除失败"}}function l(n){P.value=n,C.value=!0}function c(n){if(!n)return"—";const t=n.icon?` · ${n.icon}`:"";return`${n.x.toFixed(5)}, ${n.y.toFixed(5)}, ${n.z.toFixed(1)}${t}`}return W(b),(n,t)=>{var w,I,z;return a(),d("div",Re,[e("section",Me,[e("div",Ne,[e("div",Ue,[t[7]||(t[7]=e("div",{class:"vbar"},null,-1)),t[8]||(t[8]=e("h3",null,"摄像头管理",-1)),e("div",Be,"已打点 "+r(M.value)+"/"+r(h.value.length),1)]),e("div",Oe,[e("button",{class:"btn ghost",type:"button",disabled:f.value,onClick:b},"刷新",8,Le)])]),k.value?(a(),d("p",ze,r(k.value),1)):g("",!0),i.value?(a(),d("p",Je,r(i.value),1)):g("",!0),V(v).isAdmin?(a(),d("div",He,[e("div",qe,[t[9]||(t[9]=e("label",null,"名称",-1)),T(e("input",{"onUpdate:modelValue":t[0]||(t[0]=o=>s.name=o),placeholder:"如:走廊东"},null,512),[[S,s.name]])]),e("div",We,[t[10]||(t[10]=e("label",null,"通道",-1)),T(e("input",{"onUpdate:modelValue":t[1]||(t[1]=o=>s.channel=o),type:"number",min:"1",max:"256"},null,512),[[S,s.channel,void 0,{number:!0}]])]),e("div",Xe,[t[11]||(t[11]=e("label",null,"安装位置",-1)),T(e("input",{"onUpdate:modelValue":t[2]||(t[2]=o=>s.location=o),placeholder:"楼层/区域"},null,512),[[S,s.location]])]),e("div",Ye,[t[13]||(t[13]=e("label",null,"类型",-1)),T(e("select",{"onUpdate:modelValue":t[3]||(t[3]=o=>s.deviceType=o)},[...t[12]||(t[12]=[e("option",{value:"nvr-ch"},"NVR 通道",-1),e("option",{value:"ipc"},"网络摄像机",-1)])],512),[[te,s.deviceType]])]),e("div",Ze,[t[14]||(t[14]=e("label",null,"IP(可选)",-1)),T(e("input",{"onUpdate:modelValue":t[4]||(t[4]=o=>s.ip=o)},null,512),[[S,s.ip]])]),e("button",{class:"btn",type:"button",onClick:E},"新增摄像头")])):g("",!0),e("div",je,[e("table",Ge,[e("thead",null,[e("tr",null,[t[15]||(t[15]=e("th",null,"名称",-1)),t[16]||(t[16]=e("th",null,"通道",-1)),t[17]||(t[17]=e("th",null,"位置",-1)),t[18]||(t[18]=e("th",null,"类型",-1)),t[19]||(t[19]=e("th",null,"状态",-1)),t[20]||(t[20]=e("th",null,"三维点位",-1)),V(v).isAdmin?(a(),d("th",Ke,"操作")):g("",!0)])]),e("tbody",null,[(a(!0),d(X,null,Y(h.value,o=>(a(),d("tr",{key:o.id},[e("td",null,r(o.name),1),e("td",null,r(o.channel),1),e("td",null,r(o.location),1),e("td",null,r(A[o.deviceType]),1),e("td",null,[e("span",{class:j(["st",o.status])},r($[o.status]),3),o.enabled?g("",!0):(a(),d("span",Qe,"停用"))]),e("td",et,r(c(o.scenePoint)),1),V(v).isAdmin?(a(),d("td",tt,[e("button",{class:"btn ghost",type:"button",onClick:R=>D(o)},"三维打点",8,nt),o.scenePoint?(a(),d("button",{key:0,class:"btn ghost",type:"button",onClick:R=>u(o)}," 清点 ",8,st)):g("",!0),e("button",{class:"btn ghost",type:"button",onClick:R=>l(o)},"预览",8,lt),e("button",{class:"btn ghost",type:"button",onClick:R=>N(o)},r(o.enabled?"停用":"启用"),9,ot),e("button",{class:"btn ghost",type:"button",onClick:R=>U(o)},"删",8,it)])):g("",!0)]))),128)),h.value.length?g("",!0):(a(),d("tr",at,[e("td",{colspan:V(v).isAdmin?7:6,class:"empty"},"暂无摄像头",8,ct)]))])])]),t[21]||(t[21]=e("p",{class:"tip"}," 三维打点:打开 RTEngine 场景后点击地面拾取坐标并保存;大屏加载后自动显示摄像头标记,点击标记可播放视频。 ",-1))]),q(Se,{open:p.value,title:m.value?`打点 · ${m.value.name}`:"三维打点",initial:((w=m.value)==null?void 0:w.scenePoint)||null,onClose:t[5]||(t[5]=o=>p.value=!1),onSave:F},null,8,["open","title","initial"]),q(Ie,{open:C.value,"device-id":((I=P.value)==null?void 0:I.id)||"",title:(z=P.value)==null?void 0:z.name,onClose:t[6]||(t[6]=o=>C.value=!1)},null,8,["open","device-id","title"])])}}}),pt=L(ut,[["__scopeId","data-v-f516d601"]]);export{pt as default};
import{d as E,j as k,l as B,C,c as d,b as e,t as a,h as t,H as _,F as S,x as H,r as c,s as v,E as I,o as r,p as y,_ as T}from"./index-BssDqbym.js";import{E as g,m as f}from"./historyChart-DJ1B6lTP.js";import{u as V}from"./realtime-lmP-Cubp.js";const F={class:"page-fill cold-page"},L={class:"panel",style:{flex:"1","min-height":"0",display:"flex","flex-direction":"column",gap:"10px"}},M={class:"panel-head"},O={class:"panel-title"},R={class:"badge"},N={class:"charts"},j={class:"chart-card"},z={class:"chart-title"},D={class:"chart-card"},P={class:"chart-title"},U={class:"table"},q=E({__name:"ColdView",setup(A){const{t:s}=k(),x=V(),u=c([]),m=c([]),l=c(!1);let n;const b=v(()=>f(u.value,{unit:"℃",maxSeries:12})),w=v(()=>f(m.value,{unit:"%",maxSeries:12}));async function p(){l.value=!0;try{const[h,i]=await Promise.all([y("/api/realtime/history?source=fridge&metric=temp&hours=24&bucketMinutes=60"),y("/api/realtime/history?source=fridge&metric=humidity&hours=24&bucketMinutes=60")]);u.value=h.series||[],m.value=i.series||[]}finally{l.value=!1}}return B(()=>{p(),n=window.setInterval(()=>void p(),6e4)}),C(()=>{n&&window.clearInterval(n)}),(h,i)=>(r(),d("div",F,[e("section",L,[e("div",M,[e("div",O,[i[0]||(i[0]=e("div",{class:"vbar"},null,-1)),e("h3",null,a(t(s)("pages.coldTitle")),1)]),e("div",R,a(t(s)("pages.coldBadge")),1)]),e("div",N,[e("div",j,[e("div",z,a(t(s)("pages.coldTemp")),1),_(g,{option:b.value,loading:l.value,"empty-text":t(s)("pages.coldTempEmpty")},null,8,["option","loading","empty-text"])]),e("div",D,[e("div",P,a(t(s)("pages.coldHumidity")),1),_(g,{option:w.value,loading:l.value,"empty-text":t(s)("pages.coldHumidityEmpty")},null,8,["option","loading","empty-text"])])]),e("table",U,[e("thead",null,[e("tr",null,[e("th",null,a(t(s)("common.device")),1),e("th",null,a(t(s)("pages.colTemp")),1),e("th",null,a(t(s)("pages.colHumidity")),1),e("th",null,a(t(s)("screen.status")),1)])]),e("tbody",null,[(r(!0),d(S,null,H(t(x).snapshot.fridges,o=>(r(),d("tr",{key:o.id},[e("td",null,a(o.name),1),e("td",{style:I({color:o.temp>-19?"var(--amber)":"var(--green)"})},a(o.temp.toFixed(1))+" ℃ ",5),e("td",null,a(o.humidity)+" %",1),e("td",null,a(o.temp>-19?t(s)("status.overLimit"):t(s)("common.normal")),1)]))),128))])])])]))}}),Q=T(q,[["__scopeId","data-v-5562f3c6"]]);export{Q as default};
.cold-page[data-v-8bd876a6]{display:flex;min-height:0}.charts[data-v-8bd876a6]{display:grid;grid-template-columns:1fr 1fr;gap:10px;min-height:260px;flex:1}.chart-card[data-v-8bd876a6]{min-height:0;display:flex;flex-direction:column;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-8bd876a6]{font-size:12px;color:var(--label);margin-bottom:4px}.chart-card[data-v-8bd876a6] .echart-wrap{flex:1;min-height:200px}
import{d as b,j as w,s as k,c as o,b as t,D as p,F as B,z as S,h as C,r as n,B as v,o as r,t as a,y as E,l as h,_ as V}from"./index-Bs_x-_cK.js";import{E as y,m as f}from"./historyChart-DTdcyadg.js";import{u as F}from"./realtime-CI_KLy_N.js";const I={class:"page-fill cold-page"},M={class:"panel",style:{flex:"1","min-height":"0",display:"flex","flex-direction":"column",gap:"10px"}},O={class:"charts"},z={class:"chart-card"},D={class:"chart-card"},L={class:"table"},N=b({__name:"ColdView",setup(R){const _=F(),d=n([]),u=n([]),l=n(!1);let i;const g=v(()=>f(d.value,{unit:"℃",maxSeries:12})),x=v(()=>f(u.value,{unit:"%",maxSeries:12}));async function c(){l.value=!0;try{const[m,e]=await Promise.all([h("/api/realtime/history?source=fridge&metric=temp&hours=24&bucketMinutes=15"),h("/api/realtime/history?source=fridge&metric=humidity&hours=24&bucketMinutes=15")]);d.value=m.series||[],u.value=e.series||[]}finally{l.value=!1}}return w(()=>{c(),i=window.setInterval(()=>void c(),6e4)}),k(()=>{i&&window.clearInterval(i)}),(m,e)=>(r(),o("div",I,[t("section",M,[e[3]||(e[3]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"冷链监测 · 历史曲线")]),t("div",{class:"badge"},"E栋 · 近 24h")],-1)),t("div",O,[t("div",z,[e[0]||(e[0]=t("div",{class:"chart-title"},"温度 ℃",-1)),p(y,{option:g.value,loading:l.value,"empty-text":"温度历史积累中"},null,8,["option","loading"])]),t("div",D,[e[1]||(e[1]=t("div",{class:"chart-title"},"湿度 %RH",-1)),p(y,{option:x.value,loading:l.value,"empty-text":"湿度历史积累中"},null,8,["option","loading"])])]),t("table",L,[e[2]||(e[2]=t("thead",null,[t("tr",null,[t("th",null,"设备"),t("th",null,"温度 (℃)"),t("th",null,"湿度 (%)"),t("th",null,"状态")])],-1)),t("tbody",null,[(r(!0),o(B,null,S(C(_).snapshot.fridges,s=>(r(),o("tr",{key:s.id},[t("td",null,a(s.name),1),t("td",{style:E({color:s.temp>-19?"var(--amber)":"var(--green)"})},a(s.temp.toFixed(1))+" ℃ ",5),t("td",null,a(s.humidity)+" %",1),t("td",null,a(s.temp>-19?"超限":"正常"),1)]))),128))])])])]))}}),U=V(N,[["__scopeId","data-v-8bd876a6"]]);export{U as default};
.cold-page[data-v-5562f3c6]{display:flex;min-height:0}.charts[data-v-5562f3c6]{display:grid;grid-template-columns:1fr 1fr;gap:10px;min-height:260px;flex:1}.chart-card[data-v-5562f3c6]{min-height:0;display:flex;flex-direction:column;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-5562f3c6]{font-size:12px;color:var(--label);margin-bottom:4px}.chart-card[data-v-5562f3c6] .echart-wrap{flex:1;min-height:200px}
.devices-page[data-v-a043261c]{min-height:0}.list-panel[data-v-a043261c]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;gap:10px}.panel-title[data-v-a043261c]{gap:10px}.head-actions[data-v-a043261c]{display:flex;flex-wrap:wrap;align-items:center;gap:8px;justify-content:flex-end}.tab-row[data-v-a043261c],.filters[data-v-a043261c]{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}.field[data-v-a043261c]{display:flex;flex-direction:column;gap:4px;min-width:140px}.field label[data-v-a043261c]{font-size:12px;opacity:.75}.field input[data-v-a043261c],.field select[data-v-a043261c],.csv-area[data-v-a043261c]{background:#060c14a6;box-shadow:0 0 0 1px #3dbeff47 inset;border:none;color:inherit;border-radius:2px;padding:6px 8px}.csv-area[data-v-a043261c]{width:100%;min-height:160px;margin-top:4px;font-family:var(--digital-font),ui-monospace,monospace;font-size:12px}.filter-hint[data-v-a043261c]{font-size:12px;color:var(--panel-muted);margin-bottom:6px}.check[data-v-a043261c]{display:flex;align-items:center;gap:6px;font-size:13px;margin-bottom:4px}.table-wrap[data-v-a043261c]{flex:1;min-height:0;overflow:auto}.msg.ok[data-v-a043261c]{color:var(--ok);font-size:13px}.msg.err[data-v-a043261c]{color:#ffb0b0;font-size:13px}.hint[data-v-a043261c]{font-size:12px;opacity:.7;margin-top:10px}.mono[data-v-a043261c]{font-family:var(--digital-font),ui-monospace,monospace;font-size:11px;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ops[data-v-a043261c]{display:flex;gap:6px}.row-click[data-v-a043261c]{cursor:pointer}.row-click:hover td[data-v-a043261c]{background:#3dbeff1f}.device-meta[data-v-a043261c]{display:flex;flex-wrap:wrap;gap:10px 16px;margin-bottom:12px}.device-meta span[data-v-a043261c]{display:inline-flex;align-items:baseline;gap:6px;padding:4px 8px;border:1px solid var(--panel-border);border-radius:2px;background:#060c1473}.device-meta small[data-v-a043261c]{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--panel-muted)}.device-meta b[data-v-a043261c]{font-size:12px;font-weight:600;color:var(--panel-title)}.detail-table-wrap[data-v-a043261c]{max-height:min(68vh,720px);overflow:auto}.eng[data-v-a043261c]{font-family:var(--digital-font),ui-monospace,monospace;font-size:14px;font-weight:700;color:var(--accent)}.eng.muted[data-v-a043261c]{color:var(--panel-muted);font-weight:600}.ts[data-v-a043261c]{font-size:11px;color:var(--panel-muted)}.empty[data-v-a043261c]{text-align:center;color:var(--panel-muted);padding:28px 10px!important}.gw-strip[data-v-a043261c]{margin:0 0 10px;padding:10px 12px;border:1px solid var(--panel-border);border-radius:4px;background:#06101c73}.gw-strip-title[data-v-a043261c]{font-size:12px;color:var(--panel-muted);margin-bottom:8px}.gw-chips[data-v-a043261c]{display:flex;flex-wrap:wrap;gap:8px}.gw-chip[data-v-a043261c]{display:inline-flex;align-items:center;gap:8px;padding:6px 10px;border-radius:4px;border:1px solid rgba(0,247,255,.2);background:#00284859;font-size:12px;color:#cfe8f6}.gw-chip b[data-v-a043261c]{font-weight:600;color:#eaf4ff}.gw-chip i[data-v-a043261c]{font-style:normal;font-size:11px}.gw-chip i.on[data-v-a043261c]{color:var(--ok, #4dffb5)}.gw-chip i.off[data-v-a043261c]{color:#ffb0b0}.gw-hint[data-v-a043261c]{margin:8px 0 0}.modal-mask[data-v-a043261c]{position:fixed;top:0;right:0;bottom:0;left:0;background:#04080eb8;display:flex;align-items:center;justify-content:center;z-index:50}.modal[data-v-a043261c]{width:min(640px,92vw);max-height:90vh;overflow:auto}.modal-lg[data-v-a043261c]{width:min(860px,96vw)}.modal-xl[data-v-a043261c]{width:min(1280px,98vw);max-height:92vh}.modal-actions[data-v-a043261c]{margin-top:14px;display:flex;gap:10px}.form-grid[data-v-a043261c]{display:grid;grid-template-columns:1fr 1fr;gap:10px}.write-cell[data-v-a043261c]{display:inline-flex;align-items:center;gap:6px;min-width:140px;white-space:nowrap}.ops[data-v-a043261c]{white-space:nowrap}.ops .btn[data-v-a043261c]{margin-right:4px}.write-input[data-v-a043261c]{width:88px;padding:4px 6px;border-radius:6px;border:1px solid rgba(255,255,255,.12);background:#00000040;color:inherit}.bool-on[data-v-a043261c],.bool-off[data-v-a043261c]{min-width:44px;padding:4px 10px}.muted[data-v-a043261c]{color:var(--panel-muted)}.msg.ok[data-v-a043261c]{color:#7dcea0}
import{d as _e,u as Ue,l as Ae,m as Se,c as n,b as e,t as a,n as j,h as V,f as r,F as $,x as T,e as v,P as L,w as N,Q as re,g as ve,v as c,a as $e,r as w,R as Y,s as oe,p as S,a1 as me,o,_ as De}from"./index-BssDqbym.js";const Te={class:"page-fill devices-page"},Ne={class:"panel list-panel"},Oe={class:"panel-head"},Le={class:"panel-title"},Pe={class:"badge"},Ee={class:"head-actions"},He=["disabled"],xe={class:"gw-strip"},Re={class:"gw-strip-title"},Fe={class:"gw-chips"},Me=["title"],Ge={class:"mono"},Be={key:0,class:"muted"},Ke={class:"tab-row"},We={key:0,class:"filters"},Je={class:"field"},je=["value"],ze={class:"field"},qe=["value"],Qe={class:"filter-hint"},Xe={key:1,class:"msg ok"},Ye={key:2,class:"msg err"},Ze={class:"table-wrap"},et={key:0,class:"table"},tt=["onClick"],lt={class:"mono"},st={class:"mono"},nt={key:0},at={key:1,class:"table"},ot={key:0},it={key:1},ut={class:"mono"},dt={key:0},rt={key:0,class:"write-cell"},vt=["disabled","onClick"],mt=["disabled","onClick"],bt={key:1,class:"write-cell"},pt=["value","disabled","onInput","onKeydown"],ct=["disabled","onClick"],yt={key:2,class:"muted"},ft={key:1,class:"ops"},gt=["onClick"],kt=["onClick"],wt={key:0},It=["colspan"],Ct={class:"modal panel modal-xl"},ht={class:"panel-head"},Vt={class:"panel-title"},_t={class:"badge"},Ut={class:"device-meta"},At={class:"mono"},St={key:0},$t={class:"mono"},Dt={key:0,class:"msg err"},Tt={key:1,class:"msg ok"},Nt={class:"detail-table-wrap"},Ot={class:"table"},Lt={key:0},Pt={key:1},Et={class:"mono ts"},Ht={key:0},xt={key:0,class:"write-cell"},Rt=["disabled","onClick"],Ft=["disabled","onClick"],Mt={key:1,class:"write-cell"},Gt=["value","disabled","onInput","onKeydown"],Bt=["disabled","onClick"],Kt={key:2,class:"muted"},Wt={key:1,class:"ops"},Jt=["onClick"],jt={key:0},zt=["colspan"],qt={class:"modal panel modal-lg"},Qt={class:"filters"},Xt={class:"field"},Yt=["value"],Zt={class:"field"},el={class:"check"},tl={key:0,class:"msg err"},ll={class:"modal-actions"},sl=["disabled"],nl={class:"modal panel"},al={class:"form-grid"},ol={class:"field"},il={class:"field"},ul={class:"field"},dl={class:"field"},rl=["value"],vl={class:"field"},ml={key:0,class:"msg err"},bl={class:"modal-actions"},pl=["disabled"],cl={class:"modal panel"},yl={class:"form-grid"},fl={class:"field"},gl={class:"field"},kl=["value"],wl={class:"field"},Il={class:"field"},Cl={class:"field"},hl={class:"field"},Vl={class:"field"},_l=["value"],Ul={class:"field"},Al={class:"field"},Sl={class:"field"},$l={key:0,class:"msg err"},Dl={class:"modal-actions"},Tl=["disabled"],Nl={class:"modal panel"},Ol={class:"form-grid"},Ll={class:"field"},Pl={class:"field"},El={class:"field"},Hl={class:"field"},xl={class:"field"},Rl={class:"field"},Fl={class:"field"},Ml={class:"field"},Gl={class:"field"},Bl={class:"field"},Kl=["value"],Wl={class:"check"},Jl={key:0,class:"msg err"},jl={class:"modal-actions"},zl=["disabled"],ql=_e({__name:"DevicesView",setup(Ql){function ie(s){const t=s.rw||"r";return t==="w"?"写控":t==="rw"?"读写":"采集"}function B(s){const t=s.rw||"r";return t==="w"||t==="rw"}function Z(s){const t=(s.dataType||"").toLowerCase(),b=(s.regType||"").toUpperCase();return!!(/bool|bit|coil/.test(t)||b.includes("-F5")||/\b0X\b/.test(b)||b.includes("COIL"))}const m=Ue(),D=w("devices"),C=w(null),ee=w(!1),I=w(!1),_=w(""),d=w(""),U=w([]),P=w([]),M=w([]),K=w(1),G=w(null),h=w(null),R=w(!1),W=Y({}),A=w(null);let z;const E=w(""),J=w(""),y=Y({gatewayId:"mb-104",encoding:"gbk",replaceGateway:!0,csv:""}),p=Y({name:"",code:"",category:"other",gatewayId:"",bindUi:""}),u=Y({name:"",gatewayId:"mb-104",deviceId:null,modbusAddress:0,dataType:"Short",modbusId:1,itemId:"",scale:0,scaleOverride:.1,alarmLow:null,alarmHigh:null,enabled:!0}),i=w(null),te=oe(()=>M.value.filter(s=>!(E.value&&s.gatewayId!==E.value||J.value&&s.deviceId!==J.value))),be=oe(()=>P.value.map(s=>({...s,pointCount:M.value.filter(t=>t.deviceId===s.id).length}))),le=oe(()=>h.value?M.value.filter(s=>s.deviceId===h.value.id).sort((s,t)=>s.modbusAddress-t.modbusAddress||s.name.localeCompare(t.name,"zh")):[]);function q(){_.value="",d.value=""}function pe(s){return s==null||Number.isNaN(s)?"—":Number.isInteger(s)?String(s):s.toFixed(2)}function ce(s){if(!s)return"—";try{return new Date(s).toLocaleString("zh-CN",{hour12:!1})}catch{return s}}function Q(){z!==void 0&&(window.clearInterval(z),z=void 0)}async function X(){try{const s=await S("/api/devices/points",{token:m.token});M.value=s.points,K.value=s.pointsVersion}catch{}}function se(){Q(),X(),z=window.setInterval(()=>{X()},3e3)}function ye(s){q(),h.value=s,R.value=!1,C.value="viewDevice",se()}function ne(s){var t,b;q(),s==="import"&&(!y.gatewayId&&U.value[0]&&(y.gatewayId=U.value[0].id),y.csv=""),s==="createDevice"&&(p.name="",p.code="",p.category="other",p.gatewayId=((t=U.value[0])==null?void 0:t.id)||null,p.bindUi=""),s==="createPoint"&&(u.name="",u.gatewayId=E.value||((b=U.value[0])==null?void 0:b.id)||"mb-104",u.deviceId=J.value||null,u.modbusAddress=0,u.dataType="Short",u.modbusId=1,u.itemId="",u.scale=0,u.scaleOverride=.1,u.alarmLow=null,u.alarmHigh=null,u.enabled=!0),C.value=s}function f(){if(C.value==="editPoint"&&R.value&&h.value){i.value=null,d.value="",R.value=!1,C.value="viewDevice",se();return}Q(),C.value=null,i.value=null,h.value=null,R.value=!1,d.value=""}function ue(s){q(),R.value=C.value==="viewDevice",Q(),i.value={...s},C.value="editPoint"}async function H(){ee.value=!0,d.value="";try{const[s,t,b,g]=await Promise.allSettled([S("/api/devices/gateways",{token:m.token}),S("/api/devices",{token:m.token}),S("/api/devices/points",{token:m.token}),S("/api/devices/gateways/health",{token:m.token})]);s.status==="fulfilled"&&(U.value=s.value.gateways,!y.gatewayId&&s.value.gateways[0]&&(y.gatewayId=s.value.gateways[0].id),s.value.pointsVersion&&(K.value=s.value.pointsVersion)),t.status==="fulfilled"&&(P.value=t.value.devices),b.status==="fulfilled"&&(M.value=b.value.points,K.value=b.value.pointsVersion||K.value),g.status==="fulfilled"?G.value=g.value:G.value={ok:!1,message:"Windows 网关未连接(不影响本地设备列表)"};const F=[s,t,b].filter(O=>O.status==="rejected");if(F.length===3){const O=F[0].reason;d.value=O instanceof Error?O.message:"加载失败"}else if(t.status==="rejected"){const O=t.reason;d.value=O instanceof Error?O.message:"设备列表加载失败"}}catch(s){d.value=s instanceof Error?s.message:"加载失败"}finally{ee.value=!1}}async function fe(){if(i.value){d.value="",I.value=!0;try{await S(`/api/devices/points/${i.value.id}`,{method:"PATCH",token:m.token,body:JSON.stringify({name:i.value.name,modbusAddress:Number(i.value.modbusAddress),dataType:i.value.dataType,modbusId:Number(i.value.modbusId),itemId:i.value.itemId,scale:Number(i.value.scale),scaleOverride:i.value.scaleOverride===null||i.value.scaleOverride===""?null:Number(i.value.scaleOverride),alarmLow:i.value.alarmLow===null||i.value.alarmLow===""?null:Number(i.value.alarmLow),alarmHigh:i.value.alarmHigh===null||i.value.alarmHigh===""?null:Number(i.value.alarmHigh),deviceId:i.value.deviceId||null,enabled:i.value.enabled})}),_.value="点位已保存",i.value=null,d.value="",R.value&&h.value?(R.value=!1,C.value="viewDevice",await H(),se()):(f(),await H())}catch(s){d.value=s instanceof Error?s.message:"保存失败"}finally{I.value=!1}}}async function ge(){if(d.value="",!u.name.trim()){d.value="请填写点位名称";return}I.value=!0;try{await S("/api/devices/points",{method:"POST",token:m.token,body:JSON.stringify({name:u.name,gatewayId:u.gatewayId,deviceId:u.deviceId,modbusAddress:Number(u.modbusAddress),dataType:u.dataType,modbusId:Number(u.modbusId),itemId:u.itemId||void 0,scale:Number(u.scale),scaleOverride:u.scaleOverride,alarmLow:u.alarmLow,alarmHigh:u.alarmHigh,enabled:u.enabled})}),_.value="点位已创建",f(),D.value="points",await H()}catch(s){d.value=s instanceof Error?s.message:"创建失败"}finally{I.value=!1}}async function ke(){if(d.value="",!p.name.trim()||!p.code.trim()){d.value="名称与编码必填";return}I.value=!0;try{await S("/api/devices",{method:"POST",token:m.token,body:JSON.stringify({name:p.name,code:p.code,category:p.category,gatewayId:p.gatewayId,bindUi:p.bindUi})}),_.value="设备已创建",f(),D.value="devices",await H()}catch(s){d.value=s instanceof Error?s.message:"创建失败"}finally{I.value=!1}}async function we(s){confirm(`删除点位「${s.name}」?`)&&(await S(`/api/devices/points/${s.id}`,{method:"DELETE",token:m.token}),_.value="点位已删除",await H())}async function Ie(){if(d.value="",!y.csv.trim()){d.value="请粘贴 CSV 内容";return}I.value=!0;try{const s=await S("/api/devices/points/import",{method:"POST",token:m.token,body:JSON.stringify({gatewayId:y.gatewayId,encoding:y.encoding==="utf-8"?"utf-8":"gbk",replaceGateway:y.replaceGateway,csv:y.csv})});_.value=`已导入 ${s.imported} 个点位,版本 ${s.pointsVersion}`,E.value=y.gatewayId,f(),D.value="points",await H()}catch(s){d.value=s instanceof Error?s.message:"导入失败"}finally{I.value=!1}}async function Ce(){const s=new URLSearchParams;E.value&&s.set("gatewayId",E.value),s.set("encoding","utf-8");const t=await fetch(`/api/devices/points/export?${s.toString()}`,{headers:{Authorization:`Bearer ${m.token}`}});if(!t.ok){d.value="导出失败";return}const b=await t.blob(),g=document.createElement("a");g.href=URL.createObjectURL(b),g.download="device-points.csv",g.click(),URL.revokeObjectURL(g.href),_.value="CSV 已导出"}async function he(){q();try{const s=await S("/api/devices/points/sync-gateway",{method:"POST",token:m.token});s.ok?_.value=s.message:d.value=s.message,G.value=await S("/api/devices/gateways/health",{token:m.token})}catch(s){d.value=s instanceof Error?s.message:"同步失败"}}function ae(s){return W[s.id]!==void 0?W[s.id]:s.lastEng!==null&&s.lastEng!==void 0?String(s.lastEng):""}async function x(s,t){if(!m.isAdmin||!B(s))return;let b;if(t!==void 0)b=t;else{const g=ae(s).trim();if(b=Number(g),!Number.isFinite(b)){d.value=`请为「${s.name}」填写有效数值`;return}}A.value=s.id,d.value="";try{const g=await S(`/api/devices/points/${s.id}/write`,{method:"POST",token:m.token,body:JSON.stringify({value:b})}),F=Z(s)?b?"开":"关":String(b);_.value=`已写入 ${s.name} = ${F}${g.message?`(${g.message})`:""}`,W[s.id]=String(b),await X()}catch(g){d.value=g instanceof Error?g.message:"写入失败"}finally{A.value=null}}function de(s){var t;return((t=U.value.find(b=>b.id===s))==null?void 0:t.name)||s}function Ve(s){var t;return s?((t=P.value.find(b=>b.id===s))==null?void 0:t.name)||s:"—"}return Ae(H),Se(Q),(s,t)=>{var b,g,F,O;return o(),n("div",Te,[e("section",Ne,[e("div",Oe,[e("div",Le,[t[37]||(t[37]=e("div",{class:"vbar"},null,-1)),t[38]||(t[38]=e("h3",null,"数据采集",-1)),e("div",Pe,"点表 v"+a(K.value),1),e("span",{class:j(["badge",(b=G.value)!=null&&b.ok?"":"amber"])}," Windows 网关 "+a((g=G.value)!=null&&g.ok?"在线":((F=G.value)==null?void 0:F.message)||"未连接"),3)]),e("div",Ee,[e("button",{class:"btn ghost",type:"button",disabled:ee.value,onClick:H},"刷新",8,He),V(m).isAdmin?(o(),n("button",{key:0,class:"btn ghost",type:"button",onClick:he}," 下发网关 ")):r("",!0),D.value==="devices"&&V(m).isAdmin?(o(),n("button",{key:1,class:"btn",type:"button",onClick:t[0]||(t[0]=l=>ne("createDevice"))},"新增设备")):r("",!0),D.value==="points"?(o(),n($,{key:2},[e("button",{class:"btn ghost",type:"button",onClick:Ce},"导出 CSV"),V(m).isAdmin?(o(),n("button",{key:0,class:"btn ghost",type:"button",onClick:t[1]||(t[1]=l=>ne("import"))}," 导入 CSV ")):r("",!0),V(m).isAdmin?(o(),n("button",{key:1,class:"btn",type:"button",onClick:t[2]||(t[2]=l=>ne("createPoint"))}," 新增点位 ")):r("",!0)],64)):r("",!0)])]),e("div",xe,[e("div",Re,"采集网关("+a(U.value.length)+")",1),e("div",Fe,[(o(!0),n($,null,T(U.value,l=>(o(),n("span",{key:l.id,class:"gw-chip",title:`${l.id} · ${l.host}:${l.port}`},[e("b",null,a(l.name),1),e("span",Ge,a(l.host)+":"+a(l.port),1),e("i",{class:j(l.enabled?"on":"off")},a(l.enabled?"启用":"停用"),3)],8,Me))),128)),U.value.length?r("",!0):(o(),n("span",Be,"暂无网关主机"))]),t[39]||(t[39]=e("p",{class:"hint gw-hint"}," 由 Windows 网关连接上述主机采集;本页维护设备、点位并下发。 ",-1))]),e("div",Ke,[e("button",{class:j(["btn",{ghost:D.value!=="devices"}]),type:"button",onClick:t[3]||(t[3]=l=>D.value="devices")}," 设备("+a(P.value.length)+") ",3),e("button",{class:j(["btn",{ghost:D.value!=="points"}]),type:"button",onClick:t[4]||(t[4]=l=>D.value="points")}," 点位("+a(M.value.length)+") ",3)]),D.value==="points"?(o(),n("div",We,[e("div",Je,[t[41]||(t[41]=e("label",null,"网关",-1)),v(e("select",{"onUpdate:modelValue":t[5]||(t[5]=l=>E.value=l)},[t[40]||(t[40]=e("option",{value:""},"全部",-1)),(o(!0),n($,null,T(U.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,je))),128))],512),[[L,E.value]])]),e("div",ze,[t[43]||(t[43]=e("label",null,"设备",-1)),v(e("select",{"onUpdate:modelValue":t[6]||(t[6]=l=>J.value=l)},[t[42]||(t[42]=e("option",{value:""},"全部",-1)),(o(!0),n($,null,T(P.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,qe))),128))],512),[[L,J.value]])]),e("span",Qe,"当前 "+a(te.value.length)+" 条",1)])):r("",!0),_.value?(o(),n("p",Xe,a(_.value),1)):r("",!0),d.value&&!C.value?(o(),n("p",Ye,a(d.value),1)):r("",!0),e("div",Ze,[D.value==="devices"?(o(),n("table",et,[t[45]||(t[45]=e("thead",null,[e("tr",null,[e("th",null,"名称"),e("th",null,"编码"),e("th",null,"点位数"),e("th",null,"网关"),e("th",null,"来源 CSV"),e("th",null,"状态")])],-1)),e("tbody",null,[(o(!0),n($,null,T(be.value,l=>{var k;return o(),n("tr",{key:l.id,class:"row-click",onClick:Xl=>ye(l)},[e("td",null,a(l.name),1),e("td",lt,a(l.code),1),e("td",null,a(l.pointCount),1),e("td",null,a(l.gatewayId?de(l.gatewayId):"—"),1),e("td",st,a(((k=l.meta)==null?void 0:k.sourceCsv)||"—"),1),e("td",null,a(l.status),1)],8,tt)}),128)),P.value.length?r("",!0):(o(),n("tr",nt,[...t[44]||(t[44]=[e("td",{colspan:"6",class:"empty"},"暂无设备,点击右上角「新增设备」或导入点位 CSV",-1)])]))])])):(o(),n("table",at,[e("thead",null,[e("tr",null,[t[46]||(t[46]=e("th",null,"名称",-1)),t[47]||(t[47]=e("th",null,"地址",-1)),t[48]||(t[48]=e("th",null,"读写",-1)),t[49]||(t[49]=e("th",null,"类型",-1)),t[50]||(t[50]=e("th",null,"设备",-1)),t[51]||(t[51]=e("th",null,"ItemID",-1)),t[52]||(t[52]=e("th",null,"倍率",-1)),t[53]||(t[53]=e("th",null,"告警下限",-1)),t[54]||(t[54]=e("th",null,"告警上限",-1)),t[55]||(t[55]=e("th",null,"实时值",-1)),V(m).isAdmin?(o(),n("th",ot,"写入")):r("",!0),V(m).isAdmin?(o(),n("th",it,"操作")):r("",!0)])]),e("tbody",null,[(o(!0),n($,null,T(te.value,l=>(o(),n("tr",{key:l.id},[e("td",null,a(l.name),1),e("td",null,a(l.modbusAddress),1),e("td",null,a(ie(l)),1),e("td",null,a(l.dataType),1),e("td",null,a(Ve(l.deviceId)),1),e("td",ut,a(l.itemId),1),e("td",null,a(l.scaleOverride??l.scale),1),e("td",null,a(l.alarmLow??"—"),1),e("td",null,a(l.alarmHigh??"—"),1),e("td",null,a(l.rw==="w"?"—":l.lastEng??"—"),1),V(m).isAdmin?(o(),n("td",dt,[B(l)&&Z(l)?(o(),n("div",rt,[e("button",{class:"btn bool-on",type:"button",disabled:A.value===l.id,onClick:k=>x(l,1)}," 开 ",8,vt),e("button",{class:"btn ghost bool-off",type:"button",disabled:A.value===l.id,onClick:k=>x(l,0)}," 关 ",8,mt)])):B(l)?(o(),n("div",bt,[e("input",{class:"write-input",type:"number",step:"any",value:ae(l),disabled:A.value===l.id,onInput:k=>W[l.id]=k.target.value,onKeydown:me(N(k=>x(l),["prevent"]),["enter"])},null,40,pt),e("button",{class:"btn",type:"button",disabled:A.value===l.id,onClick:k=>x(l)},a(A.value===l.id?"…":"写"),9,ct)])):(o(),n("span",yt,"—"))])):r("",!0),V(m).isAdmin?(o(),n("td",ft,[e("button",{class:"btn ghost",type:"button",onClick:k=>ue(l)},"编辑",8,gt),e("button",{class:"btn ghost",type:"button",onClick:k=>we(l)},"删",8,kt)])):r("",!0)]))),128)),te.value.length?r("",!0):(o(),n("tr",wt,[e("td",{colspan:V(m).isAdmin?12:10,class:"empty"}," 暂无点位,点击右上角「导入 CSV」或「新增点位」 ",8,It)]))])]))])]),C.value==="viewDevice"&&h.value?(o(),n("div",{key:0,class:"modal-mask",onClick:N(f,["self"])},[e("div",Ct,[e("div",ht,[e("div",Vt,[t[56]||(t[56]=e("div",{class:"vbar"},null,-1)),e("h3",null,a(h.value.name),1),e("div",_t,a(le.value.length)+" 个点位",1)]),e("div",{class:"head-actions"},[e("button",{class:"btn ghost",type:"button",onClick:X},"刷新数值"),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")])]),e("div",Ut,[e("span",null,[t[57]||(t[57]=e("small",null,"编码",-1)),e("b",At,a(h.value.code),1)]),e("span",null,[t[58]||(t[58]=e("small",null,"网关",-1)),e("b",null,a(h.value.gatewayId?de(h.value.gatewayId):"—"),1)]),e("span",null,[t[59]||(t[59]=e("small",null,"状态",-1)),e("b",null,a(h.value.status),1)]),(O=h.value.meta)!=null&&O.sourceCsv?(o(),n("span",St,[t[60]||(t[60]=e("small",null,"来源",-1)),e("b",$t,a(h.value.meta.sourceCsv),1)])):r("",!0)]),d.value?(o(),n("p",Dt,a(d.value),1)):r("",!0),_.value?(o(),n("p",Tt,a(_.value),1)):r("",!0),e("div",Nt,[e("table",Ot,[e("thead",null,[e("tr",null,[t[61]||(t[61]=e("th",null,"点位名称",-1)),t[62]||(t[62]=e("th",null,"地址",-1)),t[63]||(t[63]=e("th",null,"读写",-1)),t[64]||(t[64]=e("th",null,"类型",-1)),t[65]||(t[65]=e("th",null,"工程值",-1)),t[66]||(t[66]=e("th",null,"告警下限",-1)),t[67]||(t[67]=e("th",null,"告警上限",-1)),t[68]||(t[68]=e("th",null,"倍率",-1)),t[69]||(t[69]=e("th",null,"更新时间",-1)),V(m).isAdmin?(o(),n("th",Lt,"写入")):r("",!0),V(m).isAdmin?(o(),n("th",Pt,"操作")):r("",!0)])]),e("tbody",null,[(o(!0),n($,null,T(le.value,l=>(o(),n("tr",{key:l.id},[e("td",null,a(l.name),1),e("td",null,a(l.modbusAddress),1),e("td",null,a(ie(l)),1),e("td",null,a(l.dataType),1),e("td",{class:j(["eng",{muted:l.lastEng===null}])},a(l.rw==="w"?"—":pe(l.lastEng)),3),e("td",null,a(l.alarmLow??"—"),1),e("td",null,a(l.alarmHigh??"—"),1),e("td",null,a(l.scaleOverride??l.scale),1),e("td",Et,a(ce(l.lastTs)),1),V(m).isAdmin?(o(),n("td",Ht,[B(l)&&Z(l)?(o(),n("div",xt,[e("button",{class:"btn bool-on",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l,1),["stop"])},a(A.value===l.id?"…":"开"),9,Rt),e("button",{class:"btn ghost bool-off",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l,0),["stop"])}," 关 ",8,Ft)])):B(l)?(o(),n("div",Mt,[e("input",{class:"write-input",type:"number",step:"any",value:ae(l),disabled:A.value===l.id,onInput:k=>W[l.id]=k.target.value,onKeydown:me(N(k=>x(l),["prevent"]),["enter"])},null,40,Gt),e("button",{class:"btn",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l),["stop"])},a(A.value===l.id?"写入中…":"写入"),9,Bt)])):(o(),n("span",Kt,"—"))])):r("",!0),V(m).isAdmin?(o(),n("td",Wt,[e("button",{class:"btn ghost",type:"button",onClick:N(k=>ue(l),["stop"])}," 编辑 ",8,Jt)])):r("",!0)]))),128)),le.value.length?r("",!0):(o(),n("tr",jt,[e("td",{colspan:V(m).isAdmin?11:9,class:"empty"},"该设备暂无绑定点位",8,zt)]))])])]),t[70]||(t[70]=e("p",{class:"hint"}," 对话框打开期间每 3 秒自动刷新采集点数值;写控点可在「写入」列下发(管理员)。 ",-1))])])):r("",!0),C.value==="import"?(o(),n("div",{key:1,class:"modal-mask",onClick:N(f,["self"])},[e("div",qt,[e("div",{class:"panel-head"},[t[71]||(t[71]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"导入 CSV")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",Qt,[e("div",Xt,[t[72]||(t[72]=e("label",null,"目标网关",-1)),v(e("select",{"onUpdate:modelValue":t[7]||(t[7]=l=>y.gatewayId=l)},[(o(!0),n($,null,T(U.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,Yt))),128))],512),[[L,y.gatewayId]])]),e("div",Zt,[t[74]||(t[74]=e("label",null,"编码",-1)),v(e("select",{"onUpdate:modelValue":t[8]||(t[8]=l=>y.encoding=l)},[...t[73]||(t[73]=[e("option",{value:"gbk"},"GBK(现场表)",-1),e("option",{value:"utf-8"},"UTF-8",-1)])],512),[[L,y.encoding]])]),e("label",el,[v(e("input",{"onUpdate:modelValue":t[9]||(t[9]=l=>y.replaceGateway=l),type:"checkbox"},null,512),[[re,y.replaceGateway]]),t[75]||(t[75]=ve(" 替换该网关已有点位 ",-1))])]),v(e("textarea",{"onUpdate:modelValue":t[10]||(t[10]=l=>y.csv=l),class:"csv-area",placeholder:"粘贴现场点位 CSV(含表头 Name, Modbus Address, ItemID …)"},null,512),[[c,y.csv]]),d.value?(o(),n("p",tl,a(d.value),1)):r("",!0),e("div",ll,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:Ie},a(I.value?"导入中…":"确认导入"),9,sl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0),C.value==="createDevice"?(o(),n("div",{key:2,class:"modal-mask",onClick:N(f,["self"])},[e("div",nl,[e("div",{class:"panel-head"},[t[76]||(t[76]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增设备")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",al,[e("div",ol,[t[77]||(t[77]=e("label",null,"名称",-1)),v(e("input",{"onUpdate:modelValue":t[11]||(t[11]=l=>p.name=l)},null,512),[[c,p.name]])]),e("div",il,[t[78]||(t[78]=e("label",null,"编码",-1)),v(e("input",{"onUpdate:modelValue":t[12]||(t[12]=l=>p.code=l)},null,512),[[c,p.code]])]),e("div",ul,[t[80]||(t[80]=e("label",null,"类别",-1)),v(e("select",{"onUpdate:modelValue":t[13]||(t[13]=l=>p.category=l)},[...t[79]||(t[79]=[$e('<option value="fridge" data-v-a043261c>冰箱</option><option value="vav" data-v-a043261c>通风柜</option><option value="room" data-v-a043261c>房间屏</option><option value="pau" data-v-a043261c>机组</option><option value="meter_power" data-v-a043261c>电表</option><option value="meter_water" data-v-a043261c>水表/流量计</option><option value="meter_cooling" data-v-a043261c>能量计</option><option value="other" data-v-a043261c>其它</option>',8)])],512),[[L,p.category]])]),e("div",dl,[t[82]||(t[82]=e("label",null,"网关",-1)),v(e("select",{"onUpdate:modelValue":t[14]||(t[14]=l=>p.gatewayId=l)},[t[81]||(t[81]=e("option",{value:null},"无",-1)),(o(!0),n($,null,T(U.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,rl))),128))],512),[[L,p.gatewayId]])]),e("div",vl,[t[83]||(t[83]=e("label",null,"界面绑定",-1)),v(e("input",{"onUpdate:modelValue":t[15]||(t[15]=l=>p.bindUi=l),placeholder:"cold / vav / …"},null,512),[[c,p.bindUi]])])]),d.value?(o(),n("p",ml,a(d.value),1)):r("",!0),e("div",bl,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:ke},a(I.value?"创建中…":"创建"),9,pl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0),C.value==="createPoint"?(o(),n("div",{key:3,class:"modal-mask",onClick:N(f,["self"])},[e("div",cl,[e("div",{class:"panel-head"},[t[84]||(t[84]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增点位")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",yl,[e("div",fl,[t[85]||(t[85]=e("label",null,"名称",-1)),v(e("input",{"onUpdate:modelValue":t[16]||(t[16]=l=>u.name=l)},null,512),[[c,u.name]])]),e("div",gl,[t[86]||(t[86]=e("label",null,"网关",-1)),v(e("select",{"onUpdate:modelValue":t[17]||(t[17]=l=>u.gatewayId=l)},[(o(!0),n($,null,T(U.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,kl))),128))],512),[[L,u.gatewayId]])]),e("div",wl,[t[87]||(t[87]=e("label",null,"Modbus Address",-1)),v(e("input",{"onUpdate:modelValue":t[18]||(t[18]=l=>u.modbusAddress=l),type:"number"},null,512),[[c,u.modbusAddress,void 0,{number:!0}]])]),e("div",Il,[t[88]||(t[88]=e("label",null,"DataType",-1)),v(e("input",{"onUpdate:modelValue":t[19]||(t[19]=l=>u.dataType=l)},null,512),[[c,u.dataType]])]),e("div",Cl,[t[89]||(t[89]=e("label",null,"Modbus ID",-1)),v(e("input",{"onUpdate:modelValue":t[20]||(t[20]=l=>u.modbusId=l),type:"number"},null,512),[[c,u.modbusId,void 0,{number:!0}]])]),e("div",hl,[t[90]||(t[90]=e("label",null,"ItemID",-1)),v(e("input",{"onUpdate:modelValue":t[21]||(t[21]=l=>u.itemId=l),placeholder:"可选"},null,512),[[c,u.itemId]])]),e("div",Vl,[t[92]||(t[92]=e("label",null,"设备",-1)),v(e("select",{"onUpdate:modelValue":t[22]||(t[22]=l=>u.deviceId=l)},[t[91]||(t[91]=e("option",{value:null},"无",-1)),(o(!0),n($,null,T(P.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,_l))),128))],512),[[L,u.deviceId]])]),e("div",Ul,[t[93]||(t[93]=e("label",null,"Scale 覆盖",-1)),v(e("input",{"onUpdate:modelValue":t[23]||(t[23]=l=>u.scaleOverride=l),type:"number",step:"any"},null,512),[[c,u.scaleOverride,void 0,{number:!0}]])]),e("div",Al,[t[94]||(t[94]=e("label",null,"告警下限",-1)),v(e("input",{"onUpdate:modelValue":t[24]||(t[24]=l=>u.alarmLow=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[c,u.alarmLow,void 0,{number:!0}]])]),e("div",Sl,[t[95]||(t[95]=e("label",null,"告警上限",-1)),v(e("input",{"onUpdate:modelValue":t[25]||(t[25]=l=>u.alarmHigh=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[c,u.alarmHigh,void 0,{number:!0}]])])]),d.value?(o(),n("p",$l,a(d.value),1)):r("",!0),e("div",Dl,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:ge},a(I.value?"创建中…":"创建"),9,Tl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0),C.value==="editPoint"&&i.value?(o(),n("div",{key:4,class:"modal-mask",onClick:N(f,["self"])},[e("div",Nl,[e("div",{class:"panel-head"},[t[96]||(t[96]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"编辑点位")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",Ol,[e("div",Ll,[t[97]||(t[97]=e("label",null,"名称",-1)),v(e("input",{"onUpdate:modelValue":t[26]||(t[26]=l=>i.value.name=l)},null,512),[[c,i.value.name]])]),e("div",Pl,[t[98]||(t[98]=e("label",null,"Modbus Address",-1)),v(e("input",{"onUpdate:modelValue":t[27]||(t[27]=l=>i.value.modbusAddress=l),type:"number"},null,512),[[c,i.value.modbusAddress,void 0,{number:!0}]])]),e("div",El,[t[99]||(t[99]=e("label",null,"DataType",-1)),v(e("input",{"onUpdate:modelValue":t[28]||(t[28]=l=>i.value.dataType=l)},null,512),[[c,i.value.dataType]])]),e("div",Hl,[t[100]||(t[100]=e("label",null,"Modbus ID",-1)),v(e("input",{"onUpdate:modelValue":t[29]||(t[29]=l=>i.value.modbusId=l),type:"number"},null,512),[[c,i.value.modbusId,void 0,{number:!0}]])]),e("div",xl,[t[101]||(t[101]=e("label",null,"ItemID",-1)),v(e("input",{"onUpdate:modelValue":t[30]||(t[30]=l=>i.value.itemId=l)},null,512),[[c,i.value.itemId]])]),e("div",Rl,[t[102]||(t[102]=e("label",null,"Scale",-1)),v(e("input",{"onUpdate:modelValue":t[31]||(t[31]=l=>i.value.scale=l),type:"number",step:"any"},null,512),[[c,i.value.scale,void 0,{number:!0}]])]),e("div",Fl,[t[103]||(t[103]=e("label",null,"Scale 覆盖",-1)),v(e("input",{"onUpdate:modelValue":t[32]||(t[32]=l=>i.value.scaleOverride=l),type:"number",step:"any"},null,512),[[c,i.value.scaleOverride,void 0,{number:!0}]])]),e("div",Ml,[t[104]||(t[104]=e("label",null,"告警下限",-1)),v(e("input",{"onUpdate:modelValue":t[33]||(t[33]=l=>i.value.alarmLow=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[c,i.value.alarmLow,void 0,{number:!0}]])]),e("div",Gl,[t[105]||(t[105]=e("label",null,"告警上限",-1)),v(e("input",{"onUpdate:modelValue":t[34]||(t[34]=l=>i.value.alarmHigh=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[c,i.value.alarmHigh,void 0,{number:!0}]])]),e("div",Bl,[t[107]||(t[107]=e("label",null,"设备",-1)),v(e("select",{"onUpdate:modelValue":t[35]||(t[35]=l=>i.value.deviceId=l)},[t[106]||(t[106]=e("option",{value:null},"无",-1)),(o(!0),n($,null,T(P.value,l=>(o(),n("option",{key:l.id,value:l.id},a(l.name),9,Kl))),128))],512),[[L,i.value.deviceId]])]),e("label",Wl,[v(e("input",{"onUpdate:modelValue":t[36]||(t[36]=l=>i.value.enabled=l),type:"checkbox"},null,512),[[re,i.value.enabled]]),t[108]||(t[108]=ve(" 启用采集",-1))])]),d.value?(o(),n("p",Jl,a(d.value),1)):r("",!0),e("div",jl,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:fe},a(I.value?"保存中…":"保存"),9,zl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0)])}}}),Zl=De(ql,[["__scopeId","data-v-a043261c"]]);export{Zl as default};
import{d as Ue,u as _e,j as Ae,k as Se,c as a,b as e,t as n,h as U,f as v,F as S,n as z,e as r,L,z as T,w as N,M as re,g as ve,v as y,a as De,r as w,N as Q,B as oe,l as D,o,Y as me,_ as $e}from"./index-Bs_x-_cK.js";const Te={class:"page-fill devices-page"},Ne={class:"panel list-panel"},Oe={class:"panel-head"},Le={class:"panel-title"},Pe={class:"badge"},Ee={class:"head-actions"},He=["disabled"],xe={class:"tab-row"},Re={key:0,class:"filters"},Me={class:"field"},Fe=["value"],Ge={class:"field"},Be=["value"],Ke={class:"filter-hint"},We={key:1,class:"msg ok"},je={key:2,class:"msg err"},ze={class:"table-wrap"},Je={key:0,class:"table"},qe=["onClick"],Xe={class:"mono"},Ye={class:"mono"},Qe={key:0},Ze={key:1,class:"table"},et={key:0},tt={key:1},lt={class:"mono"},st={key:0},nt={key:0,class:"write-cell"},at=["disabled","onClick"],ot=["disabled","onClick"],it={key:1,class:"write-cell"},ut=["value","disabled","onInput","onKeydown"],dt=["disabled","onClick"],rt={key:2,class:"muted"},vt={key:1,class:"ops"},mt=["onClick"],bt=["onClick"],pt={key:0},yt=["colspan"],ct={class:"gw-status"},ft={class:"table"},gt={class:"modal panel modal-xl"},kt={class:"panel-head"},wt={class:"panel-title"},It={class:"badge"},Ct={class:"device-meta"},ht={class:"mono"},Vt={key:0},Ut={class:"mono"},_t={key:0,class:"msg err"},At={key:1,class:"msg ok"},St={class:"detail-table-wrap"},Dt={class:"table"},$t={key:0},Tt={key:1},Nt={class:"mono ts"},Ot={key:0},Lt={key:0,class:"write-cell"},Pt=["disabled","onClick"],Et=["disabled","onClick"],Ht={key:1,class:"write-cell"},xt=["value","disabled","onInput","onKeydown"],Rt=["disabled","onClick"],Mt={key:2,class:"muted"},Ft={key:1,class:"ops"},Gt=["onClick"],Bt={key:0},Kt=["colspan"],Wt={class:"modal panel modal-lg"},jt={class:"filters"},zt={class:"field"},Jt=["value"],qt={class:"field"},Xt={class:"check"},Yt={key:0,class:"msg err"},Qt={class:"modal-actions"},Zt=["disabled"],el={class:"modal panel"},tl={class:"form-grid"},ll={class:"field"},sl={class:"field"},nl={class:"field"},al={class:"field"},ol=["value"],il={class:"field"},ul={key:0,class:"msg err"},dl={class:"modal-actions"},rl=["disabled"],vl={class:"modal panel"},ml={class:"form-grid"},bl={class:"field"},pl={class:"field"},yl=["value"],cl={class:"field"},fl={class:"field"},gl={class:"field"},kl={class:"field"},wl={class:"field"},Il=["value"],Cl={class:"field"},hl={class:"field"},Vl={class:"field"},Ul={key:0,class:"msg err"},_l={class:"modal-actions"},Al=["disabled"],Sl={class:"modal panel"},Dl={class:"form-grid"},$l={class:"field"},Tl={class:"field"},Nl={class:"field"},Ol={class:"field"},Ll={class:"field"},Pl={class:"field"},El={class:"field"},Hl={class:"field"},xl={class:"field"},Rl={class:"field"},Ml=["value"],Fl={class:"check"},Gl={key:0,class:"msg err"},Bl={class:"modal-actions"},Kl=["disabled"],Wl=Ue({__name:"DevicesView",setup(jl){function ie(s){const t=s.rw||"r";return t==="w"?"写控":t==="rw"?"读写":"采集"}function B(s){const t=s.rw||"r";return t==="w"||t==="rw"}function Z(s){const t=(s.dataType||"").toLowerCase(),b=(s.regType||"").toUpperCase();return!!(/bool|bit|coil/.test(t)||b.includes("-F5")||/\b0X\b/.test(b)||b.includes("COIL"))}const m=_e(),C=w("devices"),h=w(null),ee=w(!1),I=w(!1),_=w(""),d=w(""),$=w([]),P=w([]),F=w([]),K=w(1),G=w(null),V=w(null),R=w(!1),W=Q({}),A=w(null);let J;const E=w(""),j=w(""),c=Q({gatewayId:"mb-104",encoding:"gbk",replaceGateway:!0,csv:""}),p=Q({name:"",code:"",category:"other",gatewayId:"",bindUi:""}),u=Q({name:"",gatewayId:"mb-104",deviceId:null,modbusAddress:0,dataType:"Short",modbusId:1,itemId:"",scale:0,scaleOverride:.1,alarmLow:null,alarmHigh:null,enabled:!0}),i=w(null),te=oe(()=>F.value.filter(s=>!(E.value&&s.gatewayId!==E.value||j.value&&s.deviceId!==j.value))),be=oe(()=>P.value.map(s=>({...s,pointCount:F.value.filter(t=>t.deviceId===s.id).length}))),le=oe(()=>V.value?F.value.filter(s=>s.deviceId===V.value.id).sort((s,t)=>s.modbusAddress-t.modbusAddress||s.name.localeCompare(t.name,"zh")):[]);function q(){_.value="",d.value=""}function pe(s){return s==null||Number.isNaN(s)?"—":Number.isInteger(s)?String(s):s.toFixed(2)}function ye(s){if(!s)return"—";try{return new Date(s).toLocaleString("zh-CN",{hour12:!1})}catch{return s}}function X(){J!==void 0&&(window.clearInterval(J),J=void 0)}async function Y(){try{const s=await D("/api/devices/points",{token:m.token});F.value=s.points,K.value=s.pointsVersion}catch{}}function se(){X(),Y(),J=window.setInterval(()=>{Y()},3e3)}function ce(s){q(),V.value=s,R.value=!1,h.value="viewDevice",se()}function ne(s){var t,b;q(),s==="import"&&(!c.gatewayId&&$.value[0]&&(c.gatewayId=$.value[0].id),c.csv=""),s==="createDevice"&&(p.name="",p.code="",p.category="other",p.gatewayId=((t=$.value[0])==null?void 0:t.id)||null,p.bindUi=""),s==="createPoint"&&(u.name="",u.gatewayId=E.value||((b=$.value[0])==null?void 0:b.id)||"mb-104",u.deviceId=j.value||null,u.modbusAddress=0,u.dataType="Short",u.modbusId=1,u.itemId="",u.scale=0,u.scaleOverride=.1,u.alarmLow=null,u.alarmHigh=null,u.enabled=!0),h.value=s}function f(){if(h.value==="editPoint"&&R.value&&V.value){i.value=null,d.value="",R.value=!1,h.value="viewDevice",se();return}X(),h.value=null,i.value=null,V.value=null,R.value=!1,d.value=""}function ue(s){q(),R.value=h.value==="viewDevice",X(),i.value={...s},h.value="editPoint"}async function H(){ee.value=!0,d.value="";try{const[s,t,b,g]=await Promise.allSettled([D("/api/devices/gateways",{token:m.token}),D("/api/devices",{token:m.token}),D("/api/devices/points",{token:m.token}),D("/api/devices/gateways/health",{token:m.token})]);s.status==="fulfilled"&&($.value=s.value.gateways,!c.gatewayId&&s.value.gateways[0]&&(c.gatewayId=s.value.gateways[0].id),s.value.pointsVersion&&(K.value=s.value.pointsVersion)),t.status==="fulfilled"&&(P.value=t.value.devices),b.status==="fulfilled"&&(F.value=b.value.points,K.value=b.value.pointsVersion||K.value),g.status==="fulfilled"?G.value=g.value:G.value={ok:!1,message:"Windows 网关未连接(不影响本地设备列表)"};const M=[s,t,b].filter(O=>O.status==="rejected");if(M.length===3){const O=M[0].reason;d.value=O instanceof Error?O.message:"加载失败"}else if(t.status==="rejected"){const O=t.reason;d.value=O instanceof Error?O.message:"设备列表加载失败"}}catch(s){d.value=s instanceof Error?s.message:"加载失败"}finally{ee.value=!1}}async function fe(){if(i.value){d.value="",I.value=!0;try{await D(`/api/devices/points/${i.value.id}`,{method:"PATCH",token:m.token,body:JSON.stringify({name:i.value.name,modbusAddress:Number(i.value.modbusAddress),dataType:i.value.dataType,modbusId:Number(i.value.modbusId),itemId:i.value.itemId,scale:Number(i.value.scale),scaleOverride:i.value.scaleOverride===null||i.value.scaleOverride===""?null:Number(i.value.scaleOverride),alarmLow:i.value.alarmLow===null||i.value.alarmLow===""?null:Number(i.value.alarmLow),alarmHigh:i.value.alarmHigh===null||i.value.alarmHigh===""?null:Number(i.value.alarmHigh),deviceId:i.value.deviceId||null,enabled:i.value.enabled})}),_.value="点位已保存",i.value=null,d.value="",R.value&&V.value?(R.value=!1,h.value="viewDevice",await H(),se()):(f(),await H())}catch(s){d.value=s instanceof Error?s.message:"保存失败"}finally{I.value=!1}}}async function ge(){if(d.value="",!u.name.trim()){d.value="请填写点位名称";return}I.value=!0;try{await D("/api/devices/points",{method:"POST",token:m.token,body:JSON.stringify({name:u.name,gatewayId:u.gatewayId,deviceId:u.deviceId,modbusAddress:Number(u.modbusAddress),dataType:u.dataType,modbusId:Number(u.modbusId),itemId:u.itemId||void 0,scale:Number(u.scale),scaleOverride:u.scaleOverride,alarmLow:u.alarmLow,alarmHigh:u.alarmHigh,enabled:u.enabled})}),_.value="点位已创建",f(),C.value="points",await H()}catch(s){d.value=s instanceof Error?s.message:"创建失败"}finally{I.value=!1}}async function ke(){if(d.value="",!p.name.trim()||!p.code.trim()){d.value="名称与编码必填";return}I.value=!0;try{await D("/api/devices",{method:"POST",token:m.token,body:JSON.stringify({name:p.name,code:p.code,category:p.category,gatewayId:p.gatewayId,bindUi:p.bindUi})}),_.value="设备已创建",f(),C.value="devices",await H()}catch(s){d.value=s instanceof Error?s.message:"创建失败"}finally{I.value=!1}}async function we(s){confirm(`删除点位「${s.name}」?`)&&(await D(`/api/devices/points/${s.id}`,{method:"DELETE",token:m.token}),_.value="点位已删除",await H())}async function Ie(){if(d.value="",!c.csv.trim()){d.value="请粘贴 CSV 内容";return}I.value=!0;try{const s=await D("/api/devices/points/import",{method:"POST",token:m.token,body:JSON.stringify({gatewayId:c.gatewayId,encoding:c.encoding==="utf-8"?"utf-8":"gbk",replaceGateway:c.replaceGateway,csv:c.csv})});_.value=`已导入 ${s.imported} 个点位,版本 ${s.pointsVersion}`,E.value=c.gatewayId,f(),C.value="points",await H()}catch(s){d.value=s instanceof Error?s.message:"导入失败"}finally{I.value=!1}}async function Ce(){const s=new URLSearchParams;E.value&&s.set("gatewayId",E.value),s.set("encoding","utf-8");const t=await fetch(`/api/devices/points/export?${s.toString()}`,{headers:{Authorization:`Bearer ${m.token}`}});if(!t.ok){d.value="导出失败";return}const b=await t.blob(),g=document.createElement("a");g.href=URL.createObjectURL(b),g.download="device-points.csv",g.click(),URL.revokeObjectURL(g.href),_.value="CSV 已导出"}async function he(){q();try{const s=await D("/api/devices/points/sync-gateway",{method:"POST",token:m.token});s.ok?_.value=s.message:d.value=s.message,G.value=await D("/api/devices/gateways/health",{token:m.token})}catch(s){d.value=s instanceof Error?s.message:"同步失败"}}function ae(s){return W[s.id]!==void 0?W[s.id]:s.lastEng!==null&&s.lastEng!==void 0?String(s.lastEng):""}async function x(s,t){if(!m.isAdmin||!B(s))return;let b;if(t!==void 0)b=t;else{const g=ae(s).trim();if(b=Number(g),!Number.isFinite(b)){d.value=`请为「${s.name}」填写有效数值`;return}}A.value=s.id,d.value="";try{const g=await D(`/api/devices/points/${s.id}/write`,{method:"POST",token:m.token,body:JSON.stringify({value:b})}),M=Z(s)?b?"开":"关":String(b);_.value=`已写入 ${s.name} = ${M}${g.message?`(${g.message})`:""}`,W[s.id]=String(b),await Y()}catch(g){d.value=g instanceof Error?g.message:"写入失败"}finally{A.value=null}}function de(s){var t;return((t=$.value.find(b=>b.id===s))==null?void 0:t.name)||s}function Ve(s){var t;return s?((t=P.value.find(b=>b.id===s))==null?void 0:t.name)||s:"—"}return Ae(H),Se(X),(s,t)=>{var b,g,M,O;return o(),a("div",Te,[e("section",Ne,[e("div",Oe,[e("div",Le,[t[38]||(t[38]=e("div",{class:"vbar"},null,-1)),t[39]||(t[39]=e("h3",null,"设备与点位",-1)),e("div",Pe,"点表 v"+n(K.value),1)]),e("div",Ee,[e("button",{class:"btn ghost",type:"button",disabled:ee.value,onClick:H},"刷新",8,He),U(m).isAdmin?(o(),a("button",{key:0,class:"btn ghost",type:"button",onClick:he}," 下发网关 ")):v("",!0),C.value==="devices"&&U(m).isAdmin?(o(),a("button",{key:1,class:"btn",type:"button",onClick:t[0]||(t[0]=l=>ne("createDevice"))},"新增设备")):v("",!0),C.value==="points"?(o(),a(S,{key:2},[e("button",{class:"btn ghost",type:"button",onClick:Ce},"导出 CSV"),U(m).isAdmin?(o(),a("button",{key:0,class:"btn ghost",type:"button",onClick:t[1]||(t[1]=l=>ne("import"))}," 导入 CSV ")):v("",!0),U(m).isAdmin?(o(),a("button",{key:1,class:"btn",type:"button",onClick:t[2]||(t[2]=l=>ne("createPoint"))}," 新增点位 ")):v("",!0)],64)):v("",!0)])]),e("div",xe,[e("button",{class:z(["btn",{ghost:C.value!=="devices"}]),type:"button",onClick:t[3]||(t[3]=l=>C.value="devices")}," 设备("+n(P.value.length)+") ",3),e("button",{class:z(["btn",{ghost:C.value!=="points"}]),type:"button",onClick:t[4]||(t[4]=l=>C.value="points")}," 点位("+n(F.value.length)+") ",3),e("button",{class:z(["btn",{ghost:C.value!=="gateways"}]),type:"button",onClick:t[5]||(t[5]=l=>C.value="gateways")}," 网关("+n($.value.length)+") ",3)]),C.value==="points"?(o(),a("div",Re,[e("div",Me,[t[41]||(t[41]=e("label",null,"网关",-1)),r(e("select",{"onUpdate:modelValue":t[6]||(t[6]=l=>E.value=l)},[t[40]||(t[40]=e("option",{value:""},"全部",-1)),(o(!0),a(S,null,T($.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,Fe))),128))],512),[[L,E.value]])]),e("div",Ge,[t[43]||(t[43]=e("label",null,"设备",-1)),r(e("select",{"onUpdate:modelValue":t[7]||(t[7]=l=>j.value=l)},[t[42]||(t[42]=e("option",{value:""},"全部",-1)),(o(!0),a(S,null,T(P.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,Be))),128))],512),[[L,j.value]])]),e("span",Ke,"当前 "+n(te.value.length)+" 条",1)])):v("",!0),_.value?(o(),a("p",We,n(_.value),1)):v("",!0),d.value&&!h.value?(o(),a("p",je,n(d.value),1)):v("",!0),e("div",ze,[C.value==="devices"?(o(),a("table",Je,[t[45]||(t[45]=e("thead",null,[e("tr",null,[e("th",null,"名称"),e("th",null,"编码"),e("th",null,"点位数"),e("th",null,"网关"),e("th",null,"来源 CSV"),e("th",null,"状态")])],-1)),e("tbody",null,[(o(!0),a(S,null,T(be.value,l=>{var k;return o(),a("tr",{key:l.id,class:"row-click",onClick:zl=>ce(l)},[e("td",null,n(l.name),1),e("td",Xe,n(l.code),1),e("td",null,n(l.pointCount),1),e("td",null,n(l.gatewayId?de(l.gatewayId):"—"),1),e("td",Ye,n(((k=l.meta)==null?void 0:k.sourceCsv)||"—"),1),e("td",null,n(l.status),1)],8,qe)}),128)),P.value.length?v("",!0):(o(),a("tr",Qe,[...t[44]||(t[44]=[e("td",{colspan:"6",class:"empty"},"暂无设备,点击右上角「新增设备」或导入点位 CSV",-1)])]))])])):C.value==="points"?(o(),a("table",Ze,[e("thead",null,[e("tr",null,[t[46]||(t[46]=e("th",null,"名称",-1)),t[47]||(t[47]=e("th",null,"地址",-1)),t[48]||(t[48]=e("th",null,"读写",-1)),t[49]||(t[49]=e("th",null,"类型",-1)),t[50]||(t[50]=e("th",null,"设备",-1)),t[51]||(t[51]=e("th",null,"ItemID",-1)),t[52]||(t[52]=e("th",null,"倍率",-1)),t[53]||(t[53]=e("th",null,"告警下限",-1)),t[54]||(t[54]=e("th",null,"告警上限",-1)),t[55]||(t[55]=e("th",null,"实时值",-1)),U(m).isAdmin?(o(),a("th",et,"写入")):v("",!0),U(m).isAdmin?(o(),a("th",tt,"操作")):v("",!0)])]),e("tbody",null,[(o(!0),a(S,null,T(te.value,l=>(o(),a("tr",{key:l.id},[e("td",null,n(l.name),1),e("td",null,n(l.modbusAddress),1),e("td",null,n(ie(l)),1),e("td",null,n(l.dataType),1),e("td",null,n(Ve(l.deviceId)),1),e("td",lt,n(l.itemId),1),e("td",null,n(l.scaleOverride??l.scale),1),e("td",null,n(l.alarmLow??"—"),1),e("td",null,n(l.alarmHigh??"—"),1),e("td",null,n(l.rw==="w"?"—":l.lastEng??"—"),1),U(m).isAdmin?(o(),a("td",st,[B(l)&&Z(l)?(o(),a("div",nt,[e("button",{class:"btn bool-on",type:"button",disabled:A.value===l.id,onClick:k=>x(l,1)}," 开 ",8,at),e("button",{class:"btn ghost bool-off",type:"button",disabled:A.value===l.id,onClick:k=>x(l,0)}," 关 ",8,ot)])):B(l)?(o(),a("div",it,[e("input",{class:"write-input",type:"number",step:"any",value:ae(l),disabled:A.value===l.id,onInput:k=>W[l.id]=k.target.value,onKeydown:me(N(k=>x(l),["prevent"]),["enter"])},null,40,ut),e("button",{class:"btn",type:"button",disabled:A.value===l.id,onClick:k=>x(l)},n(A.value===l.id?"…":"写"),9,dt)])):(o(),a("span",rt,"—"))])):v("",!0),U(m).isAdmin?(o(),a("td",vt,[e("button",{class:"btn ghost",type:"button",onClick:k=>ue(l)},"编辑",8,mt),e("button",{class:"btn ghost",type:"button",onClick:k=>we(l)},"删",8,bt)])):v("",!0)]))),128)),te.value.length?v("",!0):(o(),a("tr",pt,[e("td",{colspan:U(m).isAdmin?12:10,class:"empty"}," 暂无点位,点击右上角「导入 CSV」或「新增点位」 ",8,yt)]))])])):(o(),a(S,{key:2},[e("div",ct,[e("span",{class:z(["badge",(b=G.value)!=null&&b.ok?"":"amber"])}," Windows 网关 "+n((g=G.value)!=null&&g.ok?"在线":((M=G.value)==null?void 0:M.message)||"未连接"),3)]),e("table",ft,[t[56]||(t[56]=e("thead",null,[e("tr",null,[e("th",null,"ID"),e("th",null,"名称"),e("th",null,"主机"),e("th",null,"端口"),e("th",null,"启用")])],-1)),e("tbody",null,[(o(!0),a(S,null,T($.value,l=>(o(),a("tr",{key:l.id},[e("td",null,n(l.id),1),e("td",null,n(l.name),1),e("td",null,n(l.host),1),e("td",null,n(l.port),1),e("td",null,n(l.enabled?"是":"否"),1)]))),128))])]),t[57]||(t[57]=e("p",{class:"hint"},"实际协议由单一 Windows 网关连接上述主机;平台仅维护主数据与点位。",-1))],64))])]),h.value==="viewDevice"&&V.value?(o(),a("div",{key:0,class:"modal-mask",onClick:N(f,["self"])},[e("div",gt,[e("div",kt,[e("div",wt,[t[58]||(t[58]=e("div",{class:"vbar"},null,-1)),e("h3",null,n(V.value.name),1),e("div",It,n(le.value.length)+" 个点位",1)]),e("div",{class:"head-actions"},[e("button",{class:"btn ghost",type:"button",onClick:Y},"刷新数值"),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")])]),e("div",Ct,[e("span",null,[t[59]||(t[59]=e("small",null,"编码",-1)),e("b",ht,n(V.value.code),1)]),e("span",null,[t[60]||(t[60]=e("small",null,"网关",-1)),e("b",null,n(V.value.gatewayId?de(V.value.gatewayId):"—"),1)]),e("span",null,[t[61]||(t[61]=e("small",null,"状态",-1)),e("b",null,n(V.value.status),1)]),(O=V.value.meta)!=null&&O.sourceCsv?(o(),a("span",Vt,[t[62]||(t[62]=e("small",null,"来源",-1)),e("b",Ut,n(V.value.meta.sourceCsv),1)])):v("",!0)]),d.value?(o(),a("p",_t,n(d.value),1)):v("",!0),_.value?(o(),a("p",At,n(_.value),1)):v("",!0),e("div",St,[e("table",Dt,[e("thead",null,[e("tr",null,[t[63]||(t[63]=e("th",null,"点位名称",-1)),t[64]||(t[64]=e("th",null,"地址",-1)),t[65]||(t[65]=e("th",null,"读写",-1)),t[66]||(t[66]=e("th",null,"类型",-1)),t[67]||(t[67]=e("th",null,"工程值",-1)),t[68]||(t[68]=e("th",null,"告警下限",-1)),t[69]||(t[69]=e("th",null,"告警上限",-1)),t[70]||(t[70]=e("th",null,"倍率",-1)),t[71]||(t[71]=e("th",null,"更新时间",-1)),U(m).isAdmin?(o(),a("th",$t,"写入")):v("",!0),U(m).isAdmin?(o(),a("th",Tt,"操作")):v("",!0)])]),e("tbody",null,[(o(!0),a(S,null,T(le.value,l=>(o(),a("tr",{key:l.id},[e("td",null,n(l.name),1),e("td",null,n(l.modbusAddress),1),e("td",null,n(ie(l)),1),e("td",null,n(l.dataType),1),e("td",{class:z(["eng",{muted:l.lastEng===null}])},n(l.rw==="w"?"—":pe(l.lastEng)),3),e("td",null,n(l.alarmLow??"—"),1),e("td",null,n(l.alarmHigh??"—"),1),e("td",null,n(l.scaleOverride??l.scale),1),e("td",Nt,n(ye(l.lastTs)),1),U(m).isAdmin?(o(),a("td",Ot,[B(l)&&Z(l)?(o(),a("div",Lt,[e("button",{class:"btn bool-on",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l,1),["stop"])},n(A.value===l.id?"…":"开"),9,Pt),e("button",{class:"btn ghost bool-off",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l,0),["stop"])}," 关 ",8,Et)])):B(l)?(o(),a("div",Ht,[e("input",{class:"write-input",type:"number",step:"any",value:ae(l),disabled:A.value===l.id,onInput:k=>W[l.id]=k.target.value,onKeydown:me(N(k=>x(l),["prevent"]),["enter"])},null,40,xt),e("button",{class:"btn",type:"button",disabled:A.value===l.id,onClick:N(k=>x(l),["stop"])},n(A.value===l.id?"写入中…":"写入"),9,Rt)])):(o(),a("span",Mt,"—"))])):v("",!0),U(m).isAdmin?(o(),a("td",Ft,[e("button",{class:"btn ghost",type:"button",onClick:N(k=>ue(l),["stop"])}," 编辑 ",8,Gt)])):v("",!0)]))),128)),le.value.length?v("",!0):(o(),a("tr",Bt,[e("td",{colspan:U(m).isAdmin?11:9,class:"empty"},"该设备暂无绑定点位",8,Kt)]))])])]),t[72]||(t[72]=e("p",{class:"hint"}," 对话框打开期间每 3 秒自动刷新采集点数值;写控点可在「写入」列下发(管理员)。 ",-1))])])):v("",!0),h.value==="import"?(o(),a("div",{key:1,class:"modal-mask",onClick:N(f,["self"])},[e("div",Wt,[e("div",{class:"panel-head"},[t[73]||(t[73]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"导入 CSV")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",jt,[e("div",zt,[t[74]||(t[74]=e("label",null,"目标网关",-1)),r(e("select",{"onUpdate:modelValue":t[8]||(t[8]=l=>c.gatewayId=l)},[(o(!0),a(S,null,T($.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,Jt))),128))],512),[[L,c.gatewayId]])]),e("div",qt,[t[76]||(t[76]=e("label",null,"编码",-1)),r(e("select",{"onUpdate:modelValue":t[9]||(t[9]=l=>c.encoding=l)},[...t[75]||(t[75]=[e("option",{value:"gbk"},"GBK(现场表)",-1),e("option",{value:"utf-8"},"UTF-8",-1)])],512),[[L,c.encoding]])]),e("label",Xt,[r(e("input",{"onUpdate:modelValue":t[10]||(t[10]=l=>c.replaceGateway=l),type:"checkbox"},null,512),[[re,c.replaceGateway]]),t[77]||(t[77]=ve(" 替换该网关已有点位 ",-1))])]),r(e("textarea",{"onUpdate:modelValue":t[11]||(t[11]=l=>c.csv=l),class:"csv-area",placeholder:"粘贴现场点位 CSV(含表头 Name, Modbus Address, ItemID …)"},null,512),[[y,c.csv]]),d.value?(o(),a("p",Yt,n(d.value),1)):v("",!0),e("div",Qt,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:Ie},n(I.value?"导入中…":"确认导入"),9,Zt),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):v("",!0),h.value==="createDevice"?(o(),a("div",{key:2,class:"modal-mask",onClick:N(f,["self"])},[e("div",el,[e("div",{class:"panel-head"},[t[78]||(t[78]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增设备")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",tl,[e("div",ll,[t[79]||(t[79]=e("label",null,"名称",-1)),r(e("input",{"onUpdate:modelValue":t[12]||(t[12]=l=>p.name=l)},null,512),[[y,p.name]])]),e("div",sl,[t[80]||(t[80]=e("label",null,"编码",-1)),r(e("input",{"onUpdate:modelValue":t[13]||(t[13]=l=>p.code=l)},null,512),[[y,p.code]])]),e("div",nl,[t[82]||(t[82]=e("label",null,"类别",-1)),r(e("select",{"onUpdate:modelValue":t[14]||(t[14]=l=>p.category=l)},[...t[81]||(t[81]=[De('<option value="fridge" data-v-b0783294>冰箱</option><option value="vav" data-v-b0783294>通风柜</option><option value="room" data-v-b0783294>房间屏</option><option value="pau" data-v-b0783294>机组</option><option value="meter_power" data-v-b0783294>电表</option><option value="meter_water" data-v-b0783294>水表/流量计</option><option value="meter_cooling" data-v-b0783294>能量计</option><option value="other" data-v-b0783294>其它</option>',8)])],512),[[L,p.category]])]),e("div",al,[t[84]||(t[84]=e("label",null,"网关",-1)),r(e("select",{"onUpdate:modelValue":t[15]||(t[15]=l=>p.gatewayId=l)},[t[83]||(t[83]=e("option",{value:null},"无",-1)),(o(!0),a(S,null,T($.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,ol))),128))],512),[[L,p.gatewayId]])]),e("div",il,[t[85]||(t[85]=e("label",null,"界面绑定",-1)),r(e("input",{"onUpdate:modelValue":t[16]||(t[16]=l=>p.bindUi=l),placeholder:"cold / vav / …"},null,512),[[y,p.bindUi]])])]),d.value?(o(),a("p",ul,n(d.value),1)):v("",!0),e("div",dl,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:ke},n(I.value?"创建中…":"创建"),9,rl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):v("",!0),h.value==="createPoint"?(o(),a("div",{key:3,class:"modal-mask",onClick:N(f,["self"])},[e("div",vl,[e("div",{class:"panel-head"},[t[86]||(t[86]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增点位")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",ml,[e("div",bl,[t[87]||(t[87]=e("label",null,"名称",-1)),r(e("input",{"onUpdate:modelValue":t[17]||(t[17]=l=>u.name=l)},null,512),[[y,u.name]])]),e("div",pl,[t[88]||(t[88]=e("label",null,"网关",-1)),r(e("select",{"onUpdate:modelValue":t[18]||(t[18]=l=>u.gatewayId=l)},[(o(!0),a(S,null,T($.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,yl))),128))],512),[[L,u.gatewayId]])]),e("div",cl,[t[89]||(t[89]=e("label",null,"Modbus Address",-1)),r(e("input",{"onUpdate:modelValue":t[19]||(t[19]=l=>u.modbusAddress=l),type:"number"},null,512),[[y,u.modbusAddress,void 0,{number:!0}]])]),e("div",fl,[t[90]||(t[90]=e("label",null,"DataType",-1)),r(e("input",{"onUpdate:modelValue":t[20]||(t[20]=l=>u.dataType=l)},null,512),[[y,u.dataType]])]),e("div",gl,[t[91]||(t[91]=e("label",null,"Modbus ID",-1)),r(e("input",{"onUpdate:modelValue":t[21]||(t[21]=l=>u.modbusId=l),type:"number"},null,512),[[y,u.modbusId,void 0,{number:!0}]])]),e("div",kl,[t[92]||(t[92]=e("label",null,"ItemID",-1)),r(e("input",{"onUpdate:modelValue":t[22]||(t[22]=l=>u.itemId=l),placeholder:"可选"},null,512),[[y,u.itemId]])]),e("div",wl,[t[94]||(t[94]=e("label",null,"设备",-1)),r(e("select",{"onUpdate:modelValue":t[23]||(t[23]=l=>u.deviceId=l)},[t[93]||(t[93]=e("option",{value:null},"无",-1)),(o(!0),a(S,null,T(P.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,Il))),128))],512),[[L,u.deviceId]])]),e("div",Cl,[t[95]||(t[95]=e("label",null,"Scale 覆盖",-1)),r(e("input",{"onUpdate:modelValue":t[24]||(t[24]=l=>u.scaleOverride=l),type:"number",step:"any"},null,512),[[y,u.scaleOverride,void 0,{number:!0}]])]),e("div",hl,[t[96]||(t[96]=e("label",null,"告警下限",-1)),r(e("input",{"onUpdate:modelValue":t[25]||(t[25]=l=>u.alarmLow=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[y,u.alarmLow,void 0,{number:!0}]])]),e("div",Vl,[t[97]||(t[97]=e("label",null,"告警上限",-1)),r(e("input",{"onUpdate:modelValue":t[26]||(t[26]=l=>u.alarmHigh=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[y,u.alarmHigh,void 0,{number:!0}]])])]),d.value?(o(),a("p",Ul,n(d.value),1)):v("",!0),e("div",_l,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:ge},n(I.value?"创建中…":"创建"),9,Al),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):v("",!0),h.value==="editPoint"&&i.value?(o(),a("div",{key:4,class:"modal-mask",onClick:N(f,["self"])},[e("div",Sl,[e("div",{class:"panel-head"},[t[98]||(t[98]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"编辑点位")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",Dl,[e("div",$l,[t[99]||(t[99]=e("label",null,"名称",-1)),r(e("input",{"onUpdate:modelValue":t[27]||(t[27]=l=>i.value.name=l)},null,512),[[y,i.value.name]])]),e("div",Tl,[t[100]||(t[100]=e("label",null,"Modbus Address",-1)),r(e("input",{"onUpdate:modelValue":t[28]||(t[28]=l=>i.value.modbusAddress=l),type:"number"},null,512),[[y,i.value.modbusAddress,void 0,{number:!0}]])]),e("div",Nl,[t[101]||(t[101]=e("label",null,"DataType",-1)),r(e("input",{"onUpdate:modelValue":t[29]||(t[29]=l=>i.value.dataType=l)},null,512),[[y,i.value.dataType]])]),e("div",Ol,[t[102]||(t[102]=e("label",null,"Modbus ID",-1)),r(e("input",{"onUpdate:modelValue":t[30]||(t[30]=l=>i.value.modbusId=l),type:"number"},null,512),[[y,i.value.modbusId,void 0,{number:!0}]])]),e("div",Ll,[t[103]||(t[103]=e("label",null,"ItemID",-1)),r(e("input",{"onUpdate:modelValue":t[31]||(t[31]=l=>i.value.itemId=l)},null,512),[[y,i.value.itemId]])]),e("div",Pl,[t[104]||(t[104]=e("label",null,"Scale",-1)),r(e("input",{"onUpdate:modelValue":t[32]||(t[32]=l=>i.value.scale=l),type:"number",step:"any"},null,512),[[y,i.value.scale,void 0,{number:!0}]])]),e("div",El,[t[105]||(t[105]=e("label",null,"Scale 覆盖",-1)),r(e("input",{"onUpdate:modelValue":t[33]||(t[33]=l=>i.value.scaleOverride=l),type:"number",step:"any"},null,512),[[y,i.value.scaleOverride,void 0,{number:!0}]])]),e("div",Hl,[t[106]||(t[106]=e("label",null,"告警下限",-1)),r(e("input",{"onUpdate:modelValue":t[34]||(t[34]=l=>i.value.alarmLow=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[y,i.value.alarmLow,void 0,{number:!0}]])]),e("div",xl,[t[107]||(t[107]=e("label",null,"告警上限",-1)),r(e("input",{"onUpdate:modelValue":t[35]||(t[35]=l=>i.value.alarmHigh=l),type:"number",step:"any",placeholder:"空=不启用"},null,512),[[y,i.value.alarmHigh,void 0,{number:!0}]])]),e("div",Rl,[t[109]||(t[109]=e("label",null,"设备",-1)),r(e("select",{"onUpdate:modelValue":t[36]||(t[36]=l=>i.value.deviceId=l)},[t[108]||(t[108]=e("option",{value:null},"无",-1)),(o(!0),a(S,null,T(P.value,l=>(o(),a("option",{key:l.id,value:l.id},n(l.name),9,Ml))),128))],512),[[L,i.value.deviceId]])]),e("label",Fl,[r(e("input",{"onUpdate:modelValue":t[37]||(t[37]=l=>i.value.enabled=l),type:"checkbox"},null,512),[[re,i.value.enabled]]),t[110]||(t[110]=ve(" 启用采集",-1))])]),d.value?(o(),a("p",Gl,n(d.value),1)):v("",!0),e("div",Bl,[e("button",{class:"btn",type:"button",disabled:I.value,onClick:fe},n(I.value?"保存中…":"保存"),9,Kl),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):v("",!0)])}}}),ql=$e(Wl,[["__scopeId","data-v-b0783294"]]);export{ql as default};
.devices-page[data-v-b0783294]{min-height:0}.list-panel[data-v-b0783294]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden;gap:10px}.panel-title[data-v-b0783294]{gap:10px}.head-actions[data-v-b0783294]{display:flex;flex-wrap:wrap;align-items:center;gap:8px;justify-content:flex-end}.tab-row[data-v-b0783294],.filters[data-v-b0783294]{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}.field[data-v-b0783294]{display:flex;flex-direction:column;gap:4px;min-width:140px}.field label[data-v-b0783294]{font-size:12px;opacity:.75}.field input[data-v-b0783294],.field select[data-v-b0783294],.csv-area[data-v-b0783294]{background:#060c14a6;box-shadow:0 0 0 1px #3dbeff47 inset;border:none;color:inherit;border-radius:2px;padding:6px 8px}.csv-area[data-v-b0783294]{width:100%;min-height:160px;margin-top:4px;font-family:var(--digital-font),ui-monospace,monospace;font-size:12px}.filter-hint[data-v-b0783294]{font-size:12px;color:var(--panel-muted);margin-bottom:6px}.check[data-v-b0783294]{display:flex;align-items:center;gap:6px;font-size:13px;margin-bottom:4px}.table-wrap[data-v-b0783294]{flex:1;min-height:0;overflow:auto}.msg.ok[data-v-b0783294]{color:var(--ok);font-size:13px}.msg.err[data-v-b0783294]{color:#ffb0b0;font-size:13px}.hint[data-v-b0783294]{font-size:12px;opacity:.7;margin-top:10px}.mono[data-v-b0783294]{font-family:var(--digital-font),ui-monospace,monospace;font-size:11px;max-width:280px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ops[data-v-b0783294]{display:flex;gap:6px}.row-click[data-v-b0783294]{cursor:pointer}.row-click:hover td[data-v-b0783294]{background:#3dbeff1f}.device-meta[data-v-b0783294]{display:flex;flex-wrap:wrap;gap:10px 16px;margin-bottom:12px}.device-meta span[data-v-b0783294]{display:inline-flex;align-items:baseline;gap:6px;padding:4px 8px;border:1px solid var(--panel-border);border-radius:2px;background:#060c1473}.device-meta small[data-v-b0783294]{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--panel-muted)}.device-meta b[data-v-b0783294]{font-size:12px;font-weight:600;color:var(--panel-title)}.detail-table-wrap[data-v-b0783294]{max-height:min(68vh,720px);overflow:auto}.eng[data-v-b0783294]{font-family:var(--digital-font),ui-monospace,monospace;font-size:14px;font-weight:700;color:var(--accent)}.eng.muted[data-v-b0783294]{color:var(--panel-muted);font-weight:600}.ts[data-v-b0783294]{font-size:11px;color:var(--panel-muted)}.empty[data-v-b0783294]{text-align:center;color:var(--panel-muted);padding:28px 10px!important}.gw-status[data-v-b0783294]{margin-bottom:8px}.modal-mask[data-v-b0783294]{position:fixed;top:0;right:0;bottom:0;left:0;background:#04080eb8;display:flex;align-items:center;justify-content:center;z-index:50}.modal[data-v-b0783294]{width:min(640px,92vw);max-height:90vh;overflow:auto}.modal-lg[data-v-b0783294]{width:min(860px,96vw)}.modal-xl[data-v-b0783294]{width:min(1280px,98vw);max-height:92vh}.modal-actions[data-v-b0783294]{margin-top:14px;display:flex;gap:10px}.form-grid[data-v-b0783294]{display:grid;grid-template-columns:1fr 1fr;gap:10px}.write-cell[data-v-b0783294]{display:inline-flex;align-items:center;gap:6px;min-width:140px;white-space:nowrap}.ops[data-v-b0783294]{white-space:nowrap}.ops .btn[data-v-b0783294]{margin-right:4px}.write-input[data-v-b0783294]{width:88px;padding:4px 6px;border-radius:6px;border:1px solid rgba(255,255,255,.12);background:#00000040;color:inherit}.bool-on[data-v-b0783294],.bool-off[data-v-b0783294]{min-width:44px;padding:4px 10px}.muted[data-v-b0783294]{color:var(--panel-muted)}.msg.ok[data-v-b0783294]{color:#7dcea0}
.history-page[data-v-2bf42be6]{display:flex;min-height:0}.history-panel[data-v-2bf42be6]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.filters[data-v-2bf42be6]{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:end;padding:8px 4px 12px}.filters label[data-v-2bf42be6]{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--label, #8eb0c4)}.filters select[data-v-2bf42be6]{min-width:120px;height:30px;border-radius:4px;border:1px solid rgba(0,247,255,.25);background:#041428d9;color:#e8f6ff;padding:0 8px}.btn[data-v-2bf42be6]{height:30px;padding:0 14px;border-radius:4px;border:1px solid rgba(0,247,255,.35);background:#0078a059;color:#dff8ff;cursor:pointer}.btn[data-v-2bf42be6]:disabled{opacity:.5;cursor:default}.chart-box[data-v-2bf42be6]{flex:1;min-height:280px;border:1px solid rgba(0,247,255,.15);border-radius:6px;background:#04102066;padding:6px}.table-wrap[data-v-2bf42be6]{margin-top:10px;max-height:220px;overflow:auto}.muted[data-v-2bf42be6]{text-align:center;color:var(--label)}.err[data-v-2bf42be6]{color:#ffb0b0;font-size:12px;margin-bottom:8px}
import{d as $,q as M,j as D,c as u,b as t,t as s,g,e as y,L as h,F as k,z as V,f as S,D as q,r,B as w,l as F,o as i,_ as H}from"./index-Bs_x-_cK.js";import{E as O,m as P}from"./historyChart-DTdcyadg.js";const j={class:"page-fill history-page"},z={class:"panel history-panel"},R={class:"panel-head"},T={class:"badge"},A={class:"filters"},G=["value"],J=["value"],K=["value"],Q=["disabled"],W={key:0,class:"err"},X={class:"chart-box"},Y={class:"table-wrap"},Z={class:"table"},ee={key:0},te=$({__name:"HistoryView",setup(le){const d=r([]),c=r(!1),m=r(""),f=r(24),x=r(15),n=r(""),o=r(""),b=r(""),v=r([]),L=w(()=>{const a=new Map;for(const e of d.value)a.set(e.source,e.sourceLabel);return[...a.entries()].map(([e,l])=>({value:e,label:l}))}),U=w(()=>{const a=new Map;for(const e of d.value)n.value&&e.source!==n.value||a.set(e.metric,e.metricLabel);return[...a.entries()].map(([e,l])=>({value:e,label:l}))}),C=w(()=>d.value.filter(a=>(!n.value||a.source===n.value)&&(!o.value||a.metric===o.value)).map(a=>({value:a.deviceId,label:a.name,points:a.points}))),E=w(()=>P(v.value,{maxSeries:16,unit:o.value==="temp"||o.value.includes("temp")?"℃":o.value==="pressure"?"Pa":""})),B=w(()=>{const a=v.value.length,e=v.value.reduce((l,p)=>l+p.points.length,0);return`${a} 条序列 · ${e} 个聚合点 · 近 ${f.value}h`});async function I(){c.value=!0,m.value="";try{const a=await F("/api/realtime/history/catalog");d.value=a.catalog||[],!n.value&&d.value.length&&(n.value=d.value[0].source,o.value=d.value[0].metric)}catch(a){m.value=a instanceof Error?a.message:"目录加载失败"}finally{c.value=!1}}async function _(){if(!n.value||!o.value){v.value=[];return}c.value=!0,m.value="";try{const a=new URLSearchParams({source:n.value,metric:o.value,hours:String(f.value),bucketMinutes:String(x.value)});b.value&&a.set("deviceId",b.value);const e=await F(`/api/realtime/history?${a}`);v.value=e.series||[]}catch(a){m.value=a instanceof Error?a.message:"曲线加载失败",v.value=[]}finally{c.value=!1}}return M([n,o],()=>{b.value=""}),M([n,o,b,f,x],()=>{_()}),D(async()=>{await I(),await _()}),(a,e)=>(i(),u("div",j,[t("section",z,[t("div",R,[e[5]||(e[5]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"历史数据与曲线")],-1)),t("div",T,"时序预聚合 · "+s(B.value),1)]),t("div",A,[t("label",null,[e[6]||(e[6]=g(" 类别 ",-1)),y(t("select",{"onUpdate:modelValue":e[0]||(e[0]=l=>n.value=l)},[(i(!0),u(k,null,V(L.value,l=>(i(),u("option",{key:l.value,value:l.value},s(l.label),9,G))),128))],512),[[h,n.value]])]),t("label",null,[e[7]||(e[7]=g(" 指标 ",-1)),y(t("select",{"onUpdate:modelValue":e[1]||(e[1]=l=>o.value=l)},[(i(!0),u(k,null,V(U.value,l=>(i(),u("option",{key:l.value,value:l.value},s(l.label),9,J))),128))],512),[[h,o.value]])]),t("label",null,[e[9]||(e[9]=g(" 设备 ",-1)),y(t("select",{"onUpdate:modelValue":e[2]||(e[2]=l=>b.value=l)},[e[8]||(e[8]=t("option",{value:""},"全部设备",-1)),(i(!0),u(k,null,V(C.value,l=>(i(),u("option",{key:l.value,value:l.value},s(l.label)+" ("+s(l.points)+") ",9,K))),128))],512),[[h,b.value]])]),t("label",null,[e[11]||(e[11]=g(" 时长 ",-1)),y(t("select",{"onUpdate:modelValue":e[3]||(e[3]=l=>f.value=l)},[...e[10]||(e[10]=[t("option",{value:6},"近 6 小时",-1),t("option",{value:24},"近 24 小时",-1),t("option",{value:72},"近 3 天",-1),t("option",{value:168},"近 7 天",-1)])],512),[[h,f.value,void 0,{number:!0}]])]),t("label",null,[e[13]||(e[13]=g(" 粒度 ",-1)),y(t("select",{"onUpdate:modelValue":e[4]||(e[4]=l=>x.value=l)},[...e[12]||(e[12]=[t("option",{value:5},"5 分钟",-1),t("option",{value:15},"15 分钟",-1),t("option",{value:60},"1 小时",-1)])],512),[[h,x.value,void 0,{number:!0}]])]),t("button",{type:"button",class:"btn",disabled:c.value,onClick:_},"刷新",8,Q)]),m.value?(i(),u("div",W,s(m.value),1)):S("",!0),t("div",X,[q(O,{option:E.value,loading:c.value,"empty-text":"暂无该指标历史数据,采集后将自动出现"},null,8,["option","loading"])]),t("div",Y,[t("table",Z,[e[15]||(e[15]=t("thead",null,[t("tr",null,[t("th",null,"设备"),t("th",null,"点数"),t("th",null,"最新"),t("th",null,"最低"),t("th",null,"最高"),t("th",null,"平均")])],-1)),t("tbody",null,[(i(!0),u(k,null,V(v.value,l=>(i(),u("tr",{key:l.id},[t("td",null,s(l.name||l.id),1),t("td",null,s(l.points.length),1),t("td",null,s(l.points.length?l.points[l.points.length-1].v.toFixed(2):"—"),1),t("td",null,s(l.points.length?Math.min(...l.points.map(p=>p.v)).toFixed(2):"—"),1),t("td",null,s(l.points.length?Math.max(...l.points.map(p=>p.v)).toFixed(2):"—"),1),t("td",null,s(l.points.length?(l.points.reduce((p,N)=>p+N.v,0)/l.points.length).toFixed(2):"—"),1)]))),128)),v.value.length?S("",!0):(i(),u("tr",ee,[...e[14]||(e[14]=[t("td",{colspan:"6",class:"muted"},"无数据",-1)])]))])])])])]))}}),oe=H(te,[["__scopeId","data-v-c9fbd5ec"]]);export{oe as default};
import{d as P,j as A,k as F,l as O,c as r,b as e,t as a,h as n,g as f,e as b,P as x,F as w,x as V,f as C,H as T,r as v,s as M,p as H,o as c,_ as j}from"./index-BssDqbym.js";import{E as q,m as R}from"./historyChart-DJ1B6lTP.js";const $={class:"page-fill history-page"},z={class:"panel history-panel"},G={class:"panel-head"},J={class:"panel-title"},K={class:"badge"},Q={class:"filters"},W=["value"],X=["value"],Y={value:""},Z=["value"],ee={value:6},te={value:24},ae={value:72},se={value:168},le={value:5},oe={value:15},ne={value:60},ie=["disabled"],ue={key:0,class:"err"},re={class:"chart-box"},ce={class:"table-wrap"},ve={class:"table"},pe={key:0},de={colspan:"6",class:"muted"},he=P({__name:"HistoryView",setup(me){const{t:s}=A(),d=v([]),m=v(!1),g=v(""),_=v(24),k=v(15),i=v(""),u=v(""),y=v(""),p=v([]),D=M(()=>{const o=new Map;for(const l of d.value)o.set(l.source,l.sourceLabel);return[...o.entries()].map(([l,t])=>({value:l,label:t}))}),E=M(()=>{const o=new Map;for(const l of d.value)i.value&&l.source!==i.value||o.set(l.metric,l.metricLabel);return[...o.entries()].map(([l,t])=>({value:l,label:t}))}),L=M(()=>d.value.filter(o=>(!i.value||o.source===i.value)&&(!u.value||o.metric===u.value)).map(o=>({value:o.deviceId,label:o.name,points:o.points}))),U=M(()=>R(p.value,{maxSeries:16,unit:u.value==="temp"||u.value.includes("temp")?"℃":u.value==="pressure"?"Pa":""})),B=M(()=>{const o=p.value.length,l=p.value.reduce((t,h)=>t+h.points.length,0);return s("pages.historySummary",{n:o,pts:l,hours:_.value})});async function I(){m.value=!0,g.value="";try{const o=await H("/api/realtime/history/catalog");d.value=o.catalog||[],!i.value&&d.value.length&&(i.value=d.value[0].source,u.value=d.value[0].metric)}catch(o){g.value=o instanceof Error?o.message:s("pages.historyCatalogFail")}finally{m.value=!1}}async function S(){if(!i.value||!u.value){p.value=[];return}m.value=!0,g.value="";try{const o=new URLSearchParams({source:i.value,metric:u.value,hours:String(_.value),bucketMinutes:String(k.value)});y.value&&o.set("deviceId",y.value);const l=await H(`/api/realtime/history?${o}`);p.value=l.series||[]}catch(o){g.value=o instanceof Error?o.message:s("pages.historySeriesFail"),p.value=[]}finally{m.value=!1}}return F([i,u],()=>{y.value=""}),F([i,u,y,_,k],()=>{S()}),O(async()=>{await I(),await S()}),(o,l)=>(c(),r("div",$,[e("section",z,[e("div",G,[e("div",J,[l[5]||(l[5]=e("div",{class:"vbar"},null,-1)),e("h3",null,a(n(s)("pages.historyTitle")),1)]),e("div",K,a(n(s)("pages.historyBadge",{summary:B.value})),1)]),e("div",Q,[e("label",null,[f(a(n(s)("pages.historyCat"))+" ",1),b(e("select",{"onUpdate:modelValue":l[0]||(l[0]=t=>i.value=t)},[(c(!0),r(w,null,V(D.value,t=>(c(),r("option",{key:t.value,value:t.value},a(t.label),9,W))),128))],512),[[x,i.value]])]),e("label",null,[f(a(n(s)("pages.historyMetric"))+" ",1),b(e("select",{"onUpdate:modelValue":l[1]||(l[1]=t=>u.value=t)},[(c(!0),r(w,null,V(E.value,t=>(c(),r("option",{key:t.value,value:t.value},a(t.label),9,X))),128))],512),[[x,u.value]])]),e("label",null,[f(a(n(s)("pages.historyDevice"))+" ",1),b(e("select",{"onUpdate:modelValue":l[2]||(l[2]=t=>y.value=t)},[e("option",Y,a(n(s)("pages.historyAllDevices")),1),(c(!0),r(w,null,V(L.value,t=>(c(),r("option",{key:t.value,value:t.value},a(t.label)+" ("+a(t.points)+") ",9,Z))),128))],512),[[x,y.value]])]),e("label",null,[f(a(n(s)("pages.historyDuration"))+" ",1),b(e("select",{"onUpdate:modelValue":l[3]||(l[3]=t=>_.value=t)},[e("option",ee,a(n(s)("pages.historyH6")),1),e("option",te,a(n(s)("pages.historyH24")),1),e("option",ae,a(n(s)("pages.historyH72")),1),e("option",se,a(n(s)("pages.historyH168")),1)],512),[[x,_.value,void 0,{number:!0}]])]),e("label",null,[f(a(n(s)("pages.historyBucket"))+" ",1),b(e("select",{"onUpdate:modelValue":l[4]||(l[4]=t=>k.value=t)},[e("option",le,a(n(s)("pages.historyM5")),1),e("option",oe,a(n(s)("pages.historyM15")),1),e("option",ne,a(n(s)("pages.historyM60")),1)],512),[[x,k.value,void 0,{number:!0}]])]),e("button",{type:"button",class:"btn",disabled:m.value,onClick:S},a(n(s)("common.refresh")),9,ie)]),g.value?(c(),r("div",ue,a(g.value),1)):C("",!0),e("div",re,[T(q,{option:U.value,loading:m.value,"empty-text":n(s)("pages.historyEmpty")},null,8,["option","loading","empty-text"])]),e("div",ce,[e("table",ve,[e("thead",null,[e("tr",null,[e("th",null,a(n(s)("common.device")),1),e("th",null,a(n(s)("pages.historyPoints")),1),e("th",null,a(n(s)("pages.historyLatest")),1),e("th",null,a(n(s)("pages.historyMin")),1),e("th",null,a(n(s)("pages.historyMax")),1),e("th",null,a(n(s)("pages.historyAvg")),1)])]),e("tbody",null,[(c(!0),r(w,null,V(p.value,t=>(c(),r("tr",{key:t.id},[e("td",null,a(t.name||t.id),1),e("td",null,a(t.points.length),1),e("td",null,a(t.points.length?t.points[t.points.length-1].v.toFixed(2):"—"),1),e("td",null,a(t.points.length?Math.min(...t.points.map(h=>h.v)).toFixed(2):"—"),1),e("td",null,a(t.points.length?Math.max(...t.points.map(h=>h.v)).toFixed(2):"—"),1),e("td",null,a(t.points.length?(t.points.reduce((h,N)=>h+N.v,0)/t.points.length).toFixed(2):"—"),1)]))),128)),p.value.length?C("",!0):(c(),r("tr",pe,[e("td",de,a(n(s)("pages.historyNoData")),1)]))])])])])]))}}),_e=j(he,[["__scopeId","data-v-2bf42be6"]]);export{_e as default};
.history-page[data-v-c9fbd5ec]{display:flex;min-height:0}.history-panel[data-v-c9fbd5ec]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.filters[data-v-c9fbd5ec]{display:flex;flex-wrap:wrap;gap:10px 14px;align-items:end;padding:8px 4px 12px}.filters label[data-v-c9fbd5ec]{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--label, #8eb0c4)}.filters select[data-v-c9fbd5ec]{min-width:120px;height:30px;border-radius:4px;border:1px solid rgba(0,247,255,.25);background:#041428d9;color:#e8f6ff;padding:0 8px}.btn[data-v-c9fbd5ec]{height:30px;padding:0 14px;border-radius:4px;border:1px solid rgba(0,247,255,.35);background:#0078a059;color:#dff8ff;cursor:pointer}.btn[data-v-c9fbd5ec]:disabled{opacity:.5;cursor:default}.chart-box[data-v-c9fbd5ec]{flex:1;min-height:280px;border:1px solid rgba(0,247,255,.15);border-radius:6px;background:#04102066;padding:6px}.table-wrap[data-v-c9fbd5ec]{margin-top:10px;max-height:220px;overflow:auto}.muted[data-v-c9fbd5ec]{text-align:center;color:var(--label)}.err[data-v-c9fbd5ec]{color:#ffb0b0;font-size:12px;margin-bottom:8px}
import{d as x,j as P,u as A,c as T,b as s,t as a,h as e,H,n as S,e as w,v as k,r as E,s as p,p as V,o as C,_ as F}from"./index-BssDqbym.js";import{u as O}from"./realtime-lmP-Cubp.js";import{E as z,m as B}from"./historyChart-DJ1B6lTP.js";import{u as c}from"./useMetricHistory-CLFOMuUx.js";const N={class:"page-fill"},j={class:"panel"},D={class:"panel-head"},I={class:"panel-title"},L={class:"badge"},M={class:"metric-grid",style:{"grid-template-columns":"repeat(3, 1fr)"}},R={class:"metric"},U={class:"m-label"},J={class:"m-value"},q={class:"metric"},G={class:"m-label"},K={class:"m-value"},Q={class:"metric"},W={class:"m-label"},X={class:"m-value"},Y={class:"metric"},Z={class:"m-label"},$={class:"m-value"},ss={class:"metric"},es={class:"m-label"},ts={class:"m-value"},as={class:"metric"},is={class:"m-label"},ls={class:"m-value"},os={class:"hist"},ns={class:"chart-title"},ds={class:"panel"},cs={class:"panel-head"},ps={class:"panel-title"},us={class:"form-grid",style:{"max-width":"520px"}},rs={class:"field"},vs=["disabled"],ms={class:"field",style:{"justify-content":"flex-end"}},_s=["disabled"],hs=x({__name:"HvacView",setup(ys){const{t}=P(),o=A(),l=O(),d=E(180),{series:u,loading:r}=c(()=>({source:"hvac",metric:"supply_temp"})),{series:v,loading:m}=c(()=>({source:"hvac",metric:"supply_pressure"})),{series:_,loading:h}=c(()=>({source:"hvac",metric:"exhaust_pressure"})),y=p(()=>B([...u.value.map(n=>({...n,name:t("pau.supplyTemp")})),...v.value.map(n=>({...n,name:t("pau.supplyPressure")})),..._.value.map(n=>({...n,name:t("pau.exhaustPressure")}))],{maxSeries:6})),b=p(()=>r.value||m.value||h.value);async function f(){o.isAdmin&&(await V("/api/realtime/write",{method:"POST",token:o.token,body:JSON.stringify({target:"PAU201",action:"set_supply_pressure",value:d.value})}),alert(t("pages.hvacApplied")))}return(n,i)=>(C(),T("div",N,[s("section",j,[s("div",D,[s("div",I,[i[1]||(i[1]=s("div",{class:"vbar"},null,-1)),s("h3",null,a(e(t)("pages.hvacTitle")),1)]),s("div",L,a(e(l).snapshot.hvac.systemRunning?e(t)("screen.running"):e(t)("status.stopped")),1)]),s("div",M,[s("div",R,[s("div",null,[s("div",U,a(e(t)("pau.supplyTemp")),1),s("div",J,a(e(l).snapshot.hvac.supplyTemp.toFixed(1)),1)])]),s("div",q,[s("div",null,[s("div",G,a(e(t)("pau.supplyHumidity")),1),s("div",K,a(e(l).snapshot.hvac.supplyHumidity),1)])]),s("div",Q,[s("div",null,[s("div",W,a(e(t)("pau.supplyPressure")),1),s("div",X,a(e(l).snapshot.hvac.supplyPressure),1)])]),s("div",Y,[s("div",null,[s("div",Z,a(e(t)("pau.fanHz")),1),s("div",$,a(e(l).snapshot.hvac.supplyFanHz.toFixed(1)),1)])]),s("div",ss,[s("div",null,[s("div",es,a(e(t)("pau.exhaustPressure")),1),s("div",ts,a(e(l).snapshot.hvac.exhaustPressure),1)])]),s("div",as,[s("div",null,[s("div",is,a(e(t)("pau.freshAirTemp")),1),s("div",ls,a(e(l).snapshot.hvac.freshAirTemp.toFixed(1)),1)])])]),s("div",os,[s("div",ns,a(e(t)("pages.hvacHistTitle")),1),H(z,{option:y.value,loading:b.value,"empty-text":e(t)("pages.hvacEmpty")},null,8,["option","loading","empty-text"])])]),s("section",ds,[s("div",cs,[s("div",ps,[i[2]||(i[2]=s("div",{class:"vbar"},null,-1)),s("h3",null,a(e(t)("pages.hvacParams")),1)]),s("div",{class:S(["badge",e(o).isAdmin?"":"amber"])},a(e(o).isAdmin?e(t)("common.writable"):e(t)("common.readonly")),3)]),s("div",us,[s("div",rs,[s("label",null,a(e(t)("pages.hvacSetPressure")),1),w(s("input",{"onUpdate:modelValue":i[0]||(i[0]=g=>d.value=g),type:"number",disabled:!e(o).isAdmin},null,8,vs),[[k,d.value,void 0,{number:!0}]])]),s("div",ms,[i[3]||(i[3]=s("label",null," ",-1)),s("button",{class:"btn",disabled:!e(o).isAdmin,onClick:f},a(e(t)("pages.hvacApply")),9,_s)])])])]))}}),Ps=F(hs,[["__scopeId","data-v-868cf5e9"]]);export{Ps as default};
.hist[data-v-c796d554]{margin-top:12px;min-height:220px;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-c796d554]{font-size:12px;color:var(--label);margin-bottom:4px}.hist[data-v-c796d554] .echart-wrap{height:200px}
import{d as g,u as x,c as A,b as s,t as i,h as t,D as P,n as S,e as k,v as w,r as H,B as r,l as T,o as V,_ as B}from"./index-Bs_x-_cK.js";import{u as C}from"./realtime-CI_KLy_N.js";import{E,m as F}from"./historyChart-DTdcyadg.js";import{u as n}from"./useMetricHistory-Ck1zYYEr.js";const O={class:"page-fill"},D={class:"panel"},M={class:"panel-head"},N={class:"badge"},z={class:"metric-grid",style:{"grid-template-columns":"repeat(3, 1fr)"}},L={class:"metric"},R={class:"m-value"},U={class:"metric"},j={class:"m-value"},I={class:"metric"},J={class:"m-value"},q={class:"metric"},G={class:"m-value"},K={class:"metric"},Q={class:"m-value"},W={class:"metric"},X={class:"m-value"},Y={class:"hist"},Z={class:"panel"},$={class:"panel-head"},ss={class:"form-grid",style:{"max-width":"520px"}},es={class:"field"},ts=["disabled"],is={class:"field",style:{"justify-content":"flex-end"}},ls=["disabled"],as=g({__name:"HvacView",setup(os){const a=x(),l=C(),d=H(180),{series:u,loading:v}=n(()=>({source:"hvac",metric:"supply_temp"})),{series:c,loading:p}=n(()=>({source:"hvac",metric:"supply_pressure"})),{series:m,loading:_}=n(()=>({source:"hvac",metric:"exhaust_pressure"})),h=r(()=>F([...u.value.map(o=>({...o,name:"送风温度"})),...c.value.map(o=>({...o,name:"送风压力"})),...m.value.map(o=>({...o,name:"排风压力"}))],{maxSeries:6})),y=r(()=>v.value||p.value||_.value);async function b(){a.isAdmin&&(await T("/api/realtime/write",{method:"POST",token:a.token,body:JSON.stringify({target:"PAU201",action:"set_supply_pressure",value:d.value})}),alert("送风压力设定已下发(Mock)"))}return(o,e)=>(V(),A("div",O,[s("section",D,[s("div",M,[e[1]||(e[1]=s("div",{class:"panel-title"},[s("div",{class:"vbar"}),s("h3",null,"空调及排风机组")],-1)),s("div",N,i(t(l).snapshot.hvac.systemRunning?"运行":"停机"),1)]),s("div",z,[s("div",L,[s("div",null,[e[2]||(e[2]=s("div",{class:"m-label"},"送风温度",-1)),s("div",R,i(t(l).snapshot.hvac.supplyTemp.toFixed(1)),1)])]),s("div",U,[s("div",null,[e[3]||(e[3]=s("div",{class:"m-label"},"送风湿度",-1)),s("div",j,i(t(l).snapshot.hvac.supplyHumidity),1)])]),s("div",I,[s("div",null,[e[4]||(e[4]=s("div",{class:"m-label"},"送风压力",-1)),s("div",J,i(t(l).snapshot.hvac.supplyPressure),1)])]),s("div",q,[s("div",null,[e[5]||(e[5]=s("div",{class:"m-label"},"风机频率",-1)),s("div",G,i(t(l).snapshot.hvac.supplyFanHz.toFixed(1)),1)])]),s("div",K,[s("div",null,[e[6]||(e[6]=s("div",{class:"m-label"},"排风压力",-1)),s("div",Q,i(t(l).snapshot.hvac.exhaustPressure),1)])]),s("div",W,[s("div",null,[e[7]||(e[7]=s("div",{class:"m-label"},"新风温度",-1)),s("div",X,i(t(l).snapshot.hvac.freshAirTemp.toFixed(1)),1)])])]),s("div",Y,[e[8]||(e[8]=s("div",{class:"chart-title"},"近 24h 历史曲线",-1)),P(E,{option:h.value,loading:y.value,"empty-text":"机组历史积累中"},null,8,["option","loading"])])]),s("section",Z,[s("div",$,[e[9]||(e[9]=s("div",{class:"panel-title"},[s("div",{class:"vbar"}),s("h3",null,"参数设定")],-1)),s("div",{class:S(["badge",t(a).isAdmin?"":"amber"])},i(t(a).isAdmin?"管理员可写":"只读"),3)]),s("div",ss,[s("div",es,[e[10]||(e[10]=s("label",null,"送风压力设定 (Pa)",-1)),k(s("input",{"onUpdate:modelValue":e[0]||(e[0]=f=>d.value=f),type:"number",disabled:!t(a).isAdmin},null,8,ts),[[w,d.value,void 0,{number:!0}]])]),s("div",is,[e[11]||(e[11]=s("label",null," ",-1)),s("button",{class:"btn",disabled:!t(a).isAdmin,onClick:b},"下发设定",8,ls)])])])]))}}),vs=B(as,[["__scopeId","data-v-c796d554"]]);export{vs as default};
.hist[data-v-868cf5e9]{margin-top:12px;min-height:220px;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-868cf5e9]{font-size:12px;color:var(--label);margin-bottom:4px}.hist[data-v-868cf5e9] .echart-wrap{height:200px}
.light-page[data-v-8fd9846d]{gap:12px}.light-tabs[data-v-8fd9846d]{display:flex;align-items:center;gap:8px;flex:0 0 auto}.tab[data-v-8fd9846d]{border-radius:6px;border:1px solid rgba(62,200,255,.22);background:#122a4e66;color:var(--muted);padding:6px 14px;font-size:12px;cursor:pointer}.tab.active[data-v-8fd9846d]{background:linear-gradient(90deg,#1a6fff,#0aa6e5);color:#fff;border-color:transparent;font-weight:600}.tab-spacer[data-v-8fd9846d]{flex:1}.msg[data-v-8fd9846d]{font-size:12px;color:var(--cyan-lt)}.hint[data-v-8fd9846d]{font-size:12px;color:var(--label);line-height:1.6;margin-bottom:12px}.hint.inline[data-v-8fd9846d]{margin-bottom:0}.foot-hint[data-v-8fd9846d]{margin-top:10px;font-size:12px;color:var(--label)}.form-grid.three[data-v-8fd9846d]{grid-template-columns:repeat(3,1fr);max-width:1100px}.row-actions[data-v-8fd9846d]{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:14px}.head-right[data-v-8fd9846d]{display:flex;align-items:center;gap:8px}.switch-field .switch[data-v-8fd9846d]{display:flex;align-items:center;gap:8px;height:36px;color:var(--body);font-size:13px;cursor:pointer}.list-panel[data-v-8fd9846d],.config-panel[data-v-8fd9846d]{flex:1;min-height:0;display:flex;flex-direction:column}.table-wrap[data-v-8fd9846d]{flex:1;min-height:0;overflow:auto}.ops[data-v-8fd9846d]{display:flex;flex-wrap:wrap;gap:6px}.empty[data-v-8fd9846d]{text-align:center;color:var(--label);padding:24px!important}.muted[data-v-8fd9846d]{color:var(--label);font-size:11px}.st[data-v-8fd9846d],.pwr[data-v-8fd9846d]{display:inline-block;padding:1px 8px;border-radius:4px;font-size:11px}.st.online[data-v-8fd9846d]{background:#2fd6a126;color:var(--green)}.st.offline[data-v-8fd9846d]{background:#8eb4d41f;color:var(--muted)}.st.fault[data-v-8fd9846d]{background:#f0b4292e;color:var(--amber)}.pwr.on[data-v-8fd9846d]{background:#fbbf2433;color:#fbbf24}.pwr.off[data-v-8fd9846d]{background:#8eb4d41f;color:var(--muted)}.switch-btn.is-on[data-v-8fd9846d]{border-color:#fbbf248c;background:#fbbf2438;color:#ffe08a}.switch-btn.is-on[data-v-8fd9846d]:hover:not(:disabled){background:#fbbf2461}.switch-btn.is-off[data-v-8fd9846d]{border-color:#3ac8ff73;background:#1a6fff47;color:#eaf9ff}.switch-btn.is-off[data-v-8fd9846d]:hover:not(:disabled){background:#1a6fff73}
import{d as H,u as R,j,c as u,b as e,n as w,t as a,f as c,F as T,h as d,e as p,v as b,z as q,L as G,M as K,r as h,N as U,B as $,l as f,o as r,g as E,_ as Q}from"./index-Bs_x-_cK.js";const W={class:"page-fill light-page"},X={class:"light-tabs"},Y={class:"badge"},Z={class:"badge"},ee=["disabled"],te={key:0,class:"msg"},se={key:0,class:"panel"},le={class:"panel-head"},ne={class:"head-right"},oe=["disabled"],ie=["disabled"],ae={class:"form-grid three"},de={class:"field"},ue={class:"field"},re={class:"field"},ve={class:"field"},pe={class:"panel list-panel"},ce={class:"table-wrap"},be={class:"table"},me={class:"muted"},fe={class:"ops"},ge=["disabled","onClick"],he=["onClick"],ye=["onClick"],ke={key:0},we={key:1,class:"panel config-panel"},_e={class:"panel-head"},Ae={class:"form-grid three"},Ce={class:"field"},Me=["disabled"],Se={class:"field"},Te=["disabled"],Ve={class:"field"},Oe=["disabled"],Ue={class:"field"},$e=["disabled"],Ee={class:"field"},Pe=["disabled"],xe={class:"field"},Ie=["disabled"],Ne={class:"field"},ze=["disabled"],Be={class:"field switch-field"},De={class:"switch"},Le=["disabled"],Je={class:"row-actions"},Fe=["disabled"],He={key:2,class:"msg"},Re={key:3,class:"hint inline"},je=H({__name:"LightView",setup(qe){const o=R(),_=h("devices"),S=h(!1),g=h(""),i=h(""),m=h([]),A=h(null),M=h(!1),y=h(""),v=U({name:"",zone:"",circuit:9,remark:""}),n=U({host:"",port:502,protocol:"modbus",unitId:1,username:"",password:"",pollMs:3e3,enabled:!0}),P={online:"在线",offline:"离线",fault:"故障"},x=$(()=>m.value.filter(l=>l.enabled&&l.powerOn).length),I=$(()=>m.value.filter(l=>l.enabled&&l.status==="online").length);async function k(){S.value=!0,i.value="";try{const[l,t]=await Promise.all([f("/api/light/devices",{token:o.token}),f("/api/light/config",{token:o.token})]);m.value=l.devices,A.value=t,n.host=t.host,n.port=t.port,n.protocol=t.protocol,n.unitId=t.unitId,n.username=t.username,n.password=t.passwordMasked||"",n.pollMs=t.pollMs,n.enabled=t.enabled}catch(l){i.value=l instanceof Error?l.message:"加载失败"}finally{S.value=!1}}async function N(){if(o.isAdmin){i.value="";try{await f("/api/light/devices",{method:"POST",token:o.token,body:JSON.stringify(v)}),v.name="",v.zone="",v.remark="",v.circuit+=1,i.value="设备已添加",await k()}catch(l){i.value=l instanceof Error?l.message:"添加失败"}}}async function z(l){if(o.isAdmin){i.value="";try{await f(`/api/light/devices/${l.id}`,{method:"PATCH",token:o.token,body:JSON.stringify({enabled:!l.enabled})}),await k()}catch(t){i.value=t instanceof Error?t.message:"更新失败"}}}async function B(l){if(o.isAdmin&&confirm(`确认删除「${l.name}」?`)){i.value="";try{await f(`/api/light/devices/${l.id}`,{method:"DELETE",token:o.token}),i.value="已删除",await k()}catch(t){i.value=t instanceof Error?t.message:"删除失败"}}}async function D(l,t){if(o.isAdmin){g.value=l.id,i.value="";try{const s=await f(`/api/light/devices/${l.id}/switch`,{method:"POST",token:o.token,body:JSON.stringify({powerOn:t})});i.value=s.message;const C=m.value.findIndex(F=>F.id===l.id);C>=0?m.value[C]=s.device:await k()}catch(s){i.value=s instanceof Error?s.message:"开关失败"}finally{g.value=""}}}async function V(l){if(!(!o.isAdmin||!confirm(`确认远程${l?"全部开启":"全部关闭"}所有可用回路?`))){g.value="all",i.value="";try{const s=await f("/api/light/switch-all",{method:"POST",token:o.token,body:JSON.stringify({powerOn:l})});m.value=s.devices,i.value=s.message}catch(s){i.value=s instanceof Error?s.message:"批量开关失败"}finally{g.value=""}}}async function L(){if(o.isAdmin){i.value="",y.value="";try{const l={host:n.host,port:n.port,protocol:n.protocol,unitId:n.unitId,username:n.username,pollMs:n.pollMs,enabled:n.enabled};n.password&&n.password!=="********"&&(l.password=n.password);const t=await f("/api/light/config",{method:"PUT",token:o.token,body:JSON.stringify(l)});A.value=t,n.password=t.passwordMasked||"",i.value="通信配置已保存"}catch(l){i.value=l instanceof Error?l.message:"保存失败"}}}async function J(){if(o.isAdmin){M.value=!0,y.value="";try{const l=await f("/api/light/config/test",{method:"POST",token:o.token});y.value=`${l.message} · ${l.latencyMs} ms`,i.value=l.ok?"连通性测试通过":l.message}catch(l){y.value=l instanceof Error?l.message:"测试失败"}finally{M.value=!1}}}function O(l){return l?new Date(l).toLocaleString("zh-CN",{hour12:!1}):"—"}return j(k),(l,t)=>(r(),u("div",W,[e("div",X,[e("button",{type:"button",class:w(["tab",{active:_.value==="devices"}]),onClick:t[0]||(t[0]=s=>_.value="devices")}," 设备管理 ",2),e("button",{type:"button",class:w(["tab",{active:_.value==="config"}]),onClick:t[1]||(t[1]=s=>_.value="config")}," 通信配置 ",2),t[16]||(t[16]=e("div",{class:"tab-spacer"},null,-1)),e("div",Y,"开启 "+a(x.value),1),e("div",Z,"在线 "+a(I.value)+" / "+a(m.value.length),1),e("button",{type:"button",class:"btn ghost",disabled:S.value,onClick:k},"刷新",8,ee),i.value?(r(),u("span",te,a(i.value),1)):c("",!0)]),_.value==="devices"?(r(),u(T,{key:0},[d(o).isAdmin?(r(),u("section",se,[e("div",le,[t[17]||(t[17]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"添加照明回路")],-1)),e("div",ne,[e("button",{type:"button",class:"btn ghost",disabled:!!g.value,onClick:t[2]||(t[2]=s=>V(!0))}," 全部开启 ",8,oe),e("button",{type:"button",class:"btn ghost",disabled:!!g.value,onClick:t[3]||(t[3]=s=>V(!1))}," 全部关闭 ",8,ie)])]),e("div",ae,[e("div",de,[t[18]||(t[18]=e("label",null,"名称",-1)),p(e("input",{"onUpdate:modelValue":t[4]||(t[4]=s=>v.name=s),placeholder:"如:PCR走廊照明"},null,512),[[b,v.name]])]),e("div",ue,[t[19]||(t[19]=e("label",null,"区域",-1)),p(e("input",{"onUpdate:modelValue":t[5]||(t[5]=s=>v.zone=s),placeholder:"房间/分区"},null,512),[[b,v.zone]])]),e("div",re,[t[20]||(t[20]=e("label",null,"回路号",-1)),p(e("input",{"onUpdate:modelValue":t[6]||(t[6]=s=>v.circuit=s),type:"number",min:"1",max:"256"},null,512),[[b,v.circuit,void 0,{number:!0}]])]),e("div",ve,[t[21]||(t[21]=e("label",null,"备注",-1)),p(e("input",{"onUpdate:modelValue":t[7]||(t[7]=s=>v.remark=s)},null,512),[[b,v.remark]])])]),e("div",{class:"row-actions"},[e("button",{type:"button",class:"btn",onClick:N},"添加")])])):c("",!0),e("section",pe,[t[24]||(t[24]=e("div",{class:"panel-head"},[e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"照明设备列表")]),e("div",{class:"badge amber"},"厂家接口 · Mock")],-1)),e("div",ce,[e("table",be,[t[23]||(t[23]=e("thead",null,[e("tr",null,[e("th",null,"回路"),e("th",null,"名称"),e("th",null,"区域"),e("th",null,"开关"),e("th",null,"亮度"),e("th",null,"状态"),e("th",null,"启用"),e("th",null,"最近控制"),e("th",null,"操作")])],-1)),e("tbody",null,[(r(!0),u(T,null,q(m.value,s=>(r(),u("tr",{key:s.id},[e("td",null,a(s.circuit),1),e("td",null,a(s.name),1),e("td",null,a(s.zone),1),e("td",null,[e("span",{class:w(["pwr",s.powerOn?"on":"off"])},a(s.powerOn?"开":"关"),3)]),e("td",null,a(s.brightness)+"%",1),e("td",null,[e("span",{class:w(["st",s.status])},a(P[s.status]),3)]),e("td",null,a(s.enabled?"是":"否"),1),e("td",me,[E(a(O(s.lastSwitchAt))+" ",1),s.lastSwitchBy?(r(),u(T,{key:0},[E(" · "+a(s.lastSwitchBy),1)],64)):c("",!0)]),e("td",fe,[e("button",{type:"button",class:w(["btn switch-btn",s.powerOn?"is-on":"is-off"]),disabled:!d(o).isAdmin||!s.enabled||s.status==="offline"||g.value===s.id,onClick:C=>D(s,!s.powerOn)},a(g.value===s.id?"下发中…":s.powerOn?"远程关灯":"远程开灯"),11,ge),d(o).isAdmin?(r(),u("button",{key:0,type:"button",class:"btn ghost",onClick:C=>z(s)},a(s.enabled?"禁用":"启用"),9,he)):c("",!0),d(o).isAdmin?(r(),u("button",{key:1,type:"button",class:"btn danger",onClick:C=>B(s)}," 删除 ",8,ye)):c("",!0)])]))),128)),m.value.length?c("",!0):(r(),u("tr",ke,[...t[22]||(t[22]=[e("td",{colspan:"9",class:"empty"},"暂无照明设备",-1)])]))])])]),t[25]||(t[25]=e("p",{class:"foot-hint"}," 厂家提供数据调用接口,本页负责显示集成与远程开关。一期为 Mock 落库;二期对接照明网关后实时同步。 ",-1))])],64)):(r(),u("section",we,[e("div",_e,[t[26]||(t[26]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"照明通信配置")],-1)),e("div",{class:w(["badge",d(o).isAdmin?"":"amber"])},a(d(o).isAdmin?"可编辑":"只读"),3)]),t[36]||(t[36]=e("p",{class:"hint"}," 对接厂家智能照明网关(Modbus / HTTP / TCP)。配置保存后可用于远程开关下发。 ",-1)),e("div",Ae,[e("div",Ce,[t[27]||(t[27]=e("label",null,"网关地址",-1)),p(e("input",{"onUpdate:modelValue":t[8]||(t[8]=s=>n.host=s),disabled:!d(o).isAdmin,placeholder:"192.168.x.x"},null,8,Me),[[b,n.host]])]),e("div",Se,[t[28]||(t[28]=e("label",null,"端口",-1)),p(e("input",{"onUpdate:modelValue":t[9]||(t[9]=s=>n.port=s),type:"number",disabled:!d(o).isAdmin},null,8,Te),[[b,n.port,void 0,{number:!0}]])]),e("div",Ve,[t[30]||(t[30]=e("label",null,"协议",-1)),p(e("select",{"onUpdate:modelValue":t[10]||(t[10]=s=>n.protocol=s),disabled:!d(o).isAdmin},[...t[29]||(t[29]=[e("option",{value:"modbus"},"Modbus TCP",-1),e("option",{value:"http"},"HTTP",-1),e("option",{value:"tcp"},"TCP",-1)])],8,Oe),[[G,n.protocol]])]),e("div",Ue,[t[31]||(t[31]=e("label",null,"从站地址 (Unit ID)",-1)),p(e("input",{"onUpdate:modelValue":t[11]||(t[11]=s=>n.unitId=s),type:"number",disabled:!d(o).isAdmin},null,8,$e),[[b,n.unitId,void 0,{number:!0}]])]),e("div",Ee,[t[32]||(t[32]=e("label",null,"用户名(可选)",-1)),p(e("input",{"onUpdate:modelValue":t[12]||(t[12]=s=>n.username=s),disabled:!d(o).isAdmin},null,8,Pe),[[b,n.username]])]),e("div",xe,[t[33]||(t[33]=e("label",null,"密码(可选)",-1)),p(e("input",{"onUpdate:modelValue":t[13]||(t[13]=s=>n.password=s),type:"password",disabled:!d(o).isAdmin,placeholder:"********",autocomplete:"new-password"},null,8,Ie),[[b,n.password]])]),e("div",Ne,[t[34]||(t[34]=e("label",null,"状态轮询 (ms)",-1)),p(e("input",{"onUpdate:modelValue":t[14]||(t[14]=s=>n.pollMs=s),type:"number",disabled:!d(o).isAdmin},null,8,ze),[[b,n.pollMs,void 0,{number:!0}]])]),e("div",Be,[t[35]||(t[35]=e("label",null,"启用通信",-1)),e("label",De,[p(e("input",{"onUpdate:modelValue":t[15]||(t[15]=s=>n.enabled=s),type:"checkbox",disabled:!d(o).isAdmin},null,8,Le),[[K,n.enabled]]),e("span",null,a(n.enabled?"已启用":"已关闭"),1)])])]),e("div",Je,[d(o).isAdmin?(r(),u("button",{key:0,type:"button",class:"btn",onClick:L},"保存配置")):c("",!0),d(o).isAdmin?(r(),u("button",{key:1,type:"button",class:"btn ghost",disabled:M.value,onClick:J},a(M.value?"测试中…":"测试连通性"),9,Fe)):c("",!0),y.value?(r(),u("span",He,a(y.value),1)):c("",!0),A.value?(r(),u("span",Re," 最近更新:"+a(O(A.value.updatedAt))+" · "+a(A.value.updatedBy),1)):c("",!0)])]))]))}}),Ke=Q(je,[["__scopeId","data-v-1e4e582a"]]);export{Ke as default};
import{d as R,j,u as Q,l as Z,c,b as t,n as w,t as n,h as l,f as g,F as V,e as p,v,x as q,P as G,Q as K,r as _,R as U,s as M,p as b,g as x,o as r,_ as W}from"./index-BssDqbym.js";import{f as X}from"./t-ChxyHC3f.js";const Y={class:"page-fill light-page"},tt={class:"light-tabs"},et={class:"badge"},lt={class:"badge"},st=["disabled"],it={key:0,class:"msg"},nt={key:0,class:"panel"},ot={class:"panel-head"},at={class:"panel-title"},dt={class:"head-right"},ut=["disabled"],ct=["disabled"],rt={class:"form-grid three"},ht={class:"field"},pt=["placeholder"],gt={class:"field"},vt=["placeholder"],mt={class:"field"},bt={class:"field"},ft={class:"row-actions"},_t={class:"panel list-panel"},yt={class:"panel-head"},kt={class:"panel-title"},wt={class:"badge amber"},At={class:"table-wrap"},Ct={class:"table"},Ot={class:"muted"},Tt={class:"ops"},St=["disabled","onClick"],Vt=["onClick"],Mt=["onClick"],Et={key:0},Pt={colspan:"9",class:"empty"},Ut={class:"foot-hint"},xt={key:1,class:"panel config-panel"},$t={class:"panel-head"},Ft={class:"panel-title"},It={class:"hint"},Nt={class:"form-grid three"},zt={class:"field"},Bt=["disabled"],Dt={class:"field"},Lt=["disabled"],Jt={class:"field"},Ht=["disabled"],Rt={class:"field"},jt=["disabled"],Qt={class:"field"},Zt=["disabled"],qt={class:"field"},Gt=["disabled"],Kt={class:"field"},Wt=["disabled"],Xt={class:"field switch-field"},Yt={class:"switch"},te=["disabled"],ee={class:"row-actions"},le=["disabled"],se={key:2,class:"msg"},ie={key:3,class:"hint inline"},ne=R({__name:"LightView",setup(oe){const{t:e}=j(),d=Q(),A=_("devices"),S=_(!1),f=_(""),u=_(""),m=_([]),C=_(null),T=_(!1),y=_(""),h=U({name:"",zone:"",circuit:9,remark:""}),a=U({host:"",port:502,protocol:"modbus",unitId:1,username:"",password:"",pollMs:3e3,enabled:!0}),$=M(()=>({online:e("status.online"),offline:e("status.offline"),fault:e("light.fault")})),F=M(()=>m.value.filter(o=>o.enabled&&o.powerOn).length),I=M(()=>m.value.filter(o=>o.enabled&&o.status==="online").length);async function k(){S.value=!0,u.value="";try{const[o,s]=await Promise.all([b("/api/light/devices",{token:d.token}),b("/api/light/config",{token:d.token})]);m.value=o.devices,C.value=s,a.host=s.host,a.port=s.port,a.protocol=s.protocol,a.unitId=s.unitId,a.username=s.username,a.password=s.passwordMasked||"",a.pollMs=s.pollMs,a.enabled=s.enabled}catch(o){u.value=o instanceof Error?o.message:e("light.loadFail")}finally{S.value=!1}}async function N(){if(d.isAdmin){u.value="";try{await b("/api/light/devices",{method:"POST",token:d.token,body:JSON.stringify(h)}),h.name="",h.zone="",h.remark="",h.circuit+=1,u.value=e("light.added"),await k()}catch(o){u.value=o instanceof Error?o.message:e("light.addFail")}}}async function z(o){if(d.isAdmin){u.value="";try{await b(`/api/light/devices/${o.id}`,{method:"PATCH",token:d.token,body:JSON.stringify({enabled:!o.enabled})}),await k()}catch(s){u.value=s instanceof Error?s.message:e("light.updateFail")}}}async function B(o){if(d.isAdmin&&confirm(e("light.confirmDelete",{name:o.name}))){u.value="";try{await b(`/api/light/devices/${o.id}`,{method:"DELETE",token:d.token}),u.value=e("light.deleted"),await k()}catch(s){u.value=s instanceof Error?s.message:e("light.deleteFail")}}}async function D(o,s){if(d.isAdmin){f.value=o.id,u.value="";try{const i=await b(`/api/light/devices/${o.id}/switch`,{method:"POST",token:d.token,body:JSON.stringify({powerOn:s})});u.value=i.message;const O=m.value.findIndex(H=>H.id===o.id);O>=0?m.value[O]=i.device:await k()}catch(i){u.value=i instanceof Error?i.message:e("light.switchFail")}finally{f.value=""}}}async function E(o){if(!d.isAdmin)return;const s=e(o?"light.allOn":"light.allOff");if(confirm(e("light.confirmAll",{tip:s}))){f.value="all",u.value="";try{const i=await b("/api/light/switch-all",{method:"POST",token:d.token,body:JSON.stringify({powerOn:o})});m.value=i.devices,u.value=i.message}catch(i){u.value=i instanceof Error?i.message:e("light.batchFail")}finally{f.value=""}}}async function L(){if(d.isAdmin){u.value="",y.value="";try{const o={host:a.host,port:a.port,protocol:a.protocol,unitId:a.unitId,username:a.username,pollMs:a.pollMs,enabled:a.enabled};a.password&&a.password!=="********"&&(o.password=a.password);const s=await b("/api/light/config",{method:"PUT",token:d.token,body:JSON.stringify(o)});C.value=s,a.password=s.passwordMasked||"",u.value=e("light.saved")}catch(o){u.value=o instanceof Error?o.message:e("light.saveFail")}}}async function J(){if(d.isAdmin){T.value=!0,y.value="";try{const o=await b("/api/light/config/test",{method:"POST",token:d.token});y.value=`${o.message} · ${o.latencyMs} ms`,u.value=o.ok?e("light.testOk"):o.message}catch(o){y.value=o instanceof Error?o.message:e("light.testFail")}finally{T.value=!1}}}function P(o){return X(o)}return Z(k),(o,s)=>(r(),c("div",Y,[t("div",tt,[t("button",{type:"button",class:w(["tab",{active:A.value==="devices"}]),onClick:s[0]||(s[0]=i=>A.value="devices")},n(l(e)("light.tabDevices")),3),t("button",{type:"button",class:w(["tab",{active:A.value==="config"}]),onClick:s[1]||(s[1]=i=>A.value="config")},n(l(e)("light.tabConfig")),3),s[16]||(s[16]=t("div",{class:"tab-spacer"},null,-1)),t("div",et,n(l(e)("light.onCount",{n:F.value})),1),t("div",lt,n(l(e)("light.onlineCount",{n:I.value,total:m.value.length})),1),t("button",{type:"button",class:"btn ghost",disabled:S.value,onClick:k},n(l(e)("common.refresh")),9,st),u.value?(r(),c("span",it,n(u.value),1)):g("",!0)]),A.value==="devices"?(r(),c(V,{key:0},[l(d).isAdmin?(r(),c("section",nt,[t("div",ot,[t("div",at,[s[17]||(s[17]=t("div",{class:"vbar"},null,-1)),t("h3",null,n(l(e)("light.addTitle")),1)]),t("div",dt,[t("button",{type:"button",class:"btn ghost",disabled:!!f.value,onClick:s[2]||(s[2]=i=>E(!0))},n(l(e)("light.allOn")),9,ut),t("button",{type:"button",class:"btn ghost",disabled:!!f.value,onClick:s[3]||(s[3]=i=>E(!1))},n(l(e)("light.allOff")),9,ct)])]),t("div",rt,[t("div",ht,[t("label",null,n(l(e)("light.name")),1),p(t("input",{"onUpdate:modelValue":s[4]||(s[4]=i=>h.name=i),placeholder:l(e)("light.namePh")},null,8,pt),[[v,h.name]])]),t("div",gt,[t("label",null,n(l(e)("light.zone")),1),p(t("input",{"onUpdate:modelValue":s[5]||(s[5]=i=>h.zone=i),placeholder:l(e)("light.zonePh")},null,8,vt),[[v,h.zone]])]),t("div",mt,[t("label",null,n(l(e)("light.circuit")),1),p(t("input",{"onUpdate:modelValue":s[6]||(s[6]=i=>h.circuit=i),type:"number",min:"1",max:"256"},null,512),[[v,h.circuit,void 0,{number:!0}]])]),t("div",bt,[t("label",null,n(l(e)("light.remark")),1),p(t("input",{"onUpdate:modelValue":s[7]||(s[7]=i=>h.remark=i)},null,512),[[v,h.remark]])])]),t("div",ft,[t("button",{type:"button",class:"btn",onClick:N},n(l(e)("light.add")),1)])])):g("",!0),t("section",_t,[t("div",yt,[t("div",kt,[s[18]||(s[18]=t("div",{class:"vbar"},null,-1)),t("h3",null,n(l(e)("light.listTitle")),1)]),t("div",wt,n(l(e)("light.mockBadge")),1)]),t("div",At,[t("table",Ct,[t("thead",null,[t("tr",null,[t("th",null,n(l(e)("light.colCircuit")),1),t("th",null,n(l(e)("light.colName")),1),t("th",null,n(l(e)("light.colZone")),1),t("th",null,n(l(e)("light.colPower")),1),t("th",null,n(l(e)("light.colBrightness")),1),t("th",null,n(l(e)("light.colStatus")),1),t("th",null,n(l(e)("light.colEnabled")),1),t("th",null,n(l(e)("light.colLast")),1),t("th",null,n(l(e)("light.colAction")),1)])]),t("tbody",null,[(r(!0),c(V,null,q(m.value,i=>(r(),c("tr",{key:i.id},[t("td",null,n(i.circuit),1),t("td",null,n(i.name),1),t("td",null,n(i.zone),1),t("td",null,[t("span",{class:w(["pwr",i.powerOn?"on":"off"])},n(i.powerOn?l(e)("screen.switchOn"):l(e)("screen.switchOff")),3)]),t("td",null,n(i.brightness)+"%",1),t("td",null,[t("span",{class:w(["st",i.status])},n($.value[i.status]),3)]),t("td",null,n(i.enabled?l(e)("common.yes"):l(e)("common.no")),1),t("td",Ot,[x(n(P(i.lastSwitchAt))+" ",1),i.lastSwitchBy?(r(),c(V,{key:0},[x(" · "+n(i.lastSwitchBy),1)],64)):g("",!0)]),t("td",Tt,[t("button",{type:"button",class:w(["btn switch-btn",i.powerOn?"is-on":"is-off"]),disabled:!l(d).isAdmin||!i.enabled||i.status==="offline"||f.value===i.id,onClick:O=>D(i,!i.powerOn)},n(f.value===i.id?l(e)("light.sending"):i.powerOn?l(e)("light.remoteOff"):l(e)("light.remoteOn")),11,St),l(d).isAdmin?(r(),c("button",{key:0,type:"button",class:"btn ghost",onClick:O=>z(i)},n(i.enabled?l(e)("light.disable"):l(e)("light.enable")),9,Vt)):g("",!0),l(d).isAdmin?(r(),c("button",{key:1,type:"button",class:"btn danger",onClick:O=>B(i)},n(l(e)("light.remove")),9,Mt)):g("",!0)])]))),128)),m.value.length?g("",!0):(r(),c("tr",Et,[t("td",Pt,n(l(e)("light.empty")),1)]))])])]),t("p",Ut,n(l(e)("light.foot")),1)])],64)):(r(),c("section",xt,[t("div",$t,[t("div",Ft,[s[19]||(s[19]=t("div",{class:"vbar"},null,-1)),t("h3",null,n(l(e)("light.configTitle")),1)]),t("div",{class:w(["badge",l(d).isAdmin?"":"amber"])},n(l(d).isAdmin?l(e)("light.editable"):l(e)("light.readonly")),3)]),t("p",It,n(l(e)("light.configHint")),1),t("div",Nt,[t("div",zt,[t("label",null,n(l(e)("light.host")),1),p(t("input",{"onUpdate:modelValue":s[8]||(s[8]=i=>a.host=i),disabled:!l(d).isAdmin,placeholder:"192.168.x.x"},null,8,Bt),[[v,a.host]])]),t("div",Dt,[t("label",null,n(l(e)("light.port")),1),p(t("input",{"onUpdate:modelValue":s[9]||(s[9]=i=>a.port=i),type:"number",disabled:!l(d).isAdmin},null,8,Lt),[[v,a.port,void 0,{number:!0}]])]),t("div",Jt,[t("label",null,n(l(e)("light.protocol")),1),p(t("select",{"onUpdate:modelValue":s[10]||(s[10]=i=>a.protocol=i),disabled:!l(d).isAdmin},[...s[20]||(s[20]=[t("option",{value:"modbus"},"Modbus TCP",-1),t("option",{value:"http"},"HTTP",-1),t("option",{value:"tcp"},"TCP",-1)])],8,Ht),[[G,a.protocol]])]),t("div",Rt,[t("label",null,n(l(e)("light.unitId")),1),p(t("input",{"onUpdate:modelValue":s[11]||(s[11]=i=>a.unitId=i),type:"number",disabled:!l(d).isAdmin},null,8,jt),[[v,a.unitId,void 0,{number:!0}]])]),t("div",Qt,[t("label",null,n(l(e)("light.username")),1),p(t("input",{"onUpdate:modelValue":s[12]||(s[12]=i=>a.username=i),disabled:!l(d).isAdmin},null,8,Zt),[[v,a.username]])]),t("div",qt,[t("label",null,n(l(e)("light.password")),1),p(t("input",{"onUpdate:modelValue":s[13]||(s[13]=i=>a.password=i),type:"password",disabled:!l(d).isAdmin,placeholder:"********",autocomplete:"new-password"},null,8,Gt),[[v,a.password]])]),t("div",Kt,[t("label",null,n(l(e)("light.pollMs")),1),p(t("input",{"onUpdate:modelValue":s[14]||(s[14]=i=>a.pollMs=i),type:"number",disabled:!l(d).isAdmin},null,8,Wt),[[v,a.pollMs,void 0,{number:!0}]])]),t("div",Xt,[t("label",null,n(l(e)("light.enableComm")),1),t("label",Yt,[p(t("input",{"onUpdate:modelValue":s[15]||(s[15]=i=>a.enabled=i),type:"checkbox",disabled:!l(d).isAdmin},null,8,te),[[K,a.enabled]]),t("span",null,n(a.enabled?l(e)("light.enabled"):l(e)("light.disabled")),1)])])]),t("div",ee,[l(d).isAdmin?(r(),c("button",{key:0,type:"button",class:"btn",onClick:L},n(l(e)("light.save")),1)):g("",!0),l(d).isAdmin?(r(),c("button",{key:1,type:"button",class:"btn ghost",disabled:T.value,onClick:J},n(T.value?l(e)("light.testing"):l(e)("light.test")),9,le)):g("",!0),y.value?(r(),c("span",se,n(y.value),1)):g("",!0),C.value?(r(),c("span",ie,n(l(e)("light.lastUpdate",{time:P(C.value.updatedAt),by:C.value.updatedBy})),1)):g("",!0)])]))]))}}),ue=W(ne,[["__scopeId","data-v-8fd9846d"]]);export{ue as default};
.light-page[data-v-1e4e582a]{gap:12px}.light-tabs[data-v-1e4e582a]{display:flex;align-items:center;gap:8px;flex:0 0 auto}.tab[data-v-1e4e582a]{border-radius:6px;border:1px solid rgba(62,200,255,.22);background:#122a4e66;color:var(--muted);padding:6px 14px;font-size:12px;cursor:pointer}.tab.active[data-v-1e4e582a]{background:linear-gradient(90deg,#1a6fff,#0aa6e5);color:#fff;border-color:transparent;font-weight:600}.tab-spacer[data-v-1e4e582a]{flex:1}.msg[data-v-1e4e582a]{font-size:12px;color:var(--cyan-lt)}.hint[data-v-1e4e582a]{font-size:12px;color:var(--label);line-height:1.6;margin-bottom:12px}.hint.inline[data-v-1e4e582a]{margin-bottom:0}.foot-hint[data-v-1e4e582a]{margin-top:10px;font-size:12px;color:var(--label)}.form-grid.three[data-v-1e4e582a]{grid-template-columns:repeat(3,1fr);max-width:1100px}.row-actions[data-v-1e4e582a]{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:14px}.head-right[data-v-1e4e582a]{display:flex;align-items:center;gap:8px}.switch-field .switch[data-v-1e4e582a]{display:flex;align-items:center;gap:8px;height:36px;color:var(--body);font-size:13px;cursor:pointer}.list-panel[data-v-1e4e582a],.config-panel[data-v-1e4e582a]{flex:1;min-height:0;display:flex;flex-direction:column}.table-wrap[data-v-1e4e582a]{flex:1;min-height:0;overflow:auto}.ops[data-v-1e4e582a]{display:flex;flex-wrap:wrap;gap:6px}.empty[data-v-1e4e582a]{text-align:center;color:var(--label);padding:24px!important}.muted[data-v-1e4e582a]{color:var(--label);font-size:11px}.st[data-v-1e4e582a],.pwr[data-v-1e4e582a]{display:inline-block;padding:1px 8px;border-radius:4px;font-size:11px}.st.online[data-v-1e4e582a]{background:#2fd6a126;color:var(--green)}.st.offline[data-v-1e4e582a]{background:#8eb4d41f;color:var(--muted)}.st.fault[data-v-1e4e582a]{background:#f0b4292e;color:var(--amber)}.pwr.on[data-v-1e4e582a]{background:#fbbf2433;color:#fbbf24}.pwr.off[data-v-1e4e582a]{background:#8eb4d41f;color:var(--muted)}.switch-btn.is-on[data-v-1e4e582a]{border-color:#fbbf248c;background:#fbbf2438;color:#ffe08a}.switch-btn.is-on[data-v-1e4e582a]:hover:not(:disabled){background:#fbbf2461}.switch-btn.is-off[data-v-1e4e582a]{border-color:#3ac8ff73;background:#1a6fff47;color:#eaf9ff}.switch-btn.is-off[data-v-1e4e582a]:hover:not(:disabled){background:#1a6fff73}
import{d as b,u as y,c as p,a as V,b as t,w as k,n as A,e as v,v as _,t as g,f as C,g as m,h as q,i as x,r as o,o as f,A as N}from"./index-Bs_x-_cK.js";const S={class:"tops-login"},h={class:"tops-login__stage"},B={class:"tops-login__field"},R={class:"tops-login__field"},T={key:0,class:"tops-login__error",role:"alert"},z=["disabled"],L=b({__name:"LoginView",setup(D){const c=y(),l=x(),r=o("admin"),u=o("Admin@123"),i=o(""),a=o(!1),d=o(!1);async function w(){i.value="",a.value=!0;try{await c.login(r.value.trim(),u.value);const e=typeof l.currentRoute.value.query.redirect=="string"?l.currentRoute.value.query.redirect:"/admin";await l.push(e.startsWith("/")?e:"/admin")}catch(e){i.value=e instanceof N?e.message:"登录失败",d.value=!0,window.setTimeout(()=>{d.value=!1},480)}finally{a.value=!1}}return(e,s)=>(f(),p("div",S,[s[10]||(s[10]=V('<div class="tops-login__atmosphere" aria-hidden="true"><div class="tops-login__grid"></div><div class="tops-login__glow tops-login__glow--a"></div><div class="tops-login__glow tops-login__glow--b"></div><div class="tops-login__horizon"></div></div>',1)),t("div",h,[s[6]||(s[6]=t("div",{class:"tops-login__mark"},"JH",-1)),s[7]||(s[7]=t("h1",{class:"tops-login__title"},"分子实验室三维可视化管理平台",-1)),s[8]||(s[8]=t("p",{class:"tops-login__tagline"},"Lab Intelligent Control",-1)),s[9]||(s[9]=t("p",{class:"tops-login__support"},"登录进入管理后台;大屏无需登录即可查看实时态势。",-1)),t("form",{class:A(["tops-login__form",{"is-shake":d.value}]),onSubmit:k(w,["prevent"])},[t("label",B,[s[3]||(s[3]=t("span",null,"用户名",-1)),v(t("input",{"onUpdate:modelValue":s[0]||(s[0]=n=>r.value=n),autocomplete:"username",required:""},null,512),[[_,r.value]])]),t("label",R,[s[4]||(s[4]=t("span",null,"密码",-1)),v(t("input",{"onUpdate:modelValue":s[1]||(s[1]=n=>u.value=n),type:"password",autocomplete:"current-password",required:""},null,512),[[_,u.value]])]),i.value?(f(),p("p",T,g(i.value),1)):C("",!0),t("button",{class:"tops-login__submit",type:"submit",disabled:a.value},[t("span",null,g(a.value?"登录中…":"进入后台"),1)],8,z),s[5]||(s[5]=t("p",{class:"tops-login__hint"},[m(" 演示账号 "),t("code",null,"admin / Admin@123"),m(" · "),t("code",null,"viewer / Viewer@123")],-1)),t("button",{class:"tops-login__dash",type:"button",onClick:s[2]||(s[2]=n=>q(l).push("/dashboard"))}," 无需登录,进入大屏 ")],34)])]))}});export{L as default};
import{d as b,u as y,c as p,a as V,b as t,w as k,n as A,e as v,v as _,t as g,f as C,g as m,h as q,i as x,r as o,o as f,A as N}from"./index-BssDqbym.js";const S={class:"tops-login"},h={class:"tops-login__stage"},B={class:"tops-login__field"},R={class:"tops-login__field"},T={key:0,class:"tops-login__error",role:"alert"},z=["disabled"],L=b({__name:"LoginView",setup(D){const c=y(),l=x(),r=o("admin"),u=o("Admin@123"),i=o(""),a=o(!1),d=o(!1);async function w(){i.value="",a.value=!0;try{await c.login(r.value.trim(),u.value);const e=typeof l.currentRoute.value.query.redirect=="string"?l.currentRoute.value.query.redirect:"/admin";await l.push(e.startsWith("/")?e:"/admin")}catch(e){i.value=e instanceof N?e.message:"登录失败",d.value=!0,window.setTimeout(()=>{d.value=!1},480)}finally{a.value=!1}}return(e,s)=>(f(),p("div",S,[s[10]||(s[10]=V('<div class="tops-login__atmosphere" aria-hidden="true"><div class="tops-login__grid"></div><div class="tops-login__glow tops-login__glow--a"></div><div class="tops-login__glow tops-login__glow--b"></div><div class="tops-login__horizon"></div></div>',1)),t("div",h,[s[6]||(s[6]=t("div",{class:"tops-login__mark"},"JH",-1)),s[7]||(s[7]=t("h1",{class:"tops-login__title"},"分子实验室三维可视化管理平台",-1)),s[8]||(s[8]=t("p",{class:"tops-login__tagline"},"Lab Intelligent Control",-1)),s[9]||(s[9]=t("p",{class:"tops-login__support"},"登录进入管理后台;大屏无需登录即可查看实时态势。",-1)),t("form",{class:A(["tops-login__form",{"is-shake":d.value}]),onSubmit:k(w,["prevent"])},[t("label",B,[s[3]||(s[3]=t("span",null,"用户名",-1)),v(t("input",{"onUpdate:modelValue":s[0]||(s[0]=n=>r.value=n),autocomplete:"username",required:""},null,512),[[_,r.value]])]),t("label",R,[s[4]||(s[4]=t("span",null,"密码",-1)),v(t("input",{"onUpdate:modelValue":s[1]||(s[1]=n=>u.value=n),type:"password",autocomplete:"current-password",required:""},null,512),[[_,u.value]])]),i.value?(f(),p("p",T,g(i.value),1)):C("",!0),t("button",{class:"tops-login__submit",type:"submit",disabled:a.value},[t("span",null,g(a.value?"登录中…":"进入后台"),1)],8,z),s[5]||(s[5]=t("p",{class:"tops-login__hint"},[m(" 演示账号 "),t("code",null,"admin / Admin@123"),m(" · "),t("code",null,"viewer / Viewer@123")],-1)),t("button",{class:"tops-login__dash",type:"button",onClick:s[2]||(s[2]=n=>q(l).push("/dashboard"))}," 无需登录,进入大屏 ")],34)])]))}});export{L as default};
import{d as Q,I as et,j as X,s as lt,c as d,y as Z,b as t,F as A,z as K,f as T,t as l,r as M,B as L,o as u,_ as tt,u as st,k as at,n as W,h as m,D as j,e as C,v as V,M as nt,g as J,N as ot,l as G}from"./index-Bs_x-_cK.js";import{u as it}from"./realtime-CI_KLy_N.js";const dt=["viewBox","width","height"],ut=["stop-color"],rt=["stop-color"],ct=["x1","x2","y1","y2"],vt=["x","y"],pt=["d","fill"],mt=["d","stroke"],bt=["cx","cy","r","fill","onMouseenter"],ht=["x","y"],yt=Q({__name:"CostLineChart",props:{points:{},color:{default:"#37c8ff"},unit:{default:"元"},height:{default:180},labelEvery:{default:0}},setup(x){const c=x,w=`lg-${et().replace(/:/g,"")}`,y=M(null),k=M(null),$=M(640),b={top:16,right:16,bottom:28,left:48};let r;X(()=>{if(!y.value)return;const o=()=>{var h;const v=((h=y.value)==null?void 0:h.clientWidth)||640;$.value=Math.max(280,Math.round(v))};o(),r=new ResizeObserver(o),r.observe(y.value)}),lt(()=>r==null?void 0:r.disconnect());const a=L(()=>{const o=c.points,v=$.value;if(!o.length)return{path:"",area:"",dots:[],yTicks:[],xLabels:[]};const h=o.map(i=>i.value),g=Math.min(...h),D=Math.max(...h),N=D-g||D*.1||1,E=Math.max(0,g-N*.12),U=D+N*.12,z=v-b.left-b.right,R=c.height-b.top-b.bottom,p=U-E||1,O=i=>b.left+(o.length===1?z/2:i/(o.length-1)*z),I=i=>b.top+(U-i)/p*R,F=o.map((i,f)=>({x:O(f),y:I(i.value),label:i.label,value:i.value})),S=F.map((i,f)=>`${f===0?"M":"L"}${i.x.toFixed(1)},${i.y.toFixed(1)}`).join(" "),H=`${S} L${F[F.length-1].x.toFixed(1)},${(b.top+R).toFixed(1)} L${F[0].x.toFixed(1)},${(b.top+R).toFixed(1)} Z`,Y=[];for(let i=0;i<=4;i++){const f=E+p*i/4;Y.push({v:f,y:I(f)})}const n=c.labelEvery>0?c.labelEvery:o.length<=8?1:o.length<=16?2:Math.ceil(o.length/8),e=F.map((i,f)=>({x:i.x,label:i.label,show:f%n===0||f===F.length-1})).filter(i=>i.show);return{path:S,area:H,dots:F,yTicks:Y,xLabels:e}});function P(o){return o>=1e4?`${(o/1e4).toFixed(1)}万`:o>=1e3?o.toFixed(0):o.toFixed(o>=100?0:1)}return(o,v)=>(u(),d("div",{ref_key:"rootRef",ref:y,class:"line-chart",style:Z({height:`${x.height}px`})},[(u(),d("svg",{class:"svg",viewBox:`0 0 ${$.value} ${x.height}`,width:$.value,height:x.height,preserveAspectRatio:"xMidYMid meet"},[t("defs",null,[t("linearGradient",{id:w,x1:"0",y1:"0",x2:"0",y2:"1"},[t("stop",{offset:"0%","stop-color":x.color,"stop-opacity":"0.35"},null,8,ut),t("stop",{offset:"100%","stop-color":x.color,"stop-opacity":"0.02"},null,8,rt)])]),(u(!0),d(A,null,K(a.value.yTicks,(h,g)=>(u(),d("line",{key:`g-${g}`,x1:b.left,x2:$.value-b.right,y1:h.y,y2:h.y,stroke:"rgba(62,200,255,0.12)","stroke-width":"1"},null,8,ct))),128)),(u(!0),d(A,null,K(a.value.yTicks,(h,g)=>(u(),d("text",{key:`yl-${g}`,x:b.left-8,y:h.y+4,"text-anchor":"end",class:"axis"},l(P(h.v)),9,vt))),128)),a.value.area?(u(),d("path",{key:0,d:a.value.area,fill:`url(#${w})`},null,8,pt)):T("",!0),a.value.path?(u(),d("path",{key:1,d:a.value.path,fill:"none",stroke:x.color,"stroke-width":"2.2","stroke-linejoin":"round","stroke-linecap":"round"},null,8,mt)):T("",!0),(u(!0),d(A,null,K(a.value.dots,(h,g)=>(u(),d("g",{key:`d-${g}`},[t("circle",{cx:h.x,cy:h.y,r:k.value===g?5:3.2,fill:x.color,stroke:"rgba(4,16,31,0.9)","stroke-width":"1.5",onMouseenter:D=>k.value=g,onMouseleave:v[0]||(v[0]=D=>k.value=null)},null,40,bt)]))),128)),(u(!0),d(A,null,K(a.value.xLabels,(h,g)=>(u(),d("text",{key:`xl-${g}`,x:h.x,y:x.height-8,"text-anchor":"middle",class:"axis"},l(h.label),9,ht))),128))],8,dt)),k.value!=null&&a.value.dots[k.value]?(u(),d("div",{key:0,class:"tip",style:Z({left:`${a.value.dots[k.value].x/$.value*100}%`})},[t("b",null,l(a.value.dots[k.value].label),1),t("span",null,l(a.value.dots[k.value].value.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2}))+" "+l(x.unit),1)],4)):T("",!0)],4))}}),B=tt(yt,[["__scopeId","data-v-a7e520cd"]]),ft={class:"page-fill billing-page admin-billing"},gt={class:"billing-tabs"},wt=["disabled"],kt={key:0,class:"msg"},_t={class:"metric-grid three"},xt={class:"panel metric-card"},$t={class:"m-value"},Ft={class:"m-sub"},Ct={class:"panel metric-card"},Mt={class:"m-value"},Vt={class:"m-sub"},Pt={class:"panel metric-card"},At={class:"m-value"},Dt={class:"m-sub"},Ut={class:"usage-charts"},Wt={class:"panel chart-panel"},Lt={class:"panel chart-panel"},Kt={class:"panel chart-panel"},Tt={class:"metric-grid four"},Rt={class:"panel metric-card tone-amber"},St={class:"m-value"},jt={class:"panel metric-card tone-cyan"},Bt={class:"m-value"},Nt={class:"m-sub"},Et={class:"panel metric-card tone-green"},zt={class:"m-value"},Ot={class:"m-sub"},It={class:"panel metric-card tone-violet"},Yt={class:"m-value"},Gt={class:"m-sub"},Ht={class:"split"},Jt={class:"panel"},Zt={class:"kind-list"},qt={class:"kind-meta"},Qt={class:"kind-name"},Xt={class:"kind-usage"},te={class:"kind-bar"},ee={class:"kind-cost"},le={class:"panel chart-panel"},se={class:"panel chart-panel month-trend"},ae={key:2,class:"panel tariff-panel"},ne={class:"panel-head"},oe={class:"form-grid tariff-grid"},ie={class:"field"},de=["disabled"],ue={class:"field"},re=["disabled"],ce={class:"field"},ve=["disabled"],pe={class:"field"},me=["disabled"],be={class:"field"},he=["disabled"],ye={class:"field"},fe=["disabled"],ge={class:"field"},we=["disabled"],ke={class:"field"},_e=["disabled"],xe={class:"field switch-field"},$e={class:"switch"},Fe=["disabled"],Ce={class:"tariff-actions"},Me=["disabled"],Ve={class:"hint"},Pe={key:3,class:"panel report-panel"},Ae={class:"panel-head"},De={class:"report-tools"},Ue=["disabled"],We={key:0,class:"report-summary"},Le={class:"table-wrap"},Ke={class:"table"},Te={key:4,class:"loading"},Re=Q({__name:"MeteringView",setup(x){const c=st(),w=it(),y=M("stats"),k=M(!1),$=M(!1),b=M(""),r=M(null),a=ot({powerPeak:0,powerFlat:0,powerValley:0,water:0,cooling:0,serviceFeePct:0,taxPct:0,settleDay:1,enabled:!0,updatedAt:"",updatedBy:""}),P=M(""),o=M(""),v=M(null),h=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.powerKwh}))}),g=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.waterM3}))}),D=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.coolingKwh}))}),N=L(()=>{var n;return(((n=r.value)==null?void 0:n.trend7d)||[]).map(e=>({label:e.date,value:e.total}))}),E=L(()=>{var n;return(((n=r.value)==null?void 0:n.trend12m)||[]).map(e=>({label:e.label,value:e.total}))});function U(n){return n<10?`0${n}`:`${n}`}function z(){const n=new Date;return`${n.getFullYear()}-${U(n.getMonth()+1)}-${U(n.getDate())}`}function R(n){const e=new Date;return e.setDate(e.getDate()-n),`${e.getFullYear()}-${U(e.getMonth()+1)}-${U(e.getDate())}`}function p(n){return n.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}async function O(){r.value=await G("/api/billing/stats",{token:c.token})}async function I(){const n=await G("/api/billing/tariff",{token:c.token});Object.assign(a,n)}async function F(){!P.value||!o.value||(v.value=await G(`/api/billing/report?from=${P.value}&to=${o.value}`,{token:c.token}))}async function S(){k.value=!0,b.value="";try{P.value||(P.value=R(29)),o.value||(o.value=z()),await Promise.all([O(),I(),F()])}catch(n){b.value=n instanceof Error?n.message:"加载失败"}finally{k.value=!1}}async function H(){if(c.isAdmin){$.value=!0,b.value="";try{const n=await G("/api/billing/tariff",{method:"PUT",token:c.token,body:JSON.stringify({powerPeak:a.powerPeak,powerFlat:a.powerFlat,powerValley:a.powerValley,water:a.water,cooling:a.cooling,serviceFeePct:a.serviceFeePct,taxPct:a.taxPct,settleDay:a.settleDay,enabled:a.enabled})});Object.assign(a,n),b.value="计费设置已保存",await Promise.all([O(),F()])}catch(n){b.value=n instanceof Error?n.message:"保存失败"}finally{$.value=!1}}}function Y(){var q;if(!((q=v.value)!=null&&q.rows.length))return;const e=[["日期","峰电kWh","平电kWh","谷电kWh","用水m³","冷量kWh","电费","水费","冷量费","小计","服务费","税费","合计"].join(",")];for(const _ of v.value.rows)e.push([_.date,_.powerPeakKwh,_.powerFlatKwh,_.powerValleyKwh,_.waterM3,_.coolingKwh,_.powerCost,_.waterCost,_.coolingCost,_.subtotal,_.serviceFee,_.tax,_.total].join(","));const i=new Blob(["\uFEFF"+e.join(`
`)],{type:"text/csv;charset=utf-8"}),f=URL.createObjectURL(i),s=document.createElement("a");s.href=f,s.download=`能耗计费报表_${P.value}_${o.value}.csv`,s.click(),URL.revokeObjectURL(f)}return X(()=>{w.connect(),S()}),at(()=>{w.disconnect()}),(n,e)=>{var i,f;return u(),d("div",ft,[t("div",gt,[t("button",{type:"button",class:W(["tab",{active:y.value==="meter"}]),onClick:e[0]||(e[0]=s=>y.value="meter")},"计量概览",2),t("button",{type:"button",class:W(["tab",{active:y.value==="stats"}]),onClick:e[1]||(e[1]=s=>y.value="stats")},"费用统计",2),t("button",{type:"button",class:W(["tab",{active:y.value==="tariff"}]),onClick:e[2]||(e[2]=s=>y.value="tariff")},"计费设置",2),t("button",{type:"button",class:W(["tab",{active:y.value==="report"}]),onClick:e[3]||(e[3]=s=>y.value="report")},"费用报表",2),e[15]||(e[15]=t("div",{class:"tab-spacer"},null,-1)),t("button",{type:"button",class:"btn ghost",disabled:k.value,onClick:S},"刷新",8,wt),b.value?(u(),d("span",kt,l(b.value),1)):T("",!0)]),y.value==="meter"?(u(),d(A,{key:0},[t("div",_t,[t("section",xt,[e[16]||(e[16]=t("div",{class:"m-label"},"今日用电 (kWh)",-1)),t("div",$t,l(m(w).snapshot.metering.powerKwh.toFixed(1)),1),t("div",Ft,"较昨日 "+l(m(w).snapshot.metering.powerTrendPct>0?"↑":"↓")+" "+l(Math.abs(m(w).snapshot.metering.powerTrendPct))+"%",1)]),t("section",Ct,[e[17]||(e[17]=t("div",{class:"m-label"},"今日用水 (m³)",-1)),t("div",Mt,l(m(w).snapshot.metering.waterM3.toFixed(1)),1),t("div",Vt,"较昨日 "+l(m(w).snapshot.metering.waterTrendPct>0?"↑":"↓")+" "+l(Math.abs(m(w).snapshot.metering.waterTrendPct))+"%",1)]),t("section",Pt,[e[18]||(e[18]=t("div",{class:"m-label"},"冷冻水冷量 (kWh)",-1)),t("div",At,l(m(w).snapshot.metering.coolingKwh),1),t("div",Dt,"较昨日 ↑ "+l(m(w).snapshot.metering.coolingTrendPct)+"%",1)])]),t("div",Ut,[t("section",Wt,[e[19]||(e[19]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月用电趋势")]),t("div",{class:"badge"},"kWh")],-1)),j(B,{points:h.value,color:"#fbbf24",unit:"kWh",height:220},null,8,["points"])]),t("section",Lt,[e[20]||(e[20]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月用水趋势")]),t("div",{class:"badge"},"m³")],-1)),j(B,{points:g.value,color:"#38bdf8",unit:"m³",height:220},null,8,["points"])]),t("section",Kt,[e[21]||(e[21]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月冷冻水趋势")]),t("div",{class:"badge"},"kWh")],-1)),j(B,{points:D.value,color:"#67e8f9",unit:"kWh",height:220},null,8,["points"])])])],64)):y.value==="stats"&&r.value?(u(),d(A,{key:1},[t("div",Tt,[t("section",Rt,[e[22]||(e[22]=t("div",{class:"m-label"},"今日费用 (元)",-1)),t("div",St,l(p(r.value.today.total)),1),e[23]||(e[23]=t("div",{class:"m-sub"},"含服务费与税",-1))]),t("section",jt,[e[24]||(e[24]=t("div",{class:"m-label"},"本月累计 (元)",-1)),t("div",Bt,l(p(r.value.month.total)),1),t("div",Nt,"已计 "+l(r.value.month.days)+" 天",1)]),t("section",Et,[e[25]||(e[25]=t("div",{class:"m-label"},"本月电费 (元)",-1)),t("div",zt,l(p(r.value.month.powerCost)),1),t("div",Ot,"用电 "+l(r.value.month.powerKwh)+" kWh",1)]),t("section",It,[e[26]||(e[26]=t("div",{class:"m-label"},"本月水+冷 (元)",-1)),t("div",Yt,l(p(r.value.month.waterCost+r.value.month.coolingCost)),1),t("div",Gt,"水 "+l(r.value.month.waterM3)+" m³ · 冷 "+l(r.value.month.coolingKwh)+" kWh",1)])]),t("div",Ht,[t("section",Jt,[e[27]||(e[27]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"本月费用构成")])],-1)),t("div",Zt,[(u(!0),d(A,null,K(r.value.byKind,s=>(u(),d("div",{key:s.kind,class:W(["kind-row",s.kind])},[t("div",qt,[t("span",Qt,l(s.label),1),t("span",Xt,l(s.usage)+" "+l(s.unit),1)]),t("div",te,[t("i",{style:Z({width:`${s.pct}%`})},null,4)]),t("div",ee,[J("¥ "+l(p(s.cost))+" ",1),t("em",null,l(s.pct)+"%",1)])],2))),128))])]),t("section",le,[e[28]||(e[28]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近 7 日费用趋势")]),t("div",{class:"badge"},"元")],-1)),j(B,{points:N.value,color:"#7ad8ff",unit:"元",height:160},null,8,["points"])])]),t("section",se,[e[29]||(e[29]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近 12 个月费用趋势")]),t("div",{class:"badge"},"元")],-1)),j(B,{points:E.value,color:"#a78bfa",unit:"元",height:170},null,8,["points"])])],64)):y.value==="tariff"?(u(),d("section",ae,[t("div",ne,[e[30]||(e[30]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"费率与结算规则")],-1)),t("div",{class:W(["badge",m(c).isAdmin?"":"amber"])},l(m(c).isAdmin?"管理员可改":"只读"),3)]),t("div",oe,[t("div",ie,[e[31]||(e[31]=t("label",null,"峰电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[4]||(e[4]=s=>a.powerPeak=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,de),[[V,a.powerPeak,void 0,{number:!0}]])]),t("div",ue,[e[32]||(e[32]=t("label",null,"平电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[5]||(e[5]=s=>a.powerFlat=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,re),[[V,a.powerFlat,void 0,{number:!0}]])]),t("div",ce,[e[33]||(e[33]=t("label",null,"谷电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[6]||(e[6]=s=>a.powerValley=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,ve),[[V,a.powerValley,void 0,{number:!0}]])]),t("div",pe,[e[34]||(e[34]=t("label",null,"水价 (元/m³)",-1)),C(t("input",{"onUpdate:modelValue":e[7]||(e[7]=s=>a.water=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,me),[[V,a.water,void 0,{number:!0}]])]),t("div",be,[e[35]||(e[35]=t("label",null,"冷量单价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[8]||(e[8]=s=>a.cooling=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,he),[[V,a.cooling,void 0,{number:!0}]])]),t("div",ye,[e[36]||(e[36]=t("label",null,"服务费率 (%)",-1)),C(t("input",{"onUpdate:modelValue":e[9]||(e[9]=s=>a.serviceFeePct=s),type:"number",step:"0.1",min:"0",disabled:!m(c).isAdmin},null,8,fe),[[V,a.serviceFeePct,void 0,{number:!0}]])]),t("div",ge,[e[37]||(e[37]=t("label",null,"税率 (%)",-1)),C(t("input",{"onUpdate:modelValue":e[10]||(e[10]=s=>a.taxPct=s),type:"number",step:"0.1",min:"0",disabled:!m(c).isAdmin},null,8,we),[[V,a.taxPct,void 0,{number:!0}]])]),t("div",ke,[e[38]||(e[38]=t("label",null,"每月结算日",-1)),C(t("input",{"onUpdate:modelValue":e[11]||(e[11]=s=>a.settleDay=s),type:"number",min:"1",max:"28",disabled:!m(c).isAdmin},null,8,_e),[[V,a.settleDay,void 0,{number:!0}]])]),t("div",xe,[e[39]||(e[39]=t("label",null,"启用计费",-1)),t("label",$e,[C(t("input",{"onUpdate:modelValue":e[12]||(e[12]=s=>a.enabled=s),type:"checkbox",disabled:!m(c).isAdmin},null,8,Fe),[[nt,a.enabled]]),t("span",null,l(a.enabled?"已启用":"已停用"),1)])])]),t("div",Ce,[t("button",{type:"button",class:"btn",disabled:!m(c).isAdmin||$.value,onClick:H},l($.value?"保存中…":"保存设置"),9,Me),t("span",Ve," 最近更新:"+l(a.updatedBy||"—")+" · "+l(a.updatedAt?new Date(a.updatedAt).toLocaleString("zh-CN",{hour12:!1}):"—"),1)]),e[40]||(e[40]=t("p",{class:"tip"}," 参考同类能耗计费软件:支持分时电价(峰/平/谷)、水与冷量单价、服务费与税费、按月结算日。费用 = 用量 × 单价 + 服务费 + 税。 ",-1))])):y.value==="report"?(u(),d("section",Pe,[t("div",Ae,[e[43]||(e[43]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"费用明细报表")],-1)),t("div",De,[t("label",null,[e[41]||(e[41]=J("自 ",-1)),C(t("input",{"onUpdate:modelValue":e[13]||(e[13]=s=>P.value=s),type:"date"},null,512),[[V,P.value]])]),t("label",null,[e[42]||(e[42]=J("至 ",-1)),C(t("input",{"onUpdate:modelValue":e[14]||(e[14]=s=>o.value=s),type:"date"},null,512),[[V,o.value]])]),t("button",{type:"button",class:"btn",onClick:F},"查询"),t("button",{type:"button",class:"btn ghost",disabled:!((i=v.value)!=null&&i.rows.length),onClick:Y},"导出 CSV",8,Ue)])]),v.value?(u(),d("div",We,[t("span",null,"区间 "+l(v.value.summary.from)+" ~ "+l(v.value.summary.to)+" · "+l(v.value.summary.days)+" 天",1),t("span",null,"电费 ¥"+l(p(v.value.summary.powerCost)),1),t("span",null,"水费 ¥"+l(p(v.value.summary.waterCost)),1),t("span",null,"冷量费 ¥"+l(p(v.value.summary.coolingCost)),1),t("span",null,"服务费 ¥"+l(p(v.value.summary.serviceFee)),1),t("span",null,"税费 ¥"+l(p(v.value.summary.tax)),1),t("b",null,"合计 ¥"+l(p(v.value.summary.total)),1)])):T("",!0),t("div",Le,[t("table",Ke,[e[44]||(e[44]=t("thead",null,[t("tr",null,[t("th",null,"日期"),t("th",null,"峰电"),t("th",null,"平电"),t("th",null,"谷电"),t("th",null,"用水"),t("th",null,"冷量"),t("th",null,"电费"),t("th",null,"水费"),t("th",null,"冷量费"),t("th",null,"服务费"),t("th",null,"税费"),t("th",null,"合计")])],-1)),t("tbody",null,[(u(!0),d(A,null,K(((f=v.value)==null?void 0:f.rows)||[],s=>(u(),d("tr",{key:s.date},[t("td",null,l(s.date),1),t("td",null,l(s.powerPeakKwh),1),t("td",null,l(s.powerFlatKwh),1),t("td",null,l(s.powerValleyKwh),1),t("td",null,l(s.waterM3),1),t("td",null,l(s.coolingKwh),1),t("td",null,l(p(s.powerCost)),1),t("td",null,l(p(s.waterCost)),1),t("td",null,l(p(s.coolingCost)),1),t("td",null,l(p(s.serviceFee)),1),t("td",null,l(p(s.tax)),1),t("td",null,[t("b",null,l(p(s.total)),1)])]))),128))])])])])):k.value?(u(),d("div",Te,"加载计费数据…")):T("",!0)])}}}),Be=tt(Re,[["__scopeId","data-v-a9526d06"]]);export{Be as default};
import{d as q,M as et,l as X,C as lt,c as d,E as Q,b as t,F as A,x as K,f as T,t as l,r as M,s as L,o as u,_ as tt,u as st,m as at,n as W,h as m,H as j,e as C,v as V,Q as nt,g as J,R as ot,p as H}from"./index-BssDqbym.js";import{u as it}from"./realtime-lmP-Cubp.js";const dt=["viewBox","width","height"],ut=["stop-color"],rt=["stop-color"],ct=["x1","x2","y1","y2"],vt=["x","y"],pt=["d","fill"],mt=["d","stroke"],bt=["cx","cy","r","fill","onMouseenter"],ht=["x","y"],ft=q({__name:"CostLineChart",props:{points:{},color:{default:"#37c8ff"},unit:{default:"元"},height:{default:180},labelEvery:{default:0}},setup(x){const c=x,w=`lg-${et().replace(/:/g,"")}`,f=M(null),_=M(null),$=M(640),b={top:16,right:16,bottom:28,left:48};let r;X(()=>{if(!f.value)return;const o=()=>{var h;const v=((h=f.value)==null?void 0:h.clientWidth)||640;$.value=Math.max(280,Math.round(v))};o(),r=new ResizeObserver(o),r.observe(f.value)}),lt(()=>r==null?void 0:r.disconnect());const a=L(()=>{const o=c.points,v=$.value;if(!o.length)return{path:"",area:"",dots:[],yTicks:[],xLabels:[]};const h=o.map(i=>i.value),y=Math.min(...h),D=Math.max(...h),E=D-y||D*.1||1,N=Math.max(0,y-E*.12),U=D+E*.12,z=v-b.left-b.right,R=c.height-b.top-b.bottom,p=U-N||1,O=i=>b.left+(o.length===1?z/2:i/(o.length-1)*z),I=i=>b.top+(U-i)/p*R,F=o.map((i,g)=>({x:O(g),y:I(i.value),label:i.label,value:i.value})),S=F.map((i,g)=>`${g===0?"M":"L"}${i.x.toFixed(1)},${i.y.toFixed(1)}`).join(" "),G=`${S} L${F[F.length-1].x.toFixed(1)},${(b.top+R).toFixed(1)} L${F[0].x.toFixed(1)},${(b.top+R).toFixed(1)} Z`,Y=[];for(let i=0;i<=4;i++){const g=N+p*i/4;Y.push({v:g,y:I(g)})}const n=c.labelEvery>0?c.labelEvery:o.length<=8?1:o.length<=16?2:Math.ceil(o.length/8),e=F.map((i,g)=>({x:i.x,label:i.label,show:g%n===0||g===F.length-1})).filter(i=>i.show);return{path:S,area:G,dots:F,yTicks:Y,xLabels:e}});function P(o){return o>=1e4?`${(o/1e4).toFixed(1)}万`:o>=1e3?o.toFixed(0):o.toFixed(o>=100?0:1)}return(o,v)=>(u(),d("div",{ref_key:"rootRef",ref:f,class:"line-chart",style:Q({height:`${x.height}px`})},[(u(),d("svg",{class:"svg",viewBox:`0 0 ${$.value} ${x.height}`,width:$.value,height:x.height,preserveAspectRatio:"xMidYMid meet"},[t("defs",null,[t("linearGradient",{id:w,x1:"0",y1:"0",x2:"0",y2:"1"},[t("stop",{offset:"0%","stop-color":x.color,"stop-opacity":"0.35"},null,8,ut),t("stop",{offset:"100%","stop-color":x.color,"stop-opacity":"0.02"},null,8,rt)])]),(u(!0),d(A,null,K(a.value.yTicks,(h,y)=>(u(),d("line",{key:`g-${y}`,x1:b.left,x2:$.value-b.right,y1:h.y,y2:h.y,stroke:"rgba(62,200,255,0.12)","stroke-width":"1"},null,8,ct))),128)),(u(!0),d(A,null,K(a.value.yTicks,(h,y)=>(u(),d("text",{key:`yl-${y}`,x:b.left-8,y:h.y+4,"text-anchor":"end",class:"axis"},l(P(h.v)),9,vt))),128)),a.value.area?(u(),d("path",{key:0,d:a.value.area,fill:`url(#${w})`},null,8,pt)):T("",!0),a.value.path?(u(),d("path",{key:1,d:a.value.path,fill:"none",stroke:x.color,"stroke-width":"2.2","stroke-linejoin":"round","stroke-linecap":"round"},null,8,mt)):T("",!0),(u(!0),d(A,null,K(a.value.dots,(h,y)=>(u(),d("g",{key:`d-${y}`},[t("circle",{cx:h.x,cy:h.y,r:_.value===y?5:3.2,fill:x.color,stroke:"rgba(4,16,31,0.9)","stroke-width":"1.5",onMouseenter:D=>_.value=y,onMouseleave:v[0]||(v[0]=D=>_.value=null)},null,40,bt)]))),128)),(u(!0),d(A,null,K(a.value.xLabels,(h,y)=>(u(),d("text",{key:`xl-${y}`,x:h.x,y:x.height-8,"text-anchor":"middle",class:"axis"},l(h.label),9,ht))),128))],8,dt)),_.value!=null&&a.value.dots[_.value]?(u(),d("div",{key:0,class:"tip",style:Q({left:`${a.value.dots[_.value].x/$.value*100}%`})},[t("b",null,l(a.value.dots[_.value].label),1),t("span",null,l(a.value.dots[_.value].value.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2}))+" "+l(x.unit),1)],4)):T("",!0)],4))}}),B=tt(ft,[["__scopeId","data-v-a7e520cd"]]),gt={class:"page-fill billing-page admin-billing"},yt={class:"billing-tabs"},wt=["disabled"],_t={key:0,class:"msg"},kt={class:"metric-grid three"},xt={class:"panel metric-card"},$t={class:"m-value"},Ft={class:"m-sub"},Ct={class:"panel metric-card"},Mt={class:"m-value"},Vt={class:"m-sub"},Pt={class:"panel metric-card"},At={class:"m-value"},Dt={class:"m-sub"},Ut={class:"usage-charts"},Wt={class:"panel chart-panel"},Lt={class:"panel chart-panel"},Kt={class:"panel chart-panel"},Tt={class:"metric-grid four"},Rt={class:"panel metric-card tone-amber"},St={class:"m-value"},jt={class:"panel metric-card tone-cyan"},Bt={class:"m-value"},Et={class:"m-sub"},Nt={class:"panel metric-card tone-green"},zt={class:"m-value"},Ot={class:"m-sub"},It={class:"panel metric-card tone-violet"},Yt={class:"m-value"},Ht={class:"m-sub"},Gt={class:"split"},Jt={class:"panel"},Qt={class:"kind-list"},Zt={class:"kind-meta"},qt={class:"kind-name"},Xt={class:"kind-usage"},te={class:"kind-bar"},ee={class:"kind-cost"},le={class:"panel chart-panel"},se={class:"panel chart-panel month-trend"},ae={key:2,class:"panel tariff-panel"},ne={class:"panel-head"},oe={class:"form-grid tariff-grid"},ie={class:"field"},de=["disabled"],ue={class:"field"},re=["disabled"],ce={class:"field"},ve=["disabled"],pe={class:"field"},me=["disabled"],be={class:"field"},he=["disabled"],fe={class:"field"},ge=["disabled"],ye={class:"field"},we=["disabled"],_e={class:"field"},ke=["disabled"],xe={class:"field switch-field"},$e={class:"switch"},Fe=["disabled"],Ce={class:"tariff-actions"},Me=["disabled"],Ve={class:"hint"},Pe={key:3,class:"panel report-panel"},Ae={class:"panel-head"},De={class:"report-tools"},Ue=["disabled"],We={key:0,class:"report-summary"},Le={class:"table-wrap"},Ke={class:"table"},Te={key:4,class:"loading"},Re=q({__name:"MeteringView",setup(x){const c=st(),w=it(),f=M("stats"),_=M(!1),$=M(!1),b=M(""),r=M(null),a=ot({powerPeak:0,powerFlat:0,powerValley:0,water:0,cooling:0,serviceFeePct:0,taxPct:0,settleDay:1,enabled:!0,updatedAt:"",updatedBy:""}),P=M(""),o=M(""),v=M(null),h=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.powerKwh}))}),y=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.waterM3}))}),D=L(()=>{var n;return(((n=r.value)==null?void 0:n.usage30d)||[]).map(e=>({label:e.label,value:e.coolingKwh}))}),E=L(()=>{var n;return(((n=r.value)==null?void 0:n.trend7d)||[]).map(e=>({label:e.date,value:e.total}))}),N=L(()=>{var n;return(((n=r.value)==null?void 0:n.trend12m)||[]).map(e=>({label:e.label,value:e.total}))});function U(n){return n<10?`0${n}`:`${n}`}function z(){const n=new Date;return`${n.getFullYear()}-${U(n.getMonth()+1)}-${U(n.getDate())}`}function R(n){const e=new Date;return e.setDate(e.getDate()-n),`${e.getFullYear()}-${U(e.getMonth()+1)}-${U(e.getDate())}`}function p(n){return n.toLocaleString("zh-CN",{minimumFractionDigits:2,maximumFractionDigits:2})}async function O(){r.value=await H("/api/billing/stats",{token:c.token})}async function I(){const n=await H("/api/billing/tariff",{token:c.token});Object.assign(a,n)}async function F(){!P.value||!o.value||(v.value=await H(`/api/billing/report?from=${P.value}&to=${o.value}`,{token:c.token}))}async function S(){_.value=!0,b.value="";try{P.value||(P.value=R(29)),o.value||(o.value=z()),await Promise.all([O(),I(),F()])}catch(n){b.value=n instanceof Error?n.message:"加载失败"}finally{_.value=!1}}async function G(){if(c.isAdmin){$.value=!0,b.value="";try{const n=await H("/api/billing/tariff",{method:"PUT",token:c.token,body:JSON.stringify({powerPeak:a.powerPeak,powerFlat:a.powerFlat,powerValley:a.powerValley,water:a.water,cooling:a.cooling,serviceFeePct:a.serviceFeePct,taxPct:a.taxPct,settleDay:a.settleDay,enabled:a.enabled})});Object.assign(a,n),b.value="计费设置已保存",await Promise.all([O(),F()])}catch(n){b.value=n instanceof Error?n.message:"保存失败"}finally{$.value=!1}}}function Y(){var Z;if(!((Z=v.value)!=null&&Z.rows.length))return;const e=[["日期","峰电kWh","平电kWh","谷电kWh","用水m³","冷量kWh","电费","水费","冷量费","小计","服务费","税费","合计"].join(",")];for(const k of v.value.rows)e.push([k.date,k.powerPeakKwh,k.powerFlatKwh,k.powerValleyKwh,k.waterM3,k.coolingKwh,k.powerCost,k.waterCost,k.coolingCost,k.subtotal,k.serviceFee,k.tax,k.total].join(","));const i=new Blob(["\uFEFF"+e.join(`
`)],{type:"text/csv;charset=utf-8"}),g=URL.createObjectURL(i),s=document.createElement("a");s.href=g,s.download=`能耗计费报表_${P.value}_${o.value}.csv`,s.click(),URL.revokeObjectURL(g)}return X(()=>{w.connect(),S()}),at(()=>{w.disconnect()}),(n,e)=>{var i,g;return u(),d("div",gt,[t("div",yt,[t("button",{type:"button",class:W(["tab",{active:f.value==="meter"}]),onClick:e[0]||(e[0]=s=>f.value="meter")},"计量概览",2),t("button",{type:"button",class:W(["tab",{active:f.value==="stats"}]),onClick:e[1]||(e[1]=s=>f.value="stats")},"费用统计",2),t("button",{type:"button",class:W(["tab",{active:f.value==="tariff"}]),onClick:e[2]||(e[2]=s=>f.value="tariff")},"计费设置",2),t("button",{type:"button",class:W(["tab",{active:f.value==="report"}]),onClick:e[3]||(e[3]=s=>f.value="report")},"费用报表",2),e[15]||(e[15]=t("div",{class:"tab-spacer"},null,-1)),t("button",{type:"button",class:"btn ghost",disabled:_.value,onClick:S},"刷新",8,wt),b.value?(u(),d("span",_t,l(b.value),1)):T("",!0)]),f.value==="meter"?(u(),d(A,{key:0},[t("div",kt,[t("section",xt,[e[16]||(e[16]=t("div",{class:"m-label"},"今日用电 (kWh)",-1)),t("div",$t,l(m(w).snapshot.metering.powerKwh.toFixed(1)),1),t("div",Ft,"较昨日 "+l(m(w).snapshot.metering.powerTrendPct>0?"↑":"↓")+" "+l(Math.abs(m(w).snapshot.metering.powerTrendPct))+"%",1)]),t("section",Ct,[e[17]||(e[17]=t("div",{class:"m-label"},"今日用水 (m³)",-1)),t("div",Mt,l(m(w).snapshot.metering.waterM3.toFixed(1)),1),t("div",Vt,"较昨日 "+l(m(w).snapshot.metering.waterTrendPct>0?"↑":"↓")+" "+l(Math.abs(m(w).snapshot.metering.waterTrendPct))+"%",1)]),t("section",Pt,[e[18]||(e[18]=t("div",{class:"m-label"},"冷冻水冷量 (kWh)",-1)),t("div",At,l(m(w).snapshot.metering.coolingKwh),1),t("div",Dt,"较昨日 ↑ "+l(m(w).snapshot.metering.coolingTrendPct)+"%",1)])]),t("div",Ut,[t("section",Wt,[e[19]||(e[19]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月用电趋势")]),t("div",{class:"badge"},"kWh")],-1)),j(B,{points:h.value,color:"#fbbf24",unit:"kWh",height:220},null,8,["points"])]),t("section",Lt,[e[20]||(e[20]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月用水趋势")]),t("div",{class:"badge"},"m³")],-1)),j(B,{points:y.value,color:"#38bdf8",unit:"m³",height:220},null,8,["points"])]),t("section",Kt,[e[21]||(e[21]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近一个月冷冻水趋势")]),t("div",{class:"badge"},"kWh")],-1)),j(B,{points:D.value,color:"#67e8f9",unit:"kWh",height:220},null,8,["points"])])])],64)):f.value==="stats"&&r.value?(u(),d(A,{key:1},[t("div",Tt,[t("section",Rt,[e[22]||(e[22]=t("div",{class:"m-label"},"今日费用 (元)",-1)),t("div",St,l(p(r.value.today.total)),1),e[23]||(e[23]=t("div",{class:"m-sub"},"含服务费与税",-1))]),t("section",jt,[e[24]||(e[24]=t("div",{class:"m-label"},"本月累计 (元)",-1)),t("div",Bt,l(p(r.value.month.total)),1),t("div",Et,"已计 "+l(r.value.month.days)+" 天",1)]),t("section",Nt,[e[25]||(e[25]=t("div",{class:"m-label"},"本月电费 (元)",-1)),t("div",zt,l(p(r.value.month.powerCost)),1),t("div",Ot,"用电 "+l(r.value.month.powerKwh)+" kWh",1)]),t("section",It,[e[26]||(e[26]=t("div",{class:"m-label"},"本月水+冷 (元)",-1)),t("div",Yt,l(p(r.value.month.waterCost+r.value.month.coolingCost)),1),t("div",Ht,"水 "+l(r.value.month.waterM3)+" m³ · 冷 "+l(r.value.month.coolingKwh)+" kWh",1)])]),t("div",Gt,[t("section",Jt,[e[27]||(e[27]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"本月费用构成")])],-1)),t("div",Qt,[(u(!0),d(A,null,K(r.value.byKind,s=>(u(),d("div",{key:s.kind,class:W(["kind-row",s.kind])},[t("div",Zt,[t("span",qt,l(s.label),1),t("span",Xt,l(s.usage)+" "+l(s.unit),1)]),t("div",te,[t("i",{style:Q({width:`${s.pct}%`})},null,4)]),t("div",ee,[J("¥ "+l(p(s.cost))+" ",1),t("em",null,l(s.pct)+"%",1)])],2))),128))])]),t("section",le,[e[28]||(e[28]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近 7 日费用趋势")]),t("div",{class:"badge"},"元")],-1)),j(B,{points:E.value,color:"#7ad8ff",unit:"元",height:160},null,8,["points"])])]),t("section",se,[e[29]||(e[29]=t("div",{class:"panel-head"},[t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"近 12 个月费用趋势")]),t("div",{class:"badge"},"元")],-1)),j(B,{points:N.value,color:"#a78bfa",unit:"元",height:170},null,8,["points"])])],64)):f.value==="tariff"?(u(),d("section",ae,[t("div",ne,[e[30]||(e[30]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"费率与结算规则")],-1)),t("div",{class:W(["badge",m(c).isAdmin?"":"amber"])},l(m(c).isAdmin?"管理员可改":"只读"),3)]),t("div",oe,[t("div",ie,[e[31]||(e[31]=t("label",null,"峰电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[4]||(e[4]=s=>a.powerPeak=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,de),[[V,a.powerPeak,void 0,{number:!0}]])]),t("div",ue,[e[32]||(e[32]=t("label",null,"平电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[5]||(e[5]=s=>a.powerFlat=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,re),[[V,a.powerFlat,void 0,{number:!0}]])]),t("div",ce,[e[33]||(e[33]=t("label",null,"谷电价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[6]||(e[6]=s=>a.powerValley=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,ve),[[V,a.powerValley,void 0,{number:!0}]])]),t("div",pe,[e[34]||(e[34]=t("label",null,"水价 (元/m³)",-1)),C(t("input",{"onUpdate:modelValue":e[7]||(e[7]=s=>a.water=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,me),[[V,a.water,void 0,{number:!0}]])]),t("div",be,[e[35]||(e[35]=t("label",null,"冷量单价 (元/kWh)",-1)),C(t("input",{"onUpdate:modelValue":e[8]||(e[8]=s=>a.cooling=s),type:"number",step:"0.01",min:"0",disabled:!m(c).isAdmin},null,8,he),[[V,a.cooling,void 0,{number:!0}]])]),t("div",fe,[e[36]||(e[36]=t("label",null,"服务费率 (%)",-1)),C(t("input",{"onUpdate:modelValue":e[9]||(e[9]=s=>a.serviceFeePct=s),type:"number",step:"0.1",min:"0",disabled:!m(c).isAdmin},null,8,ge),[[V,a.serviceFeePct,void 0,{number:!0}]])]),t("div",ye,[e[37]||(e[37]=t("label",null,"税率 (%)",-1)),C(t("input",{"onUpdate:modelValue":e[10]||(e[10]=s=>a.taxPct=s),type:"number",step:"0.1",min:"0",disabled:!m(c).isAdmin},null,8,we),[[V,a.taxPct,void 0,{number:!0}]])]),t("div",_e,[e[38]||(e[38]=t("label",null,"每月结算日",-1)),C(t("input",{"onUpdate:modelValue":e[11]||(e[11]=s=>a.settleDay=s),type:"number",min:"1",max:"28",disabled:!m(c).isAdmin},null,8,ke),[[V,a.settleDay,void 0,{number:!0}]])]),t("div",xe,[e[39]||(e[39]=t("label",null,"启用计费",-1)),t("label",$e,[C(t("input",{"onUpdate:modelValue":e[12]||(e[12]=s=>a.enabled=s),type:"checkbox",disabled:!m(c).isAdmin},null,8,Fe),[[nt,a.enabled]]),t("span",null,l(a.enabled?"已启用":"已停用"),1)])])]),t("div",Ce,[t("button",{type:"button",class:"btn",disabled:!m(c).isAdmin||$.value,onClick:G},l($.value?"保存中…":"保存设置"),9,Me),t("span",Ve," 最近更新:"+l(a.updatedBy||"—")+" · "+l(a.updatedAt?new Date(a.updatedAt).toLocaleString("zh-CN",{hour12:!1}):"—"),1)]),e[40]||(e[40]=t("p",{class:"tip"}," 参考同类能耗计费软件:支持分时电价(峰/平/谷)、水与冷量单价、服务费与税费、按月结算日。费用 = 用量 × 单价 + 服务费 + 税。 ",-1))])):f.value==="report"?(u(),d("section",Pe,[t("div",Ae,[e[43]||(e[43]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"费用明细报表")],-1)),t("div",De,[t("label",null,[e[41]||(e[41]=J("自 ",-1)),C(t("input",{"onUpdate:modelValue":e[13]||(e[13]=s=>P.value=s),type:"date"},null,512),[[V,P.value]])]),t("label",null,[e[42]||(e[42]=J("至 ",-1)),C(t("input",{"onUpdate:modelValue":e[14]||(e[14]=s=>o.value=s),type:"date"},null,512),[[V,o.value]])]),t("button",{type:"button",class:"btn",onClick:F},"查询"),t("button",{type:"button",class:"btn ghost",disabled:!((i=v.value)!=null&&i.rows.length),onClick:Y},"导出 CSV",8,Ue)])]),v.value?(u(),d("div",We,[t("span",null,"区间 "+l(v.value.summary.from)+" ~ "+l(v.value.summary.to)+" · "+l(v.value.summary.days)+" 天",1),t("span",null,"电费 ¥"+l(p(v.value.summary.powerCost)),1),t("span",null,"水费 ¥"+l(p(v.value.summary.waterCost)),1),t("span",null,"冷量费 ¥"+l(p(v.value.summary.coolingCost)),1),t("span",null,"服务费 ¥"+l(p(v.value.summary.serviceFee)),1),t("span",null,"税费 ¥"+l(p(v.value.summary.tax)),1),t("b",null,"合计 ¥"+l(p(v.value.summary.total)),1)])):T("",!0),t("div",Le,[t("table",Ke,[e[44]||(e[44]=t("thead",null,[t("tr",null,[t("th",null,"日期"),t("th",null,"峰电"),t("th",null,"平电"),t("th",null,"谷电"),t("th",null,"用水"),t("th",null,"冷量"),t("th",null,"电费"),t("th",null,"水费"),t("th",null,"冷量费"),t("th",null,"服务费"),t("th",null,"税费"),t("th",null,"合计")])],-1)),t("tbody",null,[(u(!0),d(A,null,K(((g=v.value)==null?void 0:g.rows)||[],s=>(u(),d("tr",{key:s.date},[t("td",null,l(s.date),1),t("td",null,l(s.powerPeakKwh),1),t("td",null,l(s.powerFlatKwh),1),t("td",null,l(s.powerValleyKwh),1),t("td",null,l(s.waterM3),1),t("td",null,l(s.coolingKwh),1),t("td",null,l(p(s.powerCost)),1),t("td",null,l(p(s.waterCost)),1),t("td",null,l(p(s.coolingCost)),1),t("td",null,l(p(s.serviceFee)),1),t("td",null,l(p(s.tax)),1),t("td",null,[t("b",null,l(p(s.total)),1)])]))),128))])])])])):_.value?(u(),d("div",Te,"加载计费数据…")):T("",!0)])}}}),Be=tt(Re,[["__scopeId","data-v-a9526d06"]]);export{Be as default};
.panel-box[data-v-59463572]{width:100%;height:100%;min-height:0;display:flex;flex-direction:column;background:#00122a6b;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid rgba(0,247,255,.12);box-shadow:0 8px 28px #00000047}.title-bar[data-v-59463572]{position:relative;height:32px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 12px 2px 10px}.title-bar.line[data-v-59463572]{height:28px;justify-content:flex-start;gap:8px;padding:0 4px 0 6px}.title-frame[data-v-59463572]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;pointer-events:none;filter:drop-shadow(0 0 6px rgba(0,247,255,.18))}.title-main[data-v-59463572],.title-extra[data-v-59463572]{position:relative;z-index:1;display:flex;align-items:center}.title-main[data-v-59463572]{gap:8px}.title-icon[data-v-59463572]{width:10px;height:10px;border:1px solid #00f7ff;background:linear-gradient(#00f7ff,#00f7ff) center / 4px 4px no-repeat,#00284899;box-shadow:0 0 8px #00f7ffb3}.plus-icon[data-v-59463572]{width:12px;height:12px;flex-shrink:0;background:linear-gradient(#00f7ff,#00f7ff) center / 12px 2px no-repeat,linear-gradient(#00f7ff,#00f7ff) center / 2px 12px no-repeat;box-shadow:0 0 8px #00f7ffb3}.hairline[data-v-59463572]{flex:1;height:1px;margin-left:4px;background:linear-gradient(90deg,rgba(0,247,255,.7) 0%,rgba(0,247,255,.18) 42%,transparent 46%,transparent 52%,rgba(0,247,255,.2) 56%,rgba(0,247,255,.05) 100%)}.title-text[data-v-59463572]{font-family:var(--title-font);color:#f4feff;font-size:15px;font-weight:500;letter-spacing:var(--cjk-tracking, 1px);text-shadow:0 0 8px rgba(0,247,255,.35);white-space:nowrap}.title-extra[data-v-59463572]{gap:8px}.title-dots[data-v-59463572]{display:flex;gap:4px}.title-dots i[data-v-59463572]{width:6px;height:6px;background:#00f7ff;box-shadow:0 0 6px #00f7ff}.panel-body[data-v-59463572]{flex:1;min-height:0;padding:8px 10px 10px;overflow:hidden;display:flex;flex-direction:column}.panel-body.line[data-v-59463572]{padding:4px 8px 8px}.flip-digit[data-v-b06c8413]{position:relative;display:inline-block;width:24px;height:38px;margin:0 1.5px;perspective:180px;font-family:var(--font-num);font-weight:700;font-size:24px;line-height:38px;color:#e8fbff;vertical-align:middle}.flip-digit.punct[data-v-b06c8413]{width:12px;background:transparent;box-shadow:none}.flip-digit.punct .static[data-v-b06c8413],.flip-digit.punct .hinge[data-v-b06c8413]{background:transparent;border:none;box-shadow:none}.static[data-v-b06c8413],.hinge[data-v-b06c8413]{position:absolute;left:0;width:100%;height:50%;overflow:hidden;background:linear-gradient(180deg,#0d2a4a,#071828);border:1px solid rgba(0,247,255,.28);box-shadow:inset 0 0 8px #00000059}.static.top[data-v-b06c8413],.hinge.top[data-v-b06c8413]{top:0;border-radius:3px 3px 0 0;border-bottom-color:#00f7ff1f}.static.bottom[data-v-b06c8413],.hinge.bottom[data-v-b06c8413]{bottom:0;border-radius:0 0 3px 3px;border-top-color:#00000059}.static i[data-v-b06c8413],.hinge i[data-v-b06c8413]{position:absolute;left:0;width:100%;height:38px;display:flex;align-items:center;justify-content:center;font-style:normal}.static.top i[data-v-b06c8413],.hinge.top i[data-v-b06c8413]{top:0}.static.bottom i[data-v-b06c8413],.hinge.bottom i[data-v-b06c8413]{bottom:0}.hinge[data-v-b06c8413]{z-index:2;backface-visibility:hidden;transform-style:preserve-3d;pointer-events:none;opacity:0}.hinge.top[data-v-b06c8413]{transform-origin:bottom center}.hinge.bottom[data-v-b06c8413]{transform-origin:top center;transform:rotateX(90deg)}.hinge.top.active[data-v-b06c8413]{opacity:1;animation:flip-top-b06c8413 .5s ease-in forwards}.hinge.bottom.active[data-v-b06c8413]{opacity:1;animation:flip-bottom-b06c8413 .5s ease-out forwards}@keyframes flip-top-b06c8413{0%{transform:rotateX(0)}to{transform:rotateX(-90deg)}}@keyframes flip-bottom-b06c8413{0%{transform:rotateX(90deg)}to{transform:rotateX(0)}}.kpi-flip-board[data-v-ccc29753]{display:flex;gap:10px;width:100%;pointer-events:auto}.kpi-flip[data-v-ccc29753]{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:10px 12px 12px;border-radius:4px;border:1px solid rgba(0,247,255,.28);background:linear-gradient(180deg,#082444e0,#030e20c7);box-shadow:inset 0 1px #ffffff0f,0 8px 20px #00000047;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.kpi-head[data-v-ccc29753]{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-width:0}.kpi-texts[data-v-ccc29753]{min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px}.kpi-label[data-v-ccc29753]{font-size:13px;font-weight:600;color:#9ad8f0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.kpi-hint[data-v-ccc29753]{font-size:10px;color:#9ed2e8b8;white-space:nowrap}.kpi-digits[data-v-ccc29753]{display:flex;align-items:center;justify-content:center;width:100%;min-height:36px}.kpi-flip[data-v-ccc29753] .kpi-ico{width:22px;height:22px;flex:0 0 auto}.tone-power[data-v-ccc29753]{border-color:#ffb44073}.tone-power .kpi-label[data-v-ccc29753]{color:#f0c878}.tone-water[data-v-ccc29753]{border-color:#38bdf873}.tone-water .kpi-label[data-v-ccc29753]{color:#7dd3fc}.tone-cool[data-v-ccc29753]{border-color:#67e8f96b}.tone-cool .kpi-label[data-v-ccc29753]{color:#a5f3fc}.tone-device[data-v-ccc29753]{border-color:#34d39973}.tone-device .kpi-label[data-v-ccc29753]{color:#6ee7b7}.tone-access[data-v-ccc29753]{border-color:#a78bfa73}.tone-access .kpi-label[data-v-ccc29753]{color:#c4b5fd}.overview-float[data-v-60f2b453]{position:relative;width:100%;height:100%;min-height:0;display:grid;grid-template-columns:var(--screen-side-w, clamp(280px, 24vw, 480px)) minmax(0,1fr) var( --screen-side-w, clamp(280px, 24vw, 480px) );grid-template-rows:auto 1fr;gap:10px 12px;pointer-events:none}.kpi-top[data-v-60f2b453]{grid-column:2;grid-row:1;min-width:0;z-index:2}.side[data-v-60f2b453]{min-width:0;min-height:0;height:100%;display:grid;gap:10px;pointer-events:auto}.left[data-v-60f2b453],.right[data-v-60f2b453]{grid-row:1 / -1;grid-template-rows:minmax(0,1.05fr) minmax(0,1fr) minmax(0,.95fr)}.left[data-v-60f2b453]{grid-column:1}.right[data-v-60f2b453]{grid-column:3}.center-pass[data-v-60f2b453]{grid-column:2;grid-row:2;pointer-events:none}.badge[data-v-60f2b453]{padding:1px 7px;border-radius:2px;font-size:10px;letter-spacing:.06em;background:#52c41a24;color:#7dff9a;border:1px solid rgba(82,196,26,.28)}.badge.amber[data-v-60f2b453]{background:#faad1424;color:#ffd666;border-color:#faad1459}.panel-stack[data-v-60f2b453]{flex:1;min-height:0;display:flex;flex-direction:column;gap:6px}.chart-main[data-v-60f2b453]{flex:1.2;min-height:0}.chart-sub[data-v-60f2b453]{flex:.9;min-height:0}.panel-split[data-v-60f2b453]{flex:1;min-height:0;display:grid;grid-template-columns:1fr 1fr;gap:6px}.panel-split--pies[data-v-60f2b453]{grid-template-rows:minmax(0,1fr)}.pie-col[data-v-60f2b453]{min-height:0;display:flex;flex-direction:column}.pie-cap[data-v-60f2b453]{text-align:center;font-size:10px;color:var(--panel-muted);margin-top:-2px}.digit-row[data-v-60f2b453]{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;flex-shrink:0}.digit-card[data-v-60f2b453]{padding:6px 8px;border-radius:4px;background:#061c3873;border:1px solid rgba(0,247,255,.14);text-align:center}.digit-card.warn[data-v-60f2b453]{border-color:#faad1466}.d-label[data-v-60f2b453]{font-size:10px;color:var(--panel-muted)}.d-value[data-v-60f2b453]{margin-top:2px;font-size:15px;font-weight:600;font-family:var(--font-num);color:#fff;line-height:1.2}.d-value small[data-v-60f2b453]{font-size:10px;color:#52c41a;font-weight:500}.energy-digits[data-v-60f2b453]{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;flex-shrink:0}.ed[data-v-60f2b453]{padding:8px;border-radius:4px;background:#061c3873;border:1px solid rgba(0,247,255,.14)}.ed span[data-v-60f2b453]{display:block;font-size:10px;color:var(--panel-muted)}.ed b[data-v-60f2b453]{display:block;margin-top:4px;font-size:16px;font-family:var(--font-num);color:#fff}.ed small[data-v-60f2b453]{font-size:10px;color:#c8e6f5a6;font-weight:500}.screen-err[data-v-60f2b453]{position:absolute;left:50%;bottom:12px;transform:translate(-50%);z-index:8;padding:4px 12px;border-radius:4px;background:#781414bf;color:#ffb0b0;font-size:12px;pointer-events:none}.side[data-v-60f2b453] .echart-wrap{flex:1;min-height:0}
.panel-box[data-v-c98402ab]{width:100%;height:100%;min-height:0;display:flex;flex-direction:column;background:#00122a6b;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);border:1px solid rgba(0,247,255,.12);box-shadow:0 8px 28px #00000047}.title-bar[data-v-c98402ab]{position:relative;height:32px;flex-shrink:0;display:flex;align-items:center;justify-content:space-between;padding:0 12px 2px 10px}.title-bar.line[data-v-c98402ab]{height:28px;justify-content:flex-start;gap:8px;padding:0 4px 0 6px}.title-frame[data-v-c98402ab]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;pointer-events:none;filter:drop-shadow(0 0 6px rgba(0,247,255,.18))}.title-main[data-v-c98402ab],.title-extra[data-v-c98402ab]{position:relative;z-index:1;display:flex;align-items:center}.title-main[data-v-c98402ab]{gap:8px}.title-icon[data-v-c98402ab]{width:10px;height:10px;border:1px solid #00f7ff;background:linear-gradient(#00f7ff,#00f7ff) center / 4px 4px no-repeat,#00284899;box-shadow:0 0 8px #00f7ffb3}.plus-icon[data-v-c98402ab]{width:12px;height:12px;flex-shrink:0;background:linear-gradient(#00f7ff,#00f7ff) center / 12px 2px no-repeat,linear-gradient(#00f7ff,#00f7ff) center / 2px 12px no-repeat;box-shadow:0 0 8px #00f7ffb3}.hairline[data-v-c98402ab]{flex:1;height:1px;margin-left:4px;background:linear-gradient(90deg,rgba(0,247,255,.7) 0%,rgba(0,247,255,.18) 42%,transparent 46%,transparent 52%,rgba(0,247,255,.2) 56%,rgba(0,247,255,.05) 100%)}.title-text[data-v-c98402ab]{font-family:var(--title-font);color:#f4feff;font-size:15px;font-weight:400;letter-spacing:1px;text-shadow:0 0 8px rgba(0,247,255,.35);white-space:nowrap}.title-extra[data-v-c98402ab]{gap:8px}.title-dots[data-v-c98402ab]{display:flex;gap:4px}.title-dots i[data-v-c98402ab]{width:6px;height:6px;background:#00f7ff;box-shadow:0 0 6px #00f7ff}.panel-body[data-v-c98402ab]{flex:1;min-height:0;padding:8px 10px 10px;overflow:hidden;display:flex;flex-direction:column}.panel-body.line[data-v-c98402ab]{padding:4px 8px 8px}.flip-digit[data-v-b06c8413]{position:relative;display:inline-block;width:24px;height:38px;margin:0 1.5px;perspective:180px;font-family:var(--font-num);font-weight:700;font-size:24px;line-height:38px;color:#e8fbff;vertical-align:middle}.flip-digit.punct[data-v-b06c8413]{width:12px;background:transparent;box-shadow:none}.flip-digit.punct .static[data-v-b06c8413],.flip-digit.punct .hinge[data-v-b06c8413]{background:transparent;border:none;box-shadow:none}.static[data-v-b06c8413],.hinge[data-v-b06c8413]{position:absolute;left:0;width:100%;height:50%;overflow:hidden;background:linear-gradient(180deg,#0d2a4a,#071828);border:1px solid rgba(0,247,255,.28);box-shadow:inset 0 0 8px #00000059}.static.top[data-v-b06c8413],.hinge.top[data-v-b06c8413]{top:0;border-radius:3px 3px 0 0;border-bottom-color:#00f7ff1f}.static.bottom[data-v-b06c8413],.hinge.bottom[data-v-b06c8413]{bottom:0;border-radius:0 0 3px 3px;border-top-color:#00000059}.static i[data-v-b06c8413],.hinge i[data-v-b06c8413]{position:absolute;left:0;width:100%;height:38px;display:flex;align-items:center;justify-content:center;font-style:normal}.static.top i[data-v-b06c8413],.hinge.top i[data-v-b06c8413]{top:0}.static.bottom i[data-v-b06c8413],.hinge.bottom i[data-v-b06c8413]{bottom:0}.hinge[data-v-b06c8413]{z-index:2;backface-visibility:hidden;transform-style:preserve-3d;pointer-events:none;opacity:0}.hinge.top[data-v-b06c8413]{transform-origin:bottom center}.hinge.bottom[data-v-b06c8413]{transform-origin:top center;transform:rotateX(90deg)}.hinge.top.active[data-v-b06c8413]{opacity:1;animation:flip-top-b06c8413 .5s ease-in forwards}.hinge.bottom.active[data-v-b06c8413]{opacity:1;animation:flip-bottom-b06c8413 .5s ease-out forwards}@keyframes flip-top-b06c8413{0%{transform:rotateX(0)}to{transform:rotateX(-90deg)}}@keyframes flip-bottom-b06c8413{0%{transform:rotateX(90deg)}to{transform:rotateX(0)}}.kpi-flip-board[data-v-ccc29753]{display:flex;gap:10px;width:100%;pointer-events:auto}.kpi-flip[data-v-ccc29753]{flex:1;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;padding:10px 12px 12px;border-radius:4px;border:1px solid rgba(0,247,255,.28);background:linear-gradient(180deg,#082444e0,#030e20c7);box-shadow:inset 0 1px #ffffff0f,0 8px 20px #00000047;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.kpi-head[data-v-ccc29753]{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;min-width:0}.kpi-texts[data-v-ccc29753]{min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:2px}.kpi-label[data-v-ccc29753]{font-size:13px;font-weight:600;color:#9ad8f0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.kpi-hint[data-v-ccc29753]{font-size:10px;color:#9ed2e8b8;white-space:nowrap}.kpi-digits[data-v-ccc29753]{display:flex;align-items:center;justify-content:center;width:100%;min-height:36px}.kpi-flip[data-v-ccc29753] .kpi-ico{width:22px;height:22px;flex:0 0 auto}.tone-power[data-v-ccc29753]{border-color:#ffb44073}.tone-power .kpi-label[data-v-ccc29753]{color:#f0c878}.tone-water[data-v-ccc29753]{border-color:#38bdf873}.tone-water .kpi-label[data-v-ccc29753]{color:#7dd3fc}.tone-cool[data-v-ccc29753]{border-color:#67e8f96b}.tone-cool .kpi-label[data-v-ccc29753]{color:#a5f3fc}.tone-device[data-v-ccc29753]{border-color:#34d39973}.tone-device .kpi-label[data-v-ccc29753]{color:#6ee7b7}.tone-access[data-v-ccc29753]{border-color:#a78bfa73}.tone-access .kpi-label[data-v-ccc29753]{color:#c4b5fd}.overview-float[data-v-390066df]{position:relative;width:100%;height:100%;min-height:0;display:grid;grid-template-columns:var(--screen-side-w, clamp(280px, 24vw, 480px)) minmax(0,1fr) var( --screen-side-w, clamp(280px, 24vw, 480px) );grid-template-rows:auto 1fr;gap:10px 12px;pointer-events:none}.kpi-top[data-v-390066df]{grid-column:2;grid-row:1;min-width:0;z-index:2}.side[data-v-390066df]{min-width:0;min-height:0;height:100%;display:grid;gap:10px;pointer-events:auto}.left[data-v-390066df],.right[data-v-390066df]{grid-row:1 / -1;grid-template-rows:minmax(0,1.05fr) minmax(0,1fr) minmax(0,.95fr)}.left[data-v-390066df]{grid-column:1}.right[data-v-390066df]{grid-column:3}.center-pass[data-v-390066df]{grid-column:2;grid-row:2;pointer-events:none}.badge[data-v-390066df]{padding:1px 7px;border-radius:2px;font-size:10px;letter-spacing:.06em;background:#52c41a24;color:#7dff9a;border:1px solid rgba(82,196,26,.28)}.badge.amber[data-v-390066df]{background:#faad1424;color:#ffd666;border-color:#faad1459}.panel-stack[data-v-390066df]{flex:1;min-height:0;display:flex;flex-direction:column;gap:6px}.chart-main[data-v-390066df]{flex:1.2;min-height:0}.chart-sub[data-v-390066df]{flex:.9;min-height:0}.panel-split[data-v-390066df]{flex:1;min-height:0;display:grid;grid-template-columns:1fr 1fr;gap:6px}.panel-split--pies[data-v-390066df]{grid-template-rows:minmax(0,1fr)}.pie-col[data-v-390066df]{min-height:0;display:flex;flex-direction:column}.pie-cap[data-v-390066df]{text-align:center;font-size:10px;color:var(--panel-muted);margin-top:-2px}.digit-row[data-v-390066df]{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;flex-shrink:0}.digit-card[data-v-390066df]{padding:6px 8px;border-radius:4px;background:#061c3873;border:1px solid rgba(0,247,255,.14)}.digit-card.warn[data-v-390066df]{border-color:#faad1466}.d-label[data-v-390066df]{font-size:10px;color:var(--panel-muted)}.d-value[data-v-390066df]{margin-top:2px;font-size:15px;font-weight:600;font-family:var(--font-num);color:#fff;line-height:1.2}.d-value small[data-v-390066df]{font-size:10px;color:#c8e6f5a6;font-weight:500}.energy-digits[data-v-390066df]{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;flex-shrink:0}.ed[data-v-390066df]{padding:8px;border-radius:4px;background:#061c3873;border:1px solid rgba(0,247,255,.14)}.ed span[data-v-390066df]{display:block;font-size:10px;color:var(--panel-muted)}.ed b[data-v-390066df]{display:block;margin-top:4px;font-size:16px;font-family:var(--font-num);color:#fff}.ed small[data-v-390066df]{font-size:10px;color:#c8e6f5a6;font-weight:500}.screen-err[data-v-390066df]{position:absolute;left:50%;bottom:12px;transform:translate(-50%);z-index:8;padding:4px 12px;border-radius:4px;background:#781414bf;color:#ffb0b0;font-size:12px;pointer-events:none}.side[data-v-390066df] .echart-wrap{flex:1;min-height:0}
import{d as E,c as m,b as a,n as _,F as C,t as r,q as W,M as X,o as p,_ as A,r as H,k as Y,x as D,s as d,D as L,f as I,l as ee,C as te,p as ae,N as ie,j as oe,H as f,I as h,h as n,g as B}from"./index-BssDqbym.js";import{A as se}from"./AppIcon-C7TEwW-P.js";import{E as $,m as T,t as ne,p as V}from"./historyChart-DJ1B6lTP.js";import{t as le}from"./t-ChxyHC3f.js";import{u as re}from"./realtime-lmP-Cubp.js";const ve={class:"panel-box"},ue={class:"title-text"},ce={class:"title-main"},pe={class:"title-text"},de={class:"title-extra"},me={class:"title-frame",viewBox:"0 0 460 32",preserveAspectRatio:"none"},fe=["fill"],we=E({__name:"PanelBox",props:{title:{},variant:{default:"bar"}},setup(u){const t=`titleFill-${X()}`;return(c,l)=>(p(),m("div",ve,[a("div",{class:_(["title-bar",u.variant])},[u.variant==="line"?(p(),m(C,{key:0},[l[0]||(l[0]=a("i",{class:"plus-icon"},null,-1)),a("span",ue,r(u.title),1),l[1]||(l[1]=a("b",{class:"hairline"},null,-1))],64)):(p(),m(C,{key:1},[a("div",ce,[l[2]||(l[2]=a("i",{class:"title-icon"},null,-1)),a("span",pe,r(u.title),1)]),a("div",de,[W(c.$slots,"extra",{},void 0),l[3]||(l[3]=a("span",{class:"title-dots"},[a("i"),a("i")],-1))]),(p(),m("svg",me,[a("defs",null,[a("linearGradient",{id:t,x1:"0",y1:"0",x2:"1",y2:"0"},[...l[4]||(l[4]=[a("stop",{offset:"0%","stop-color":"#0b4d86","stop-opacity":"0.72"},null,-1),a("stop",{offset:"55%","stop-color":"#07325a","stop-opacity":"0.38"},null,-1),a("stop",{offset:"100%","stop-color":"#031528","stop-opacity":"0.08"},null,-1)])])]),a("path",{d:"M0 0 H460 V32 H0 Z",fill:`url(#${t})`},null,8,fe),l[5]||(l[5]=a("path",{d:"M0 31.3 H460",fill:"none",stroke:"#00f7ff","stroke-width":"1.4"},null,-1))]))],64))],2),a("div",{class:_(["panel-body",u.variant])},[W(c.$slots,"default",{},void 0)],2)]))}}),F=A(we,[["__scopeId","data-v-59463572"]]),ye={class:"static top"},ge={class:"static bottom"},he=E({__name:"FlipDigit",props:{char:{}},setup(u){const t=u,c=H(t.char||"0"),l=H(t.char||"0"),v=H(!1);return Y(()=>t.char,y=>{const s=y||" ";s!==c.value&&(l.value=c.value,c.value=s,!(!/[0-9]/.test(s)&&!/[0-9]/.test(l.value))&&(v.value=!1,requestAnimationFrame(()=>{v.value=!0,window.setTimeout(()=>{v.value=!1,l.value=s},520)})))}),(y,s)=>(p(),m("span",{class:_(["flip-digit",{flip:v.value,punct:!/[0-9]/.test(c.value)}])},[a("span",ye,[a("i",null,r(c.value),1)]),a("span",ge,[a("i",null,r(c.value),1)]),a("span",{class:_(["hinge top",{active:v.value}])},[a("i",null,r(l.value),1)],2),a("span",{class:_(["hinge bottom",{active:v.value}])},[a("i",null,r(c.value),1)],2)],2))}}),_e=A(he,[["__scopeId","data-v-b06c8413"]]),ke={class:"kpi-flip-board"},be={class:"kpi-head"},xe={class:"kpi-texts"},Oe={class:"kpi-label"},$e={key:0,class:"kpi-hint"},Te=["aria-label"],Ce=E({__name:"KpiFlipBoard",props:{items:{}},setup(u){const t=u;function c(v){return String(v??"").split("")}const l=d(()=>t.items||[]);return(v,y)=>(p(),m("div",ke,[(p(!0),m(C,null,D(l.value,s=>(p(),m("div",{key:s.key,class:_(["kpi-flip",s.tone?`tone-${s.tone}`:""])},[a("div",be,[s.icon?(p(),L(se,{key:0,name:s.icon,"class-name":"kpi-ico"},null,8,["name"])):I("",!0),a("div",xe,[a("div",Oe,r(s.label),1),s.hint?(p(),m("div",$e,r(s.hint),1)):I("",!0)])]),a("div",{class:"kpi-digits","aria-label":s.label},[(p(!0),m(C,null,D(c(s.value),(k,g)=>(p(),L(_e,{key:`${s.key}-${g}`,char:k},null,8,["char"]))),128))],8,Te)],2))),128))]))}}),Se=A(Ce,[["__scopeId","data-v-ccc29753"]]),Fe={deviceTotal:0,deviceOnline:0,roomOk:0,roomTotal:0,fridgeOk:0,fridgeTotal:0,alarmOpen:0,gatewayOk:!1,powerKwh:0,waterM3:0,coolingKwh:0};function Be(u){var c,l,v;const t=y=>y?Object.entries(y).map(([s,k])=>{const g=k||[];return`${s}:${g.length}:${g.map(b=>{var P,x;const O=(P=b.points)==null?void 0:P[b.points.length-1];return`${b.id}:${((x=b.points)==null?void 0:x.length)||0}:${(O==null?void 0:O.t)??""}:${(O==null?void 0:O.v)??""}`}).join(",")}`}).join("|"):"";return JSON.stringify({digits:u.digits,statusPie:u.statusPie,categoryPie:u.categoryPie,envBubbles:u.envBubbles,pauCards:u.pauCards,pressureBars:u.pressureBars,fridgeBars:u.fridgeBars,curves:t(u.curves),alarmN:((l=(c=u.snapshot)==null?void 0:c.pointAlarms)==null?void 0:l.length)??0,snapTs:((v=u.snapshot)==null?void 0:v.ts)??0})}function He(u=5e3){const t=ie(null),c=H(!1),l=H("");let v,y=!1,s="";async function k(){if(!y){y=!0;try{const g=await ae("/api/realtime/screen"),b=Be(g);b!==s&&(s=b,t.value=g),l.value=""}catch(g){t.value||(l.value=g instanceof Error?g.message:le("screen.loadFailed"))}finally{c.value=!1,y=!1}}}return ee(()=>{k(),v=window.setInterval(()=>void k(),u)}),te(()=>{v&&window.clearInterval(v)}),{data:t,loading:c,error:l,refresh:k,emptyDigits:Fe}}const Pe={class:"overview-float"},Ie={class:"kpi-top"},Ee={class:"side left"},Ae={class:"panel-stack"},De={class:"panel-split panel-split--pies"},Ne={class:"pie-col"},Re={class:"pie-cap"},We={class:"pie-col"},Le={class:"pie-cap"},Ve={class:"side right"},Ke={class:"panel-stack"},Me={class:"digit-row"},je={class:"d-label"},ze={class:"d-value"},Ue={key:0},qe={class:"badge"},Ge={class:"panel-stack"},Je={class:"energy-digits"},Qe={class:"ed"},Ze={class:"ed"},Xe={class:"ed"},Ye={key:0,class:"screen-err"},K="#9ec8dc",et=E({__name:"OverviewView",setup(u){const{t,te:c}=oe(),l=re(),{data:v,error:y}=He(5e3),s=d(()=>{var e;return(e=v.value)==null?void 0:e.digits}),k=d(()=>{var e;return((e=v.value)==null?void 0:e.snapshot)||l.snapshot}),g=d(()=>{const e=s.value;if(!e)return[{key:"online",label:t("overview.kpiOnline"),value:"—",tone:"device",icon:"kpi-device"},{key:"cold",label:t("overview.kpiCold"),value:"—",tone:"cool",icon:"kpi-cool"},{key:"env",label:t("overview.kpiEnv"),value:"—",tone:"access",icon:"kpi-access"},{key:"alarm",label:t("overview.kpiAlarm"),value:"—",tone:"power",icon:"kpi-power"}];const o=e.deviceTotal?(e.deviceOnline/e.deviceTotal*100).toFixed(0):"0",i=e.gatewayOk?t("overview.gatewayOk"):t("overview.gatewayDown");return[{key:"online",label:t("overview.kpiOnline"),value:o,hint:t("overview.gatewayHint",{online:e.deviceOnline,total:e.deviceTotal,gw:i}),tone:"device",icon:"kpi-device"},{key:"cold",label:t("overview.kpiCold"),value:`${e.fridgeOk}/${e.fridgeTotal}`,hint:e.fridgeOk===e.fridgeTotal?t("overview.allOk"):t("overview.hasWatch"),tone:"cool",icon:"kpi-cool"},{key:"env",label:t("overview.kpiEnv"),value:`${e.roomOk}/${e.roomTotal}`,hint:e.roomOk===e.roomTotal?t("overview.allNormal"):t("overview.hasWatchArea"),tone:"access",icon:"kpi-access"},{key:"alarm",label:t("overview.kpiAlarm"),value:String(e.alarmOpen),hint:e.alarmOpen?t("overview.dutyFollow"):t("overview.noOpenAlarm"),tone:e.alarmOpen?"power":"device",icon:"kpi-power"}]});function b(e,o){return e&&c(`status.${e}`)?t(`status.${e}`):{在线:t("status.online"),告警:t("status.alarm"),离线:t("status.offline"),未知:t("status.unknown")}[o]||o}function O(e,o){return c(`deviceCat.${e}`)?t(`deviceCat.${e}`):o}function P(e,o){return e&&c(`pau.${e}`)?t(`pau.${e}`):o}const x=d(()=>{var e;return(e=v.value)==null?void 0:e.curves}),M=d(()=>{var e;return T(((e=x.value)==null?void 0:e.roomHumidity)||[],{unit:"%RH",maxSeries:10})}),j=d(()=>{var e;return T(((e=x.value)==null?void 0:e.roomTemp)||[],{unit:"℃",maxSeries:10})}),z=d(()=>{var o,i;const e=((o=x.value)==null?void 0:o.fridgeTemp)||[];return e.length?T(e,{unit:"℃",maxSeries:10}):T(ne(((i=v.value)==null?void 0:i.fridgeSeries)||[]),{unit:"℃",maxSeries:10})}),N=d(()=>{const e=s.value;return e?e.fridgeTotal===0?{text:t("overview.noFridge"),amber:!0}:e.fridgeOk<e.fridgeTotal?{text:t("overview.fridgeWatch",{n:e.fridgeTotal-e.fridgeOk}),amber:!0}:{text:t("overview.allNormal"),amber:!1}:{text:t("overview.collecting"),amber:!1}}),U=d(()=>{var i;const e=((i=v.value)==null?void 0:i.statusPie)||[],o={online:"#52c41a",alarm:"#faad14",offline:"#ff4d4f",unknown:"#5a7a90",在线:"#52c41a",告警:"#faad14",离线:"#ff4d4f",未知:"#5a7a90"};return{backgroundColor:"transparent",animation:!1,animationDurationUpdate:0,tooltip:V(),series:[{type:"pie",radius:["42%","68%"],center:["50%","52%"],animation:!1,label:{color:K,fontSize:10,formatter:`{b}
{c}`},data:e.map(w=>({name:b(w.key,w.name),value:w.value,itemStyle:{color:o[w.key||""]||o[w.name]||"#37c8ff"}}))}]}}),q=d(()=>{var o;const e=((o=v.value)==null?void 0:o.categoryPie)||[];return{backgroundColor:"transparent",animation:!1,animationDurationUpdate:0,tooltip:V(),series:[{type:"pie",radius:["36%","62%"],center:["50%","52%"],roseType:"radius",animation:!1,label:{color:K,fontSize:9,formatter:"{b}"},data:e.map(i=>({name:O(i.category,i.name),value:i.value}))}]}}),G=d(()=>{var e;return(((e=v.value)==null?void 0:e.pauCards)||[]).map(o=>({...o,label:P(o.key,o.label)}))}),J=d(()=>{const e=x.value,o=[...((e==null?void 0:e.hvacSupplyTemp)||[]).map(i=>({...i,name:t("overview.seriesSupplyTemp",{name:i.name||i.id})})),...((e==null?void 0:e.vavAirflow)||[]).map(i=>({...i,name:t("overview.seriesAirflow",{name:i.name||i.id})}))];return T(o,{maxSeries:8})}),Q=d(()=>{var i;const e=((i=x.value)==null?void 0:i.roomPressure)||[],o=e.filter(w=>/缓冲|气锁|负压|PCR|buffer|airlock/i.test(w.name||w.id));return T(o.length?o:e,{unit:"Pa",maxSeries:10})}),R=d(()=>{var o;const e=(((o=v.value)==null?void 0:o.pressureBars)||[]).filter(i=>/缓冲|气锁|负压|buffer|airlock/i.test(i.name));return e.length?e.every(i=>i.ok):!0}),Z=d(()=>{const e=x.value,o=[...((e==null?void 0:e.meteringPower)||[]).map(i=>({...i,name:t("overview.seriesPower")})),...((e==null?void 0:e.meteringWater)||[]).map(i=>({...i,name:t("overview.seriesWater")})),...((e==null?void 0:e.meteringCooling)||[]).map(i=>({...i,name:t("overview.seriesCooling")}))];return T(o,{maxSeries:6})}),S=d(()=>s.value);return(e,o)=>(p(),m("div",Pe,[a("div",Ie,[f(Se,{items:g.value},null,8,["items"])]),a("div",Ee,[f(F,{title:n(t)("overview.envTitle")},{extra:h(()=>{var i,w;return[a("span",{class:_(["badge",{amber:(((i=s.value)==null?void 0:i.roomOk)??0)<(((w=s.value)==null?void 0:w.roomTotal)??0)}])},r(s.value?n(t)("overview.envQualified",{ok:s.value.roomOk,total:s.value.roomTotal}):n(t)("overview.deviceLedger")),3)]}),default:h(()=>[a("div",Ae,[f($,{class:"chart-main",option:M.value,"empty-text":n(t)("overview.roomHumidityEmpty")},null,8,["option","empty-text"]),f($,{class:"chart-sub",option:j.value,"empty-text":n(t)("overview.roomTempEmpty")},null,8,["option","empty-text"])])]),_:1},8,["title"]),f(F,{title:n(t)("overview.coldTitle")},{extra:h(()=>[a("span",{class:_(["badge",{amber:N.value.amber}])},r(N.value.text),3)]),default:h(()=>[f($,{option:z.value,"empty-text":n(t)("overview.coldEmpty")},null,8,["option","empty-text"])]),_:1},8,["title"]),f(F,{title:n(t)("overview.deviceStatus")},{extra:h(()=>{var i,w;return[a("span",{class:_(["badge",{amber:(((i=s.value)==null?void 0:i.alarmOpen)??0)>0}])},r((w=s.value)!=null&&w.alarmOpen?n(t)("overview.alarmCount",{n:s.value.alarmOpen}):n(t)("overview.runOk")),3)]}),default:h(()=>[a("div",De,[a("div",Ne,[f($,{option:U.value,"empty-text":n(t)("overview.noDevice")},null,8,["option","empty-text"]),a("div",Re,r(n(t)("overview.onlineStatus")),1)]),a("div",We,[f($,{option:q.value,"empty-text":n(t)("overview.noCategory")},null,8,["option","empty-text"]),a("div",Le,r(n(t)("overview.deviceCats")),1)])])]),_:1},8,["title"])]),o[3]||(o[3]=a("div",{class:"center-pass","aria-hidden":"true"},null,-1)),a("div",Ve,[f(F,{title:n(t)("overview.systemTitle")},{extra:h(()=>[a("span",{class:_(["badge",{amber:!k.value.hvac.systemRunning}])},r(k.value.hvac.systemRunning?n(t)("overview.unitRunning"):n(t)("overview.unitIdle")),3)]),default:h(()=>[a("div",Ke,[a("div",Me,[(p(!0),m(C,null,D(G.value,i=>(p(),m("div",{key:i.key||i.label,class:_(["digit-card",{warn:i.ok===!1}])},[a("div",je,r(i.label),1),a("div",ze,[i.value===null?(p(),m(C,{key:0},[B("—")],64)):(p(),m(C,{key:1},[B(r(i.unit===""?i.value?n(t)("screen.switchOn"):n(t)("screen.switchOff"):i.value.toFixed(1))+" ",1),i.unit?(p(),m("small",Ue,r(i.unit),1)):I("",!0)],64))])],2))),128))]),f($,{class:"chart-sub",option:J.value,"empty-text":n(t)("overview.systemEmpty")},null,8,["option","empty-text"])])]),_:1},8,["title"]),f(F,{title:n(t)("overview.bioTitle")},{extra:h(()=>[a("span",{class:_(["badge",{amber:!R.value}])},r(R.value?n(t)("overview.interlockOk"):n(t)("overview.pressureWatch")),3)]),default:h(()=>[f($,{option:Q.value,"empty-text":n(t)("overview.pressureEmpty")},null,8,["option","empty-text"])]),_:1},8,["title"]),f(F,{title:n(t)("overview.energyTitle")},{extra:h(()=>[a("span",qe,r(n(t)("overview.timeseries")),1)]),default:h(()=>[a("div",Ge,[a("div",Je,[a("div",Qe,[a("span",null,r(n(t)("overview.powerTotal")),1),a("b",null,[B(r(S.value?S.value.powerKwh.toFixed(1):"—")+" ",1),o[0]||(o[0]=a("small",null,"kWh",-1))])]),a("div",Ze,[a("span",null,r(n(t)("overview.water")),1),a("b",null,[B(r(S.value?S.value.waterM3.toFixed(1):"—")+" ",1),o[1]||(o[1]=a("small",null,"m³",-1))])]),a("div",Xe,[a("span",null,r(n(t)("overview.cooling")),1),a("b",null,[B(r(S.value?S.value.coolingKwh.toFixed(0):"—")+" ",1),o[2]||(o[2]=a("small",null,"kWh",-1))])])]),f($,{class:"chart-main",option:Z.value,"empty-text":n(t)("overview.energyEmpty")},null,8,["option","empty-text"])])]),_:1},8,["title"])]),n(y)?(p(),m("div",Ye,r(n(y)),1)):I("",!0)]))}}),nt=A(et,[["__scopeId","data-v-60f2b453"]]);export{nt as default};
import{d as A,c as d,b as t,n as b,F as O,t as u,m as R,I as Z,o as c,_ as H,r as P,q as Q,z as V,B as p,x as K,f as D,j as X,s as Y,l as ee,J as te,D as f,E as y,h as E,g as C}from"./index-Bs_x-_cK.js";import{A as ae}from"./AppIcon-Ds6CYf3P.js";import{E as $,c as se,r as L,m as T,t as le,p as W}from"./historyChart-DTdcyadg.js";import{u as oe}from"./realtime-CI_KLy_N.js";const ne={class:"panel-box"},ie={class:"title-text"},re={class:"title-main"},ue={class:"title-text"},ce={class:"title-extra"},pe={class:"title-frame",viewBox:"0 0 460 32",preserveAspectRatio:"none"},de=["fill"],ve=A({__name:"PanelBox",props:{title:{},variant:{default:"bar"}},setup(r){const v=`titleFill-${Z()}`;return(o,l)=>(c(),d("div",ne,[t("div",{class:b(["title-bar",r.variant])},[r.variant==="line"?(c(),d(O,{key:0},[l[0]||(l[0]=t("i",{class:"plus-icon"},null,-1)),t("span",ie,u(r.title),1),l[1]||(l[1]=t("b",{class:"hairline"},null,-1))],64)):(c(),d(O,{key:1},[t("div",re,[l[2]||(l[2]=t("i",{class:"title-icon"},null,-1)),t("span",ue,u(r.title),1)]),t("div",ce,[R(o.$slots,"extra",{},void 0),l[3]||(l[3]=t("span",{class:"title-dots"},[t("i"),t("i")],-1))]),(c(),d("svg",pe,[t("defs",null,[t("linearGradient",{id:v,x1:"0",y1:"0",x2:"1",y2:"0"},[...l[4]||(l[4]=[t("stop",{offset:"0%","stop-color":"#0b4d86","stop-opacity":"0.72"},null,-1),t("stop",{offset:"55%","stop-color":"#07325a","stop-opacity":"0.38"},null,-1),t("stop",{offset:"100%","stop-color":"#031528","stop-opacity":"0.08"},null,-1)])])]),t("path",{d:"M0 0 H460 V32 H0 Z",fill:`url(#${v})`},null,8,de),l[5]||(l[5]=t("path",{d:"M0 31.3 H460",fill:"none",stroke:"#00f7ff","stroke-width":"1.4"},null,-1))]))],64))],2),t("div",{class:b(["panel-body",r.variant])},[R(o.$slots,"default",{},void 0)],2)]))}}),B=H(ve,[["__scopeId","data-v-c98402ab"]]),me={class:"static top"},fe={class:"static bottom"},ge=A({__name:"FlipDigit",props:{char:{}},setup(r){const v=r,o=P(v.char||"0"),l=P(v.char||"0"),n=P(!1);return Q(()=>v.char,g=>{const i=g||" ";i!==o.value&&(l.value=o.value,o.value=i,!(!/[0-9]/.test(i)&&!/[0-9]/.test(l.value))&&(n.value=!1,requestAnimationFrame(()=>{n.value=!0,window.setTimeout(()=>{n.value=!1,l.value=i},520)})))}),(g,i)=>(c(),d("span",{class:b(["flip-digit",{flip:n.value,punct:!/[0-9]/.test(o.value)}])},[t("span",me,[t("i",null,u(o.value),1)]),t("span",fe,[t("i",null,u(o.value),1)]),t("span",{class:b(["hinge top",{active:n.value}])},[t("i",null,u(l.value),1)],2),t("span",{class:b(["hinge bottom",{active:n.value}])},[t("i",null,u(o.value),1)],2)],2))}}),he=H(ge,[["__scopeId","data-v-b06c8413"]]),ye={class:"kpi-flip-board"},be={class:"kpi-head"},ke={class:"kpi-texts"},_e={class:"kpi-label"},xe={key:0,class:"kpi-hint"},$e=["aria-label"],we=A({__name:"KpiFlipBoard",props:{items:{}},setup(r){const v=r;function o(n){return String(n??"").split("")}const l=p(()=>v.items||[]);return(n,g)=>(c(),d("div",ye,[(c(!0),d(O,null,V(l.value,i=>(c(),d("div",{key:i.key,class:b(["kpi-flip",i.tone?`tone-${i.tone}`:""])},[t("div",be,[i.icon?(c(),K(ae,{key:0,name:i.icon,"class-name":"kpi-ico"},null,8,["name"])):D("",!0),t("div",ke,[t("div",_e,u(i.label),1),i.hint?(c(),d("div",xe,u(i.hint),1)):D("",!0)])]),t("div",{class:"kpi-digits","aria-label":i.label},[(c(!0),d(O,null,V(o(i.value),(k,m)=>(c(),K(he,{key:`${i.key}-${m}`,char:k},null,8,["char"]))),128))],8,$e)],2))),128))]))}}),Oe=H(we,[["__scopeId","data-v-ccc29753"]]),Se={deviceTotal:0,deviceOnline:0,roomOk:0,roomTotal:0,fridgeOk:0,fridgeTotal:0,alarmOpen:0,gatewayOk:!1,powerKwh:0,waterM3:0,coolingKwh:0};function Te(r){var o,l,n;const v=g=>g?Object.entries(g).map(([i,k])=>{const m=k||[];return`${i}:${m.length}:${m.map(_=>{var F,M;const x=(F=_.points)==null?void 0:F[_.points.length-1];return`${_.id}:${((M=_.points)==null?void 0:M.length)||0}:${(x==null?void 0:x.t)??""}:${(x==null?void 0:x.v)??""}`}).join(",")}`}).join("|"):"";return JSON.stringify({digits:r.digits,statusPie:r.statusPie,categoryPie:r.categoryPie,envBubbles:r.envBubbles,pauCards:r.pauCards,pressureBars:r.pressureBars,fridgeBars:r.fridgeBars,curves:v(r.curves),alarmN:((l=(o=r.snapshot)==null?void 0:o.pointAlarms)==null?void 0:l.length)??0,snapTs:((n=r.snapshot)==null?void 0:n.ts)??0})}function Be(r=5e3){const v=te(null),o=P(!1),l=P("");let n,g=!1,i="";async function k(){if(!g){g=!0;try{const m=await ee("/api/realtime/screen"),_=Te(m);_!==i&&(i=_,v.value=m),l.value=""}catch(m){v.value||(l.value=m instanceof Error?m.message:"大屏数据加载失败")}finally{o.value=!1,g=!1}}}return X(()=>{k(),n=window.setInterval(()=>void k(),r)}),Y(()=>{n&&window.clearInterval(n)}),{data:v,loading:o,error:l,refresh:k,emptyDigits:Se}}const Fe={class:"overview-float"},Ce={class:"kpi-top"},Pe={class:"side left"},Me={class:"panel-stack"},ze={class:"panel-split panel-split--pies"},Ie={class:"pie-col"},De={class:"pie-col"},Ae={class:"side right"},He={class:"panel-stack"},Le={class:"digit-row"},Ve={class:"d-label"},Ne={class:"d-value"},Re={key:0},Ke={class:"panel-stack"},Ee={class:"energy-digits"},We={class:"ed"},je={class:"ed"},Ue={class:"ed"},qe={key:0,class:"screen-err"},z="#9ec8dc",I="rgba(158,200,220,0.35)",Je=A({__name:"OverviewView",setup(r){const v=oe(),{data:o,error:l}=Be(5e3),n=p(()=>{var e;return(e=o.value)==null?void 0:e.digits}),g=p(()=>{var e;return((e=o.value)==null?void 0:e.snapshot)||v.snapshot}),i=p(()=>{const e=n.value;return e?[{key:"online",label:"设备在线率 %",value:e.deviceTotal?(e.deviceOnline/e.deviceTotal*100).toFixed(0):"0",hint:`${e.deviceOnline}/${e.deviceTotal} · 网关${e.gatewayOk?"通":"断"}`,tone:"device",icon:"kpi-device"},{key:"cold",label:"冷链正常",value:`${e.fridgeOk}/${e.fridgeTotal}`,hint:e.fridgeOk===e.fridgeTotal?"全部达标":"有关注项",tone:"cool",icon:"kpi-cool"},{key:"env",label:"环境合格区",value:`${e.roomOk}/${e.roomTotal}`,hint:e.roomOk===e.roomTotal?"全部正常":"有关注区",tone:"access",icon:"kpi-access"},{key:"alarm",label:"当前告警",value:String(e.alarmOpen),hint:e.alarmOpen?"值班跟进中":"无未闭环",tone:e.alarmOpen?"power":"device",icon:"kpi-power"}]:[{key:"online",label:"设备在线率 %",value:"—",tone:"device",icon:"kpi-device"},{key:"cold",label:"冷链正常",value:"—",tone:"cool",icon:"kpi-cool"},{key:"env",label:"环境合格区",value:"—",tone:"access",icon:"kpi-access"},{key:"alarm",label:"当前告警",value:"—",tone:"power",icon:"kpi-power"}]}),k=p(()=>{var s;const e=(((s=o.value)==null?void 0:s.envBubbles)||[]).filter(a=>a.temp!==null&&a.humidity!==null);return{backgroundColor:"transparent",animation:!1,animationDurationUpdate:0,grid:{left:36,right:12,top:28,bottom:28},tooltip:{...se,trigger:"item",formatter:a=>{const w=a.data;return w!=null&&w.value?`<div style="font-size:11px;color:#e8fbff;font-weight:600">${w.name??""}</div><div style="font-size:10px;margin-top:2px">温度 ${L(w.value[0])}℃ · 湿度 ${L(w.value[1])}%</div><div style="font-size:10px">压差 ${L(w.pressure)} Pa</div>`:""}},xAxis:{name:"℃",nameTextStyle:{color:I,fontSize:10},axisLabel:{color:z,fontSize:10},splitLine:{lineStyle:{color:"rgba(0,247,255,0.08)"}},axisLine:{lineStyle:{color:I}}},yAxis:{name:"%RH",nameTextStyle:{color:I,fontSize:10},axisLabel:{color:z,fontSize:10},splitLine:{lineStyle:{color:"rgba(0,247,255,0.08)"}},axisLine:{lineStyle:{color:I}}},series:[{type:"scatter",symbolSize:a=>Math.max(10,Math.min(36,Math.abs(Number(a[2])||0)*1.2+10)),data:e.map(a=>({value:[Math.round(a.temp*10)/10,Math.round(a.humidity*10)/10,Math.round(Math.abs(a.pressure??0)*10)/10],name:a.name,pressure:a.pressure==null?null:Math.round(a.pressure*10)/10,itemStyle:{color:a.ok?"rgba(82,196,26,0.85)":"rgba(250,173,20,0.9)"}}))}]}}),m=p(()=>{var e;return(e=o.value)==null?void 0:e.curves}),_=p(()=>{var e;return T(((e=m.value)==null?void 0:e.roomTemp)||[],{unit:"℃",maxSeries:10})}),x=p(()=>{var s,a;const e=((s=m.value)==null?void 0:s.fridgeTemp)||[];return e.length?T(e,{unit:"℃",maxSeries:10}):T(le(((a=o.value)==null?void 0:a.fridgeSeries)||[]),{unit:"℃",maxSeries:10})}),F=p(()=>{const e=n.value;return e?e.fridgeTotal===0?{text:"无冰箱设备",amber:!0}:e.fridgeOk<e.fridgeTotal?{text:`${e.fridgeTotal-e.fridgeOk}台关注`,amber:!0}:{text:"全部正常",amber:!1}:{text:"采集中",amber:!1}}),M=p(()=>{var a;const e=((a=o.value)==null?void 0:a.statusPie)||[],s={在线:"#52c41a",告警:"#faad14",离线:"#ff4d4f",未知:"#5a7a90"};return{backgroundColor:"transparent",animation:!1,animationDurationUpdate:0,tooltip:W(),series:[{type:"pie",radius:["42%","68%"],center:["50%","52%"],animation:!1,label:{color:z,fontSize:10,formatter:`{b}
{c}`},data:e.map(h=>({name:h.name,value:h.value,itemStyle:{color:s[h.name]||"#37c8ff"}}))}]}}),j=p(()=>{var s;const e=((s=o.value)==null?void 0:s.categoryPie)||[];return{backgroundColor:"transparent",animation:!1,animationDurationUpdate:0,tooltip:W(),series:[{type:"pie",radius:["36%","62%"],center:["50%","52%"],roseType:"radius",animation:!1,label:{color:z,fontSize:9,formatter:"{b}"},data:e.map(a=>({name:a.name,value:a.value}))}]}}),U=p(()=>{var e;return((e=o.value)==null?void 0:e.pauCards)||[]}),q=p(()=>{const e=m.value,s=[...((e==null?void 0:e.hvacSupplyTemp)||[]).map(a=>({...a,name:`${a.name||a.id}·送风温`})),...((e==null?void 0:e.vavAirflow)||[]).map(a=>({...a,name:`${a.name||a.id}·风量`}))];return T(s,{maxSeries:8})}),J=p(()=>{var a;const e=((a=m.value)==null?void 0:a.roomPressure)||[],s=e.filter(h=>/缓冲|气锁|负压|PCR/i.test(h.name||h.id));return T(s.length?s:e,{unit:"Pa",maxSeries:10})}),N=p(()=>{var s;const e=(((s=o.value)==null?void 0:s.pressureBars)||[]).filter(a=>/缓冲|气锁|负压/i.test(a.name));return e.length?e.every(a=>a.ok):!0}),G=p(()=>{const e=m.value,s=[...((e==null?void 0:e.meteringPower)||[]).map(a=>({...a,name:"用电 kWh"})),...((e==null?void 0:e.meteringWater)||[]).map(a=>({...a,name:"用水 m³"})),...((e==null?void 0:e.meteringCooling)||[]).map(a=>({...a,name:"冷量 kWh"}))];return T(s,{maxSeries:6})}),S=p(()=>n.value);return(e,s)=>(c(),d("div",Fe,[t("div",Ce,[f(Oe,{items:i.value},null,8,["items"])]),t("div",Pe,[f(B,{title:"环境总览"},{extra:y(()=>{var a,h;return[t("span",{class:b(["badge",{amber:(((a=n.value)==null?void 0:a.roomOk)??0)<(((h=n.value)==null?void 0:h.roomTotal)??0)}])},u(n.value?`${n.value.roomOk}/${n.value.roomTotal} 合格`:"设备台账"),3)]}),default:y(()=>[t("div",Me,[f($,{class:"chart-main",option:k.value,"empty-text":"房间温湿度待采集"},null,8,["option"]),f($,{class:"chart-sub",option:_.value,"empty-text":"房间温度历史积累中"},null,8,["option"])])]),_:1}),f(B,{title:"冷链监测 · 24h"},{extra:y(()=>[t("span",{class:b(["badge",{amber:F.value.amber}])},u(F.value.text),3)]),default:y(()=>[f($,{option:x.value,"empty-text":"冰箱温度历史积累中"},null,8,["option"])]),_:1}),f(B,{title:"设备状态"},{extra:y(()=>{var a,h;return[t("span",{class:b(["badge",{amber:(((a=n.value)==null?void 0:a.alarmOpen)??0)>0}])},u((h=n.value)!=null&&h.alarmOpen?`${n.value.alarmOpen}项告警`:"运行正常"),3)]}),default:y(()=>[t("div",ze,[t("div",Ie,[f($,{option:M.value,"empty-text":"无设备"},null,8,["option"]),s[0]||(s[0]=t("div",{class:"pie-cap"},"在线状态",-1))]),t("div",De,[f($,{option:j.value,"empty-text":"无分类"},null,8,["option"]),s[1]||(s[1]=t("div",{class:"pie-cap"},"设备分类",-1))])])]),_:1})]),s[9]||(s[9]=t("div",{class:"center-pass","aria-hidden":"true"},null,-1)),t("div",Ae,[f(B,{title:"系统运行状态"},{extra:y(()=>[t("span",{class:b(["badge",{amber:!g.value.hvac.systemRunning}])},u(g.value.hvac.systemRunning?"机组运行":"未启动/无信号"),3)]),default:y(()=>[t("div",He,[t("div",Le,[(c(!0),d(O,null,V(U.value,a=>(c(),d("div",{key:a.label,class:b(["digit-card",{warn:a.ok===!1}])},[t("div",Ve,u(a.label),1),t("div",Ne,[a.value===null?(c(),d(O,{key:0},[C("—")],64)):(c(),d(O,{key:1},[C(u(a.unit===""?a.value?"开":"关":a.value.toFixed(1))+" ",1),a.unit?(c(),d("small",Re,u(a.unit),1)):D("",!0)],64))])],2))),128))]),f($,{class:"chart-sub",option:q.value,"empty-text":"机组/VAV 历史积累中"},null,8,["option"])])]),_:1}),f(B,{title:"生物安全压差 · 24h"},{extra:y(()=>[t("span",{class:b(["badge",{amber:!N.value}])},u(N.value?"联锁正常":"压差关注"),3)]),default:y(()=>[f($,{option:J.value,"empty-text":"压差历史积累中"},null,8,["option"])]),_:1}),f(B,{title:"能耗与绿色 · 24h"},{extra:y(()=>[...s[2]||(s[2]=[t("span",{class:"badge"},"时序",-1)])]),default:y(()=>[t("div",Ke,[t("div",Ee,[t("div",We,[s[4]||(s[4]=t("span",null,"总用电",-1)),t("b",null,[C(u(S.value?S.value.powerKwh.toFixed(1):"—")+" ",1),s[3]||(s[3]=t("small",null,"kWh",-1))])]),t("div",je,[s[6]||(s[6]=t("span",null,"用水",-1)),t("b",null,[C(u(S.value?S.value.waterM3.toFixed(1):"—")+" ",1),s[5]||(s[5]=t("small",null,"m³",-1))])]),t("div",Ue,[s[8]||(s[8]=t("span",null,"冷量",-1)),t("b",null,[C(u(S.value?S.value.coolingKwh.toFixed(0):"—")+" ",1),s[7]||(s[7]=t("small",null,"kWh",-1))])])]),f($,{class:"chart-main",option:G.value,"empty-text":"能耗历史积累中"},null,8,["option"])])]),_:1})]),E(l)?(c(),d("div",qe,u(E(l)),1)):D("",!0)]))}}),Ye=H(Je,[["__scopeId","data-v-390066df"]]);export{Ye as default};
import{E as r,m as n}from"./historyChart-DTdcyadg.js";import{u as d}from"./useMetricHistory-Ck1zYYEr.js";import{u as x}from"./realtime-CI_KLy_N.js";import{d as y,c as a,b as e,D as u,h as o,F as b,z as S,B as p,o as i,t as l,y as P,_ as w}from"./index-Bs_x-_cK.js";const B={class:"page-fill pressure-page"},F={class:"panel",style:{flex:"1","min-height":"0",display:"flex","flex-direction":"column",gap:"10px",overflow:"hidden"}},L={class:"charts"},V={class:"chart-card"},k={class:"chart-card"},E={class:"table-wrap"},O={class:"table"},z=y({__name:"PressureView",setup(C){const c=x(),{series:m,loading:h}=d(()=>({source:"room",metric:"pressure"})),{series:v,loading:_}=d(()=>({source:"room",metric:"temp"})),g=p(()=>n(m.value,{unit:"Pa",maxSeries:14})),f=p(()=>n(v.value,{unit:"℃",maxSeries:14}));return(D,t)=>(i(),a("div",B,[e("section",F,[t[3]||(t[3]=e("div",{class:"panel-head"},[e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"房间压差集中监控")]),e("div",{class:"badge"},"实时 + 近24h")],-1)),e("div",L,[e("div",V,[t[0]||(t[0]=e("div",{class:"chart-title"},"压差历史 Pa",-1)),u(r,{option:g.value,loading:o(h),"empty-text":"压差历史积累中"},null,8,["option","loading"])]),e("div",k,[t[1]||(t[1]=e("div",{class:"chart-title"},"温度历史 ℃",-1)),u(r,{option:f.value,loading:o(_),"empty-text":"温度历史积累中"},null,8,["option","loading"])])]),e("div",E,[e("table",O,[t[2]||(t[2]=e("thead",null,[e("tr",null,[e("th",null,"房间"),e("th",null,"压差 (Pa)"),e("th",null,"温度 (℃)"),e("th",null,"湿度 (%)"),e("th",null,"告警")])],-1)),e("tbody",null,[(i(!0),a(b,null,S(o(c).snapshot.rooms,s=>(i(),a("tr",{key:s.id},[e("td",null,l(s.name),1),e("td",{style:P({color:s.alarms.length?"var(--red)":"var(--green)"})},l(s.pressure.toFixed(1)),5),e("td",null,l(s.temp.toFixed(1)),1),e("td",null,l(s.humidity),1),e("td",null,l(s.alarms.join("、")||"正常"),1)]))),128))])])])])]))}}),M=w(z,[["__scopeId","data-v-9d9108d2"]]);export{M as default};
.pressure-page[data-v-4f9dd116]{display:flex;min-height:0}.charts[data-v-4f9dd116]{display:grid;grid-template-columns:1fr 1fr;gap:10px;min-height:240px;flex:1}.chart-card[data-v-4f9dd116]{min-height:0;display:flex;flex-direction:column;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-4f9dd116]{font-size:12px;color:var(--label);margin-bottom:4px}.chart-card[data-v-4f9dd116] .echart-wrap{flex:1;min-height:180px}.table-wrap[data-v-4f9dd116]{max-height:260px;overflow:auto}
.pressure-page[data-v-9d9108d2]{display:flex;min-height:0}.charts[data-v-9d9108d2]{display:grid;grid-template-columns:1fr 1fr;gap:10px;min-height:240px;flex:1}.chart-card[data-v-9d9108d2]{min-height:0;display:flex;flex-direction:column;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.chart-title[data-v-9d9108d2]{font-size:12px;color:var(--label);margin-bottom:4px}.chart-card[data-v-9d9108d2] .echart-wrap{flex:1;min-height:180px}.table-wrap[data-v-9d9108d2]{max-height:260px;overflow:auto}
import{d as f,j as b,c as l,b as e,t,h as s,H as n,F as S,x as E,s as c,E as H,o as i,_ as w}from"./index-BssDqbym.js";import{E as d,m as p}from"./historyChart-DJ1B6lTP.js";import{u as m}from"./useMetricHistory-CLFOMuUx.js";import{u as F}from"./realtime-lmP-Cubp.js";const L={class:"page-fill pressure-page"},P={class:"panel",style:{flex:"1","min-height":"0",display:"flex","flex-direction":"column",gap:"10px",overflow:"hidden"}},V={class:"panel-head"},k={class:"panel-title"},B={class:"badge"},O={class:"charts"},j={class:"chart-card"},C={class:"chart-title"},I={class:"chart-card"},N={class:"chart-title"},T={class:"table-wrap"},z={class:"table"},A=f({__name:"PressureView",setup(D){const{t:o}=b(),u=F(),{series:_,loading:h}=m(()=>({source:"room",metric:"pressure"})),{series:g,loading:v}=m(()=>({source:"room",metric:"temp"})),x=c(()=>p(_.value,{unit:"Pa",maxSeries:14})),y=c(()=>p(g.value,{unit:"℃",maxSeries:14}));return(M,r)=>(i(),l("div",L,[e("section",P,[e("div",V,[e("div",k,[r[0]||(r[0]=e("div",{class:"vbar"},null,-1)),e("h3",null,t(s(o)("pages.pressureTitle")),1)]),e("div",B,t(s(o)("common.realtime24h")),1)]),e("div",O,[e("div",j,[e("div",C,t(s(o)("pages.pressureHist")),1),n(d,{option:x.value,loading:s(h),"empty-text":s(o)("pages.pressureEmpty")},null,8,["option","loading","empty-text"])]),e("div",I,[e("div",N,t(s(o)("pages.tempHist")),1),n(d,{option:y.value,loading:s(v),"empty-text":s(o)("pages.tempEmpty")},null,8,["option","loading","empty-text"])])]),e("div",T,[e("table",z,[e("thead",null,[e("tr",null,[e("th",null,t(s(o)("common.room")),1),e("th",null,t(s(o)("pages.colPressure")),1),e("th",null,t(s(o)("pages.colTemp")),1),e("th",null,t(s(o)("pages.colHumidity")),1),e("th",null,t(s(o)("pages.colAlarm")),1)])]),e("tbody",null,[(i(!0),l(S,null,E(s(u).snapshot.rooms,a=>(i(),l("tr",{key:a.id},[e("td",null,t(a.name),1),e("td",{style:H({color:a.alarms.length?"var(--red)":"var(--green)"})},t(a.pressure.toFixed(1)),5),e("td",null,t(a.temp.toFixed(1)),1),e("td",null,t(a.humidity),1),e("td",null,t(a.alarms.join("、")||s(o)("common.normal")),1)]))),128))])])])])]))}}),K=w(A,[["__scopeId","data-v-4f9dd116"]]);export{K as default};
import{j as se,k as we,r as x,l as Ve,d as re,c as k,b as s,h as S,t as $,m as ze,o as w,_ as de,p as dt,q as Z,s as Ae,x as Fe,w as j,y as ae,n as A,F as J,z as Q,f as W,T as qe,B as F,C as je,D as z,g as he,u as ct,a as ut,E as Te,G as mt,i as ft,H as pt}from"./index-Bs_x-_cK.js";import{u as We}from"./realtime-CI_KLy_N.js";import{u as vt}from"./useClock-liJ_G-iS.js";import{A as q}from"./AppIcon-Ds6CYf3P.js";import{u as bt,p as gt}from"./useRtengineBridge-zn3rZLWd.js";const ht=900*1e3;function yt(){const a=x("澳门"),r=x("--"),l=x("获取中"),h=x("--");let p;async function n(){try{const c=await Ve("/api/weather/macau");a.value=c.place||"澳门",r.value=c.temp||"--",l.value=c.text||"—",h.value=c.humidity||"--"}catch{l.value="暂无数据"}}return se(()=>{n(),p=window.setInterval(()=>void n(),ht)}),we(()=>{p&&window.clearInterval(p)}),{place:a,temp:r,text:l,humidity:h}}function wt(){const a=x({position:"fixed",inset:"0",width:"100%",height:"100%",transform:"none",left:"0",top:"0"});function r(){const l=window.innerWidth,h=Math.round(Math.min(480,Math.max(280,l*.24)));document.documentElement.style.setProperty("--screen-side-w",`${h}px`),document.documentElement.style.setProperty("--screen-vw",`${l}px`),document.documentElement.style.setProperty("--screen-vh",`${window.innerHeight}px`)}return se(()=>{r(),window.addEventListener("resize",r)}),we(()=>window.removeEventListener("resize",r)),{style:a}}const kt="/assets/header-bar-CT0XVael.png",xt={class:"screen-header-hy"},_t=["src"],It={class:"slot-left"},Et={class:"slot-right"},$t=re({__name:"ScreenHeader",props:{title:{}},setup(a){return(r,l)=>(w(),k("header",xt,[s("img",{class:"banner",src:S(kt),alt:""},null,8,_t),s("h1",null,$(a.title||"分子实验室三维可视化管理平台"),1),s("div",It,[ze(r.$slots,"left",{},void 0)]),s("div",Et,[ze(r.$slots,"right",{},void 0)])]))}}),Mt=de($t,[["__scopeId","data-v-83363d93"]]),Ue=dt("screenMode",()=>{const a=x("pressure");function r(l){a.value=l}return{mode:a,setMode:r}}),Ct=[{id:"seq",name:"测序区",viewpoint:"测序区",roomId:"seq"},{id:"lib-2",name:"文库制备区2",viewpoint:"文库制备区2",roomId:"lib-2"},{id:"lib-1",name:"文库制备区1",viewpoint:"文库制备区1",roomId:"lib-1"},{id:"sample-2",name:"样本制备区2",viewpoint:"样本制备区2",roomId:"sample-2"},{id:"sample-1",name:"样本制备区1",viewpoint:"样本制备区1",roomId:"sample-1"},{id:"consult",name:"咨询室",viewpoint:"咨询室",roomId:"recv"},{id:"prep",name:"准备区",viewpoint:"准备区",roomId:"reagent"},{id:"report",name:"报告室",viewpoint:"报告室",roomId:"report"}],Ht={pressure:"pressure",lightN:"lightN",lightE:"lightE",fridge:"fridge",vav:"vav",camera:"camera",access:"access"},Pt=[{id:"home",label:"全景总览"},{id:"camera",label:"监控"},{id:"access",label:"门禁"},{id:"pressure",label:"压差"},{id:"lightN",label:"普通照明"},{id:"lightE",label:"应急照明"},{id:"fridge",label:"冰箱"},{id:"vav",label:"通风柜"},{id:"e066",label:"E栋1F066冰箱"}],St=Pt.filter(a=>a.id!=="e066"&&a.id!=="home"),Rt=[{id:"p-seq",mode:"pressure",label:"测序区",roomHint:"测序区",bind:{kind:"room",roomId:"seq"},x:133.54306829,y:22.19722037,z:53.009},{id:"p-seq-buf",mode:"pressure",label:"测序区缓冲",roomHint:"测序区缓冲",bind:{kind:"room",roomId:"seq-buf"},x:133.54303821,y:22.19722473,z:51.299},{id:"p-lib-2",mode:"pressure",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"room",roomId:"lib-2"},x:133.54306137,y:22.1971966,z:53.3},{id:"p-lib-2-buf",mode:"pressure",label:"文库制备区2缓冲",roomHint:"文库制备区2缓冲",bind:{kind:"room",roomId:"lib-2-buf"},x:133.54302644,y:22.19721349,z:53.858},{id:"p-lib-1",mode:"pressure",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"room",roomId:"lib-1"},x:133.54306985,y:22.19716263,z:51.299},{id:"p-lib-1-buf",mode:"pressure",label:"文库制备区1缓冲",roomHint:"文库制备区1缓冲",bind:{kind:"room",roomId:"lib-1-buf"},x:133.54303366,y:22.19717608,z:51.499},{id:"p-sample-2",mode:"pressure",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"room",roomId:"sample-2"},x:133.54305343,y:22.19715687,z:52.67},{id:"p-sample-1",mode:"pressure",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"room",roomId:"sample-1"},x:133.54303277,y:22.19715687,z:53.924},{id:"p-sample-buf",mode:"pressure",label:"样本制备区缓冲",roomHint:"样本制备区缓冲",bind:{kind:"room",roomId:"sample-buf"},x:133.54300622,y:22.19717578,z:54.124},{id:"p-recv",mode:"pressure",label:"收样咨询室",roomHint:"咨询室",bind:{kind:"room",roomId:"recv"},x:133.54308054,y:22.19712738,z:52.734},{id:"p-reagent",mode:"pressure",label:"试剂准备间",roomHint:"准备区",bind:{kind:"room",roomId:"reagent"},x:133.54302092,y:22.19715687,z:53.729},{id:"p-report",mode:"pressure",label:"生信分析报告室",roomHint:"报告室",bind:{kind:"room",roomId:"report"},x:133.54300854,y:22.19715864,z:54.059},{id:"p-pcr",mode:"pressure",label:"PCR走廊",roomHint:"PCR走廊",bind:{kind:"room",roomId:"pcr-corridor"},x:133.54298833,y:22.19716597,z:53.436}],Lt=[{id:"ln-seq",mode:"lightN",label:"测序区",roomHint:"测序区",bind:{kind:"neLight",lightId:"n-seq"},x:133.54306571,y:22.19722162,z:53.31},{id:"ln-lib-2",mode:"lightN",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"neLight",lightId:"n-lib-2"},x:133.54305879,y:22.19719785,z:53.6},{id:"ln-lib-1",mode:"lightN",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"neLight",lightId:"n-lib-1"},x:133.54306727,y:22.19716387,z:51.6},{id:"ln-sample-2",mode:"lightN",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"neLight",lightId:"n-sample-2"},x:133.54305085,y:22.19715811,z:52.97},{id:"ln-sample-1",mode:"lightN",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"neLight",lightId:"n-sample-1"},x:133.54303019,y:22.19715811,z:54.22},{id:"ln-report",mode:"lightN",label:"报告室",roomHint:"报告室",bind:{kind:"neLight",lightId:"n-report"},x:133.54300596,y:22.19715989,z:54.36},{id:"ln-corridor",mode:"lightN",label:"NGS走廊",roomHint:"PCR走廊",bind:{kind:"neLight",lightId:"n-corridor"},x:133.54298833,y:22.19716597,z:53.74}],zt=[{id:"le-seq-buf",mode:"lightE",label:"测序区缓冲",roomHint:"测序区缓冲",bind:{kind:"neLight",lightId:"e-seq-buf"},x:133.54303649,y:22.19722556,z:51.65},{id:"le-seq",mode:"lightE",label:"测序区",roomHint:"测序区",bind:{kind:"neLight",lightId:"e-seq"},x:133.54307173,y:22.19721871,z:53.36},{id:"le-lib-2-buf",mode:"lightE",label:"文库制备区2缓冲",roomHint:"文库制备区2缓冲",bind:{kind:"neLight",lightId:"e-lib-2-buf"},x:133.54302472,y:22.19721432,z:54.21},{id:"le-lib-2",mode:"lightE",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"neLight",lightId:"e-lib-2"},x:133.54306481,y:22.19719494,z:53.65},{id:"le-lib-1-buf",mode:"lightE",label:"文库制备区1缓冲",roomHint:"文库制备区1缓冲",bind:{kind:"neLight",lightId:"e-lib-1-buf"},x:133.54303194,y:22.19717691,z:51.85},{id:"le-lib-1",mode:"lightE",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"neLight",lightId:"e-lib-1"},x:133.54307329,y:22.19716096,z:51.65},{id:"le-sample-1-buf",mode:"lightE",label:"样本制备区1缓冲",roomHint:"样本制备区缓冲",bind:{kind:"neLight",lightId:"e-sample-1-buf"},x:133.5430045,y:22.19717661,z:54.47},{id:"le-sample-2",mode:"lightE",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"neLight",lightId:"e-sample-2"},x:133.54305687,y:22.1971552,z:53.02},{id:"le-sample-1",mode:"lightE",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"neLight",lightId:"e-sample-1"},x:133.54303621,y:22.1971552,z:54.27},{id:"le-report",mode:"lightE",label:"报告室",roomHint:"报告室",bind:{kind:"neLight",lightId:"e-report"},x:133.54301112,y:22.19715739,z:54.41},{id:"le-prep",mode:"lightE",label:"准备间",roomHint:"准备区",bind:{kind:"neLight",lightId:"e-prep"},x:133.5430235,y:22.19715562,z:54.08},{id:"le-recv",mode:"lightE",label:"咨询室",roomHint:"咨询室",bind:{kind:"neLight",lightId:"e-recv"},x:133.54308312,y:22.19712613,z:53.08},{id:"le-corridor",mode:"lightE",label:"走廊",roomHint:"PCR走廊",bind:{kind:"neLight",lightId:"e-corridor"},x:133.54297987,y:22.19715486,z:53.79}],Tt=[{id:"f-recv-1",mode:"fridge",label:"收样咨询室冰箱1",roomHint:"咨询室",bind:{kind:"fridge",deviceId:"mb-104-rtu-3-收样咨询室冰箱1"},x:133.54307894,y:22.19713424,z:52.98},{id:"f-recv-2",mode:"fridge",label:"收样咨询室冰箱2",roomHint:"咨询室",bind:{kind:"fridge",deviceId:"mb-104-rtu-4-收样咨询室冰箱2"},x:133.54307355,y:22.19712468,z:52.98},{id:"f-lib-1",mode:"fridge",label:"文库制备区1冰箱",roomHint:"文库制备区1",bind:{kind:"fridge",deviceId:"mb-104-rtu-6-文库制备区1冰箱"},x:133.54306507,y:22.1971619,z:51.55},{id:"f-lib-2",mode:"fridge",label:"文库制备区2冰箱",roomHint:"文库制备区2",bind:{kind:"fridge",deviceId:"mb-104-rtu-7-文库制备区2冰箱"},x:133.54305179,y:22.19719515,z:53.55},{id:"f-sample-1",mode:"fridge",label:"样本制备区1冰箱",roomHint:"样本制备区1",bind:{kind:"fridge",deviceId:"mb-104-rtu-5-样本制备区1冰箱"},x:133.54303441,y:22.19715202,z:54.17},{id:"f-seq",mode:"fridge",label:"测序区冰箱1",roomHint:"测序区",bind:{kind:"fridge",deviceId:"mb-104-rtu-8-测序区冰箱1"},x:133.54307704,y:22.19722424,z:53.26},{id:"f-reagent-1",mode:"fridge",label:"试剂准备间冰箱1",roomHint:"准备区",bind:{kind:"fridge",deviceId:"mb-104-rtu-1-试剂准备间冰箱1"},x:133.54301972,y:22.19716251,z:53.98},{id:"f-reagent-2",mode:"fridge",label:"试剂准备间冰箱2",roomHint:"准备区",bind:{kind:"fridge",deviceId:"mb-104-rtu-2-试剂准备间冰箱2"},x:133.54301523,y:22.19715455,z:53.98}],Nt=[{id:"v-lib-1",mode:"vav",label:"文库制备1通风柜",roomHint:"文库制备区1",bind:{kind:"vav",deviceId:"mb-103-文库制备1通风柜"},x:133.54308365,y:22.19715798,z:51.5},{id:"v-lib-2",mode:"vav",label:"文库制备2通风柜",roomHint:"文库制备区2",bind:{kind:"vav",deviceId:"mb-103-文库制备2通风柜"},x:133.54307292,y:22.19718797,z:53.5}],ce=[...Rt,...Lt,...zt,...Tt,...Nt],Dt=[{prefix:"监控-",mode:"camera"},{prefix:"门禁-",mode:"access"},{prefix:"压差-",mode:"pressure"},{prefix:"普通照明-",mode:"lightN"},{prefix:"应急照明-",mode:"lightE"},{prefix:"冰箱-",mode:"fridge"},{prefix:"通风柜-",mode:"vav"}],Ot=[{test:/cctv/i,mode:"camera"},{test:/access-control/i,mode:"access"},{test:/speedometer/i,mode:"pressure"},{test:/electricity-meter-blue/i,mode:"lightN"},{test:/electricity-meter-orange/i,mode:"lightE"},{test:/temperature-sensor/i,mode:"fridge"},{test:/motor-green|moter-green/i,mode:"vav"}];function ke(a){const r=(a.name||"").trim();for(const n of Dt)if(r.startsWith(n.prefix))return n.mode;const l=(a.tag0||"").trim();if(l==="screen-mode"&&a.tag1){const n=ce.find(c=>c.id===a.tag1);if(n)return n.mode}const h=l.toLowerCase();if(h==="camera")return"camera";if(h==="access")return"access";if(l==="pressure"||l==="lightN"||l==="lightE"||l==="fridge"||l==="vav")return l;const p=a.icon||"";for(const n of Ot)if(n.test.test(p))return n.mode;return null}function Bt(a,r){const l=a.replace(/^(压差|普通照明|应急照明|冰箱|通风柜)-/,"").trim(),h=ce.filter(m=>m.mode===r),p=h.find(m=>m.label===l||m.label===a||m.roomHint===l);if(p)return p;let n,c=0;for(const m of h)for(const v of[m.label,m.roomHint]){if(!v)continue;let g=0;l===v?g=100+v.length:l.includes(v)?g=v.length:v.includes(l)&&l.length>=2&&(g=l.length),g>c&&(c=g,n=m)}return n}const Vt={open:"开启",closed:"关闭",alarm:"报警",offline:"离线"};function At(a,r){var p;const l=a.bind;if(l.kind==="room"){const n=r.rooms.find(m=>m.id===l.roomId),c=[{label:"温度",value:`${V(n==null?void 0:n.temp)} ℃`},{label:"湿度",value:`${V(n==null?void 0:n.humidity,0)} %`},{label:"压差",value:`${V(n==null?void 0:n.pressure)} Pa`}];return(p=n==null?void 0:n.alarms)!=null&&p.length&&c.push({label:"报警",value:n.alarms.join("、")}),c}if(l.kind==="fridge"){const n=r.fridges.find(c=>c.id===l.deviceId);return[{label:"温度",value:`${V(n==null?void 0:n.temp)} ℃`},{label:"湿度",value:`${V(n==null?void 0:n.humidity,0)} %`}]}if(l.kind==="vav"){const n=r.vav.find(c=>c.id===l.deviceId);return[{label:"状态",value:n?n.running?"运行":"停止":"--"},{label:"面风速",value:`${V(n==null?void 0:n.faceVelocity)} m/s`},{label:"视窗高度",value:`${V(n==null?void 0:n.sashHeight)} mm`},{label:"风量",value:`${V(n==null?void 0:n.airflow,0)} m³/h`},{label:"阀门开度",value:`${V(n==null?void 0:n.valveOpen,0)} %`},{label:"最大排风",value:n?n.maxExhaust?"是":"否":"--"},{label:"最小风量",value:n?n.minAirflow?"是":"否":"--"},{label:"报警码",value:n?n.alarmCode?String(n.alarmCode):"无":"--"}]}const h=(r.neLights||[]).find(n=>n.id===l.lightId);return[{label:"区域",value:a.roomHint||a.label},{label:"状态",value:h?h.on?"开":"关":"--"}]}function Ne(a,r){const l=a.tag1?ce.find(m=>m.id===a.tag1):void 0,h=(l==null?void 0:l.mode)||ke(a);if(!h||h==="camera")return null;const p=(a.name||(l==null?void 0:l.label)||"").trim(),n=p||"设备";if(h==="access"){const m=p.replace(/^门禁-/,"").replace(/门禁$/,"").trim(),v=r.access.doors.find(g=>{const _=g.name.replace(/门禁$/,"");return g.name.includes(m)||m.includes(_)||_.includes(m)});return{title:n,lines:[{label:"门点",value:(v==null?void 0:v.name)||p||"--"},{label:"状态",value:v?Vt[v.status]||v.status:"--"},{label:"今日通行",value:String(r.access.todayPassCount??"--")}]}}const c=l||Bt(p,h);return c?{title:p||c.label,lines:At(c,r)}:{title:n,lines:[{label:"数据",value:"--"}]}}function V(a,r=1){return a==null||!Number.isFinite(Number(a))?"--":Number(a).toFixed(r)}const Ft={key:0,class:"near-layer"},qt=["aria-label"],jt=["title"],Wt=["src"],Ut={key:1,class:"near-values"},De=400,Oe=36,Xt=re({__name:"MarkerNearDialog",props:{open:{type:Boolean},title:{},left:{},top:{},src:{default:"/cams/lab-seq.mp4"},kind:{default:"video"},lines:{default:()=>[]}},emits:["close"],setup(a,{emit:r}){const l=a,h=r,p=F(()=>{if(l.kind==="values"){const d=Math.max(l.lines.length,1);return Math.min(420,Oe+d*36+16)}return 240}),n=x(0),c=x(0),m=x(!1);let v=0,g=0;function _(d,u){const I=window.innerWidth,E=window.innerHeight;return{left:Math.max(0,Math.min(Math.round(d),Math.max(0,I-De))),top:Math.max(0,Math.min(Math.round(u),Math.max(0,E-p.value)))}}function M(){const d=_(l.left,l.top);n.value=d.left,c.value=d.top}Z(()=>[l.open,l.left,l.top],([d])=>{d&&M()},{immediate:!0});const N=F(()=>({left:`${n.value}px`,top:`${c.value}px`,width:`${De}px`,height:`${p.value}px`})),R=F(()=>p.value-Oe);function P(d){d.key==="Escape"&&L()}function T(d){var I,E;if(d.button!==0||(E=(I=d.target)==null?void 0:I.closest)!=null&&E.call(I,".near-close"))return;d.currentTarget.setPointerCapture(d.pointerId),m.value=!0,v=d.clientX-n.value,g=d.clientY-c.value}function C(d){if(!m.value)return;const u=_(d.clientX-v,d.clientY-g);n.value=u.left,c.value=u.top}function D(d){if(m.value){m.value=!1;try{d.currentTarget.releasePointerCapture(d.pointerId)}catch{}}}function L(d){d==null||d.preventDefault(),d==null||d.stopPropagation(),m.value&&(m.value=!1),h("close")}return Z(()=>l.open,d=>{d?window.addEventListener("keydown",P):window.removeEventListener("keydown",P)}),Ae(()=>window.removeEventListener("keydown",P)),(d,u)=>(w(),Fe(qe,{to:"body"},[a.open?(w(),k("div",Ft,[s("div",{class:"near-backdrop",onPointerdown:L,onClick:u[0]||(u[0]=j(()=>{},["prevent","stop"]))},null,32),s("div",{class:"near-dialog",style:ae(N.value),role:"dialog","aria-label":a.title,onPointerdown:u[1]||(u[1]=j(()=>{},["stop"])),onClick:u[2]||(u[2]=j(()=>{},["stop"]))},[s("header",{class:"near-head",onPointerdown:T,onPointermove:C,onPointerup:D,onPointercancel:D},[s("h3",{title:a.title},$(a.title),9,jt),s("button",{class:"near-close",type:"button","aria-label":"关闭",onPointerdown:j(L,["stop"]),onClick:j(L,["stop","prevent"])}," × ",32)],32),s("div",{class:A(["near-body",{"near-body--values":a.kind==="values"}]),style:ae({height:`${R.value}px`})},[a.kind!=="values"?(w(),k("video",{key:0,class:"near-video",src:a.src,autoplay:"",muted:"",loop:"",playsinline:"",controls:""},null,8,Wt)):(w(),k("ul",Ut,[(w(!0),k(J,null,Q(a.lines,I=>(w(),k("li",{key:I.label},[s("span",null,$(I.label),1),s("b",null,$(I.value),1)]))),128))]))],6)],44,qt)])):W("",!0)]))}}),Yt=de(Xt,[["__scopeId","data-v-369dcccd"]]),Gt="sm:";function Kt(a){try{return new URL(a,window.location.href).searchParams.get("scene")||""}catch{return""}}async function Jt(a){const r=Kt(a);if(!r)return[];const l=[`/rtengine/designer/data/scenes/${encodeURIComponent(r)}.json`,`/designer/data/scenes/${encodeURIComponent(r)}.json`,`/designer/api/embed/scenes/${encodeURIComponent(r)}`,`/rtengine/api/scenes/${encodeURIComponent(r)}`];for(const h of l)try{const p=await fetch(h);if(!p.ok)continue;const n=await p.json(),c=Array.isArray(n.components)?n.components:[],m=[];for(const v of c){if(!v||typeof v!="object")continue;const g=v;if(g.type!=="marker"||g.id==null)continue;const _=g.params||{};m.push({id:String(g.id),name:String(g.name||_.text||_.name||""),icon:String(_.icon||_.url||""),tag0:String(_.tag0||"")})}if(m.length)return m}catch{}return[]}function Qt(a,r,l){const h=Ue(),{mode:p}=je(h);let n=[],c=!1,m=!1,v,g,_=0;function M(){_=24,!g&&(g=window.setInterval(()=>{_-=1,r.value&&a.ready.value&&P(p.value),_<=0&&g&&(window.clearInterval(g),g=void 0)},700))}async function N(){if(!(c||m)){m=!0;try{n=await Jt(l),c=n.length>0}finally{m=!1}}}function R(){for(const C of ce)try{a.removeMarker(`${Gt}${C.id}`)}catch{}}function P(C){var d;if(!r.value||!a.ready.value)return;R(),a.hidePois("screen-mode");const D=((d=a.listMarkers)==null?void 0:d.call(a))||[],L=D.length?D:n;for(const u of Object.values(Ht))C!=="home"&&C!==u&&a.hidePois(u);C!=="home"&&C!=="camera"&&a.hidePois("Camera"),C!=="home"&&C!=="access"&&a.hidePois("Access"),C!=="home"&&a.hidePois("Devices");for(const u of L){const I=ke(u),E=C==="home"||C!=="e066"&&I!=null&&C===I;a.setMarkerVisible(u.id,E)}}async function T(){await N(),P(p.value),c||window.setTimeout(()=>{N().then(()=>P(p.value))},2e3)}return Z([p,r,()=>a.ready.value],()=>{window.clearTimeout(v),v=window.setTimeout(()=>{M(),T()},80)},{flush:"post"}),{clearModeMarkers:R,syncModePois:T}}const Zt={key:0,class:"vp-corners"},en={key:1,class:"vp-topbar"},tn={class:"area"},nn={class:"view"},on={class:"vp-area-side","aria-label":"设备分类"},ln=["onClick"],an={class:"name"},sn={class:"vp-mode-bar","aria-label":"区域飞视"},rn=["onClick"],dn={key:3,class:"vp-room-panel"},cn={class:"vp-room-head"},un={class:"vp-room-list"},mn=["onClick"],fn={class:"name"},pn=["src"],vn={key:6,class:"vp-tip"},bn={key:0},gn={key:1},ye="overview",Be="全景总览",hn=re({__name:"SceneViewport",props:{areaLabel:{default:""},layout:{default:"inset"}},setup(a){const r=a,l=We(),h=Ue(),{mode:p}=je(h),n="/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/rtengine/gis.html?scene=mvlpj2yt6379aa29",c=F(()=>!!n),m=x(null),v=x(null),g=x(""),_=x([]),M=x(!1),N=x("监控预览"),R=x("video"),P=x([]),T=x(null),C=x(120),D=x(120);let L=0;const d=x(null),u=x(!1);let I=!1,E=!1,ee=!1,Y=null;const G=x(null);function xe(){var e,t;try{return((t=(e=v.value)==null?void 0:e.contentDocument)==null?void 0:t.querySelector("video"))??null}catch{return null}}function Xe(e,t){var K;const o=xe(),i=(K=v.value)==null?void 0:K.getBoundingClientRect();if(!i)return null;const f=(o==null?void 0:o.clientWidth)||i.width,y=(o==null?void 0:o.clientHeight)||i.height,b=(o==null?void 0:o.videoWidth)||0,H=(o==null?void 0:o.videoHeight)||0;if(!b||!H||f<=0||y<=0)return{x:e,y:t};const O=o?getComputedStyle(o).objectFit:"fill";if(O==="contain"||O==="scale-down"){const B=Math.min(f/b,y/H),pe=b*B,ve=H*B,be=(f-pe)/2,ge=(y-ve)/2;return{x:be+e*B,y:ge+t*B}}if(O==="cover"){const B=Math.max(f/b,y/H),pe=b*B,ve=H*B,be=(f-pe)/2,ge=(y-ve)/2;return{x:be+e*B,y:ge+t*B}}return{x:e/b*f,y:t/H*y}}function te(e){const t=v.value;if(!t)return null;const o=t.getBoundingClientRect(),i=getComputedStyle(t),f=parseFloat(i.borderLeftWidth)||0,y=parseFloat(i.borderTopWidth)||0;return{left:o.left+f+e.x,top:o.top+y+e.y}}function ne(e){const t=te({x:e.clientX,y:e.clientY});t&&(G.value=t),d.value={x:e.clientX,y:e.clientY}}function _e(){var t;Ie();const e=(t=v.value)==null?void 0:t.contentDocument;e&&(e.addEventListener("pointerdown",ne,!0),e.addEventListener("click",ne,!0),Y=e)}function Ie(){Y&&(Y.removeEventListener("pointerdown",ne,!0),Y.removeEventListener("click",ne,!0),Y=null)}function Ye(){return{left:Math.max(0,Math.round(window.innerWidth/2-200)),top:Math.max(0,Math.round(window.innerHeight/2-120))}}function Ee(e){if(!e||typeof e!="object")return null;const t=[e],o=e;o.data&&typeof o.data=="object"&&t.push(o.data),o.metaData&&typeof o.metaData=="object"&&t.push(o.metaData);for(const i of t){const f=Number(i.screenX??i.clientX??i.mouseX??i.px??i.screen_x??i.ScreenX??i.viewportX),y=Number(i.screenY??i.clientY??i.mouseY??i.py??i.screen_y??i.ScreenY??i.viewportY);if(Number.isFinite(f)&&Number.isFinite(y)&&(f!==0||y!==0))return{x:f,y}}return null}function $e(e){var b;const t=(b=v.value)==null?void 0:b.getBoundingClientRect();if(!t)return null;const o=xe(),i=(o==null?void 0:o.videoWidth)||0,f=(o==null?void 0:o.videoHeight)||0;if(i>t.width+8&&f>t.height+8&&(e.x>t.width+1||e.y>t.height+1)&&e.x>=0&&e.y>=0&&e.x<=i+2&&e.y<=f+2){const H=Xe(e.x,e.y);return H?te(H):null}return e.x>=0&&e.y>=0&&e.x<=t.width+2&&e.y<=t.height+2?te(e):e.x>=0&&e.y>=0&&e.x<=window.innerWidth&&e.y<=window.innerHeight?{left:e.x,top:e.y}:null}function Ge(e,t){var f,y;if(G.value){const b=G.value;return G.value=null,b}const o=d.value;if(o){const b=te(o);if(b)return b}const i=Ee(t);if(i){const b=$e(i);if(b)return b}if(e)try{const b=(f=v.value)==null?void 0:f.contentWindow,H=(y=b==null?void 0:b.$gisObj)==null?void 0:y.getMarker;if(typeof H=="function"){const O=H.call(b==null?void 0:b.$gisObj,e),K=Ee(O);if(K)return $e(K)}}catch{}return null}function Me(e,t,o){if(Date.now()<L)return;const i=Ge(t,o)||Ye();N.value=e,C.value=Math.round(i.left),D.value=Math.round(i.top),M.value=!0}function Ke(){M.value=!1,L=Date.now()+400,G.value=null}function Je(){return _.value.filter(e=>e.enabled&&e.scenePoint).map(e=>({id:e.id,name:e.name,text:e.name,x:e.scenePoint.x,y:e.scenePoint.y,z:e.scenePoint.z,icon:e.scenePoint.icon||"cctv-blue.png",tag0:"camera",tag1:e.id}))}async function Qe(){if(!(!c.value||ee||E)){E=!0;try{await gt(void 0,n),h.setMode("pressure"),await Pe(),ue(!0),oe(),await ie(),fe(Be),window.setTimeout(()=>{I||ue(!0),oe(),ie()},1500),window.setTimeout(()=>{ie()},3500)}catch{ue(!0)}finally{E=!1,ee=!0}}}function Ze(){return p.value==="home"||p.value==="camera"}function oe(){const e=Ze();for(const t of _.value)t.scenePoint&&U.setMarkerVisible(t.id,e)}function ue(e=!1){if(!c.value||I&&!e)return;const t=Je();t.length&&(U.addMarkers(t),I=!0,oe())}function me(e){return String(e||"").trim().replace(/^cam:/i,"")}function Ce(e){const t=e.trim();return!!(!t||/^cam:/i.test(t)||/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(t)||/^[0-9a-f]{16,}$/i.test(t))}function et(e,t){const o=[t,e.id,e.tag1,e.tag2,e.name].map(me).filter(Boolean);for(const f of o){const y=_.value.find(b=>b.id===f);if(y)return y}const i=(e.name||"").trim();if(i&&!Ce(i)){const f=_.value.find(y=>y.name===i||y.location===i);if(f)return f}return null}function tt(e,t,o){const i=((e==null?void 0:e.name)||(e==null?void 0:e.location)||"").trim();if(i)return i;const f=(t.name||"").trim(),y=new Set([o,t.id,t.tag1,t.tag0,t.tag2].map(me).filter(Boolean));return f&&!Ce(f)&&!y.has(me(f))?f:"监控预览"}function nt(e){if(Date.now()<L||M.value)return;const{markerId:t,marker:o,raw:i}=e;if(!t&&!o.id&&!o.tag0&&!o.name)return;const f=et(o,t),y=ke(o);if(T.value=o,y==="camera"||f){R.value="video",P.value=[],Me(tt(f,o,t),t||o.id,i);return}const b=Ne(o,l.snapshot);b&&(R.value="values",P.value=b.lines,Me(b.title,t||o.id,i))}const U=bt({iframeRef:v,cloudUrl:n,onReady:()=>{Qe(),_e(),ie()},onMouseClick:nt}),ot=F(()=>r.layout==="fill"&&c.value),{syncModePois:ie}=Qt(U,ot,n);function He(e){return e.filter(t=>t.enabled&&t.scenePoint).map(t=>{const o=t.scenePoint;return`${t.id}:${o.x},${o.y},${o.z},${o.icon||""}`}).sort().join("|")}async function Pe(){try{const t=(await Ve("/api/video/devices")).devices||[],o=He(_.value)!==He(t);_.value=t,o&&(I=!1)}catch{}}function it(){_e(),window.setTimeout(()=>U.markReady(),2500)}function lt(e){for(const t of Object.getOwnPropertySymbols(e)){const o=e[t];if(o&&typeof o=="object"&&typeof o.initializePan=="function"&&typeof o.onMouseDown=="function")return o}return null}function le(){const e=m.value;if(!e)return!1;const t=lt(e);if(!(t!=null&&t.onMouseDown)||t.__mouseSwapped)return!!(t!=null&&t.__mouseSwapped);const o=t.onMouseDown.bind(t);return t.onMouseDown=i=>{const f=i.button===0?2:i.button===2?0:i.button,y=new Proxy(i,{get(b,H){if(H==="button")return f;const O=Reflect.get(b,H,b);return typeof O=="function"?O.bind(b):O}});o(y)},t.__mouseSwapped=!0,!0}function Se(){le()||requestAnimationFrame(()=>{le()||window.setTimeout(()=>le(),300)})}const X=F(()=>{const t=r.layout==="fill"&&c.value?null:l.snapshot.rooms;return Ct.map(o=>{const i=t==null?void 0:t.find(f=>f.id===o.roomId);return{id:o.id,name:o.name,viewpoint:o.viewpoint,roomId:o.roomId,temp:(i==null?void 0:i.temp)??null,humidity:(i==null?void 0:i.humidity)??null,pressure:(i==null?void 0:i.pressure)??null,alarms:(i==null?void 0:i.alarms)??[]}})}),at=F(()=>X.value.find(e=>e.id===g.value)||X.value.find(e=>e.roomId===l.selectedRoomId)||X.value[0]),st=F(()=>"RTEngineHD 云渲染");function fe(e){e&&U.flyToBookmark(e)}function Re(e){const t=X.value.find(o=>o.id===e);t&&(g.value=t.id,l.selectRoom(t.roomId),c.value&&fe(t.viewpoint))}function Le(){g.value=ye,h.setMode("home"),c.value&&fe(Be)}function rt(e){h.setMode(e)}return Z(p,()=>oe()),Z(()=>l.snapshot.ts,()=>{if(!M.value||R.value!=="values"||!T.value)return;const e=Ne(T.value,l.snapshot);e&&(P.value=e.lines)}),se(()=>{if(Pe(),r.layout==="fill"&&(u.value=!!document.getElementById("screen-float-overlays"),u.value||requestAnimationFrame(()=>{u.value=!!document.getElementById("screen-float-overlays")})),c.value){window.setTimeout(()=>U.markReady(),6e3);return}const e=m.value;e==null||e.addEventListener("load",Se),le()}),Ae(()=>{var e;(e=m.value)==null||e.removeEventListener("load",Se),Ie()}),(e,t)=>{var o;return w(),k("div",{class:A(["viewport",{"viewport--fill":r.layout==="fill"}])},[r.layout!=="fill"?(w(),k("div",Zt,[...t[1]||(t[1]=[s("i",null,null,-1),s("i",null,null,-1),s("i",null,null,-1),s("i",null,null,-1)])])):W("",!0),r.layout!=="fill"?(w(),k("div",en,[z(q,{name:"pin"}),s("span",tn,$(a.areaLabel||`当前区域:${((o=at.value)==null?void 0:o.name)||"—"}`),1),t[2]||(t[2]=s("span",{class:"sep"},null,-1)),s("span",nn,$(st.value),1)])):W("",!0),r.layout==="fill"&&u.value?(w(),Fe(qe,{key:2,to:"#screen-float-overlays",defer:""},[s("div",on,[(w(!0),k(J,null,Q(S(St),i=>(w(),k("button",{key:i.id,type:"button",class:A(["vp-area-side-item",{active:i.id===S(p)}]),onClick:f=>rt(i.id)},[s("span",an,$(i.label),1)],10,ln))),128))]),s("div",sn,[s("button",{type:"button",class:A(["vp-mode-item",{active:g.value===ye}]),onClick:Le},[z(q,{name:"pin","class-name":"room-ico"}),t[3]||(t[3]=s("span",null,"全景总览",-1))],2),(w(!0),k(J,null,Q(X.value,i=>(w(),k("button",{key:i.id,type:"button",class:A(["vp-mode-item",{active:i.id===g.value,alarm:i.alarms.length>0}]),onClick:f=>Re(i.id)},[z(q,{name:"pin","class-name":"room-ico"}),s("span",null,$(i.name),1)],10,rn))),128))])])):r.layout!=="fill"?(w(),k("div",dn,[s("div",cn,[z(q,{name:"pin"}),t[4]||(t[4]=s("div",null,[s("div",{class:"vp-room-label"},"区域导航"),s("div",{class:"vp-room-sub"},"点击飞视点")],-1))]),s("div",un,[s("button",{type:"button",class:A(["vp-room-item",{active:g.value===ye}]),onClick:Le},[z(q,{name:"pin","class-name":"room-ico"}),t[5]||(t[5]=s("span",{class:"name"},"全景总览",-1))],2),(w(!0),k(J,null,Q(X.value,i=>(w(),k("button",{key:i.id,type:"button",class:A(["vp-room-item",{active:i.id===g.value,alarm:i.alarms.length>0}]),onClick:f=>Re(i.id)},[z(q,{name:"pin","class-name":"room-ico"}),s("span",fn,$(i.name),1)],10,mn))),128))])])):W("",!0),c.value?(w(),k("iframe",{key:4,ref_key:"cloudFrameRef",ref:v,class:"ue-frame",src:S(n),title:"RTEngineHD Cloud Render",allow:"autoplay; fullscreen; microphone; camera; clipboard-read; clipboard-write; display-capture",allowfullscreen:"",referrerpolicy:"no-referrer-when-downgrade",onLoad:it},null,40,pn)):(w(),k("model-viewer",{key:5,ref_key:"viewerRef",ref:m,class:"scene",src:"/models/scene-model.glb","camera-controls":"","auto-rotate":"","shadow-intensity":"0.6",exposure:"1.1","interaction-prompt":"none",onContextmenu:t[0]||(t[0]=j(()=>{},["prevent"]))},null,544)),r.layout!=="fill"?(w(),k("div",vn,[z(q,{name:"hand","class-name":"hand"}),c.value?(w(),k("span",bn," RTEngineHD 云渲染 · 在画面内操作漫游 · 底部点选区域飞视点 ")):(w(),k("span",gn,[...t[6]||(t[6]=[s("b",null,"左键",-1),he(" 拖动 · ",-1),s("b",null,"右键",-1),he(" 旋转 · ",-1),s("b",null,"滚轮",-1),he(" 缩放 · 底部点选区域 ",-1)])]))])):W("",!0),z(Yt,{open:M.value,title:N.value,kind:R.value,lines:P.value,left:C.value,top:D.value,src:"/cams/lab-seq.mp4",onClose:Ke},null,8,["open","title","kind","lines","left","top"])],2)}}}),yn=de(hn,[["__scopeId","data-v-e3a57494"]]),wn={class:"scene-layer"},kn={class:"ui-layer"},xn={class:"weather-wrap"},_n={class:"place"},In={class:"temp"},En={class:"w-text"},$n={class:"humid"},Mn={class:"clock-wrap"},Cn={class:"time"},Hn={class:"date"},Pn={class:"alarm-wrap"},Sn=["aria-expanded"],Rn={class:"screen-main screen-main--float"},Ln={class:"alarm-dd-head"},zn={class:"alarm-dd-list"},Tn={class:"a-txt"},Nn={class:"a-title"},Dn={class:"a-sub"},On={class:"a-state"},Bn=re({__name:"ScreenLayout",setup(a){const r=ct(),l=We(),h=ft(),{time:p,date:n}=vt(),{place:c,temp:m,text:v,humidity:g}=yt(),{style:_}=wt(),M=x(!1),N=x(null),R=x({}),P=F(()=>{const d=l.snapshot.pointAlarms||[];return d.length?d.slice(0,12).map(u=>({level:u.level==="red"?"red":"amber",title:u.message,sub:u.name||"点位超限",state:"关注中"})):[{level:"calm",title:"系统运行正常",sub:"点位阈值监测中",state:"正常"}]});se(()=>{l.connect(),r.isLoggedIn&&!r.user&&r.fetchMe().catch(()=>{}),window.addEventListener("keydown",T)}),we(()=>{l.disconnect(),window.removeEventListener("keydown",T)});function T(d){d.key==="Escape"&&(M.value=!1)}function C(){const d=N.value,u=d==null?void 0:d.closest(".stage");if(!d||!u)return;const I=d.getBoundingClientRect(),E=u.getBoundingClientRect();R.value={top:`${Math.round(I.bottom-E.top+8)}px`,right:`${Math.round(E.right-I.right)}px`}}async function D(){M.value=!M.value,M.value&&(await mt(),C())}function L(){r.isLoggedIn?h.push("/admin"):h.push({path:"/login",query:{redirect:"/admin"}})}return(d,u)=>{const I=pt("RouterView");return w(),k("div",{class:"stage stage--immersive",style:ae(S(_))},[u[4]||(u[4]=s("div",{id:"screen-float-overlays",class:"screen-float-overlays"},null,-1)),s("div",wn,[z(yn,{layout:"fill"})]),u[5]||(u[5]=ut('<div class="edge-mask" aria-hidden="true" data-v-e06f39ec><i class="edge edge-t" data-v-e06f39ec></i><i class="edge edge-b" data-v-e06f39ec></i><i class="edge edge-l" data-v-e06f39ec></i><i class="edge edge-r" data-v-e06f39ec></i></div>',1)),s("div",kn,[z(Mt,null,{left:Te(()=>[s("div",xn,[s("span",_n,$(S(c)),1),s("span",In,$(S(m)),1),s("span",En,$(S(v)),1),s("span",$n,"RH:"+$(S(g)),1)])]),right:Te(()=>[s("div",Mn,[s("span",Cn,$(S(p)),1),s("span",Hn,$(S(n)),1)]),s("div",Pn,[s("button",{ref_key:"alarmBtnRef",ref:N,type:"button",class:A(["alarm-badge",{open:M.value}]),"aria-haspopup":"true","aria-expanded":M.value,onClick:j(D,["stop"])},[u[2]||(u[2]=s("span",{class:"dot red"},null,-1)),s("span",null,"告警 "+$(S(l).alarmCount),1)],10,Sn)]),s("button",{class:"tops-logout admin-entry",type:"button",onClick:L},"管理")]),_:1}),s("main",Rn,[z(I)])]),M.value?(w(),k("div",{key:0,class:"alarm-backdrop",onClick:u[0]||(u[0]=E=>M.value=!1)})):W("",!0),M.value?(w(),k("div",{key:1,class:"alarm-dropdown",role:"dialog","aria-label":"告警列表",style:ae(R.value),onClick:u[1]||(u[1]=j(()=>{},["stop"]))},[s("div",Ln,[u[3]||(u[3]=s("span",null,"当前告警",-1)),s("b",null,$(S(l).alarmCount),1)]),s("div",zn,[(w(!0),k(J,null,Q(P.value,(E,ee)=>(w(),k("div",{key:`${E.title}-${ee}`,class:A(["alarm-dd-item",E.level])},[z(q,{name:E.level==="red"?"alarm-warn":E.level==="amber"?"alarm-amber":"alarm-ok"},null,8,["name"]),s("div",Tn,[s("div",Nn,$(E.title),1),s("div",Dn,$(E.sub),1)]),s("div",On,$(E.state),1)],2))),128))])],4)):W("",!0)],4)}}}),Wn=de(Bn,[["__scopeId","data-v-e06f39ec"]]);export{Wn as default};
.screen-header-hy[data-v-35ef0672]{position:relative;width:100%;height:clamp(64px,7.8vh,84px);flex-shrink:0;pointer-events:auto}.banner[data-v-35ef0672]{display:block;width:100%;height:100%;object-fit:cover;object-position:center top}h1[data-v-35ef0672]{position:absolute;left:12%;right:12%;top:50%;transform:translateY(-55%);z-index:1;margin:0;height:auto;line-height:1.2;text-align:center;font-family:var(--title-font);font-size:clamp(16px,1.7vw,30px);font-weight:900;font-synthesis:none;letter-spacing:clamp(2px,.35vw,6px);color:#f4feff;font-style:italic;text-shadow:0 0 14px rgba(0,200,255,.45);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}h1.is-cjk[data-v-35ef0672]{font-style:normal;letter-spacing:.06em;font-weight:800}.slot-left[data-v-35ef0672],.slot-right[data-v-35ef0672]{position:absolute;top:0;bottom:0;z-index:2;display:flex;align-items:center;gap:clamp(6px,.8vw,12px);pointer-events:auto;max-width:min(36vw,420px)}.slot-left[data-v-35ef0672]{left:clamp(8px,1.2vw,24px)}.slot-right[data-v-35ef0672]{right:clamp(8px,1.2vw,24px);justify-content:flex-end}.lang-switch[data-v-88d8963f]{display:inline-flex;align-items:center;flex-shrink:0;height:28px;padding:2px;gap:2px;border-radius:3px;border:1px solid rgba(61,190,255,.45);background:#060c148c;pointer-events:auto}.lang-btn[data-v-88d8963f]{min-width:28px;height:22px;padding:0 6px;border:0;border-radius:2px;background:transparent;color:#cfe6ff;cursor:pointer;font-size:12px;font-weight:800;letter-spacing:.02em;line-height:1}.lang-btn[data-v-88d8963f]:hover{color:#fff;background:#3dbeff29}.lang-btn.active[data-v-88d8963f]{color:#041018;background:#3dbeff}.near-layer[data-v-63c7e0dc]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:340;pointer-events:none}.near-backdrop[data-v-63c7e0dc]{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:auto;background:transparent}.near-dialog[data-v-63c7e0dc]{position:absolute;pointer-events:auto;display:flex;flex-direction:column;overflow:hidden;border-radius:6px;border:1px solid rgba(0,247,255,.4);background:#071426;box-shadow:0 12px 36px #00000080,0 0 0 1px #00000059}.near-head[data-v-63c7e0dc]{flex:0 0 36px;height:36px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid rgba(0,247,255,.18);background:linear-gradient(180deg,#0c2a48fa,#06162afa);cursor:move;-webkit-user-select:none;user-select:none;touch-action:none}.near-head h3[data-v-63c7e0dc]{margin:0;min-width:0;flex:1;font-size:13px;font-weight:600;color:#e8fbff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none}.near-close[data-v-63c7e0dc]{flex:0 0 auto;width:28px;height:28px;border:none;border-radius:4px;background:transparent;color:#9ec8dc;font-size:18px;line-height:1;cursor:pointer}.near-close[data-v-63c7e0dc]:hover{color:#fff;background:#ffffff14}.near-body[data-v-63c7e0dc]{flex:1;min-height:0;background:#000}.near-body--values[data-v-63c7e0dc]{background:#071426;overflow:auto}.near-body--switch[data-v-63c7e0dc]{background:#071426;display:flex;align-items:center;justify-content:center}.near-switch[data-v-63c7e0dc]{width:100%;padding:12px 18px 16px;display:flex;flex-direction:column;align-items:center;gap:12px}.near-switch-status[data-v-63c7e0dc]{margin:0;font-size:13px;color:#8fb4c8}.near-switch-status b[data-v-63c7e0dc]{font-size:15px;font-weight:700;margin-left:4px}.near-switch-status b.on[data-v-63c7e0dc]{color:#4dffb5}.near-switch-status b.off[data-v-63c7e0dc]{color:#9ec8dc}.near-switch-actions[data-v-63c7e0dc]{display:flex;gap:16px}.sw-btn[data-v-63c7e0dc]{min-width:96px;height:40px;border-radius:4px;border:1px solid rgba(0,247,255,.35);background:#082440e6;color:#e8fbff;font-size:16px;font-weight:700;letter-spacing:.2em;cursor:pointer}.sw-btn.on[data-v-63c7e0dc]{border-color:#4dffb58c;color:#4dffb5}.sw-btn.off[data-v-63c7e0dc]{border-color:#9ec8dc73;color:#c5e4f4}.sw-btn[data-v-63c7e0dc]:hover:not(:disabled){background:#0064a066}.sw-btn[data-v-63c7e0dc]:disabled{opacity:.55;cursor:wait}.near-switch-err[data-v-63c7e0dc]{margin:0;font-size:12px;color:#ffb0b0;text-align:center}.near-values[data-v-63c7e0dc]{list-style:none;margin:0;padding:8px 14px 12px}.near-values li[data-v-63c7e0dc]{display:flex;align-items:baseline;justify-content:space-between;gap:16px;min-height:32px;border-bottom:1px solid rgba(0,247,255,.12);font-size:13px}.near-values li[data-v-63c7e0dc]:last-child{border-bottom:none}.near-values span[data-v-63c7e0dc]{color:#8fb4c8;flex:0 0 auto}.near-values b[data-v-63c7e0dc]{color:#e8fbff;font-weight:600;text-align:right;word-break:break-all}.near-video[data-v-63c7e0dc]{display:block;width:100%;height:100%;object-fit:cover;background:#000}.viewport[data-v-9d7e8d70]{flex:1;min-width:0;position:relative;overflow:hidden;border-radius:10px;border:1px solid rgba(62,200,255,.4);background:linear-gradient(180deg,#0a2148,#041022);box-shadow:inset 0 0 0 1px #ffffff0a,0 14px 34px #02081780}.viewport--fill[data-v-9d7e8d70]{width:100%;height:100%;border:none;border-radius:0;box-shadow:none;background:#000}.scene[data-v-9d7e8d70],.ue-frame[data-v-9d7e8d70]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;border:0;background:#000;transform:translateZ(0);contain:strict;content-visibility:auto}.vp-topbar[data-v-9d7e8d70],.vp-tip[data-v-9d7e8d70]{position:absolute;z-index:5;display:flex;align-items:center;gap:10px;padding:7px 12px;border-radius:7px;background:#081a3dd9;border:1px solid rgba(91,212,255,.42);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);pointer-events:none}.vp-topbar[data-v-9d7e8d70]{left:14px;top:14px}.vp-room-panel[data-v-9d7e8d70]{position:absolute;z-index:6;right:14px;top:14px;width:max-content;min-width:108px;max-width:148px;max-height:calc(100% - 72px);display:flex;flex-direction:column;border-radius:6px;background:#06122a8c;border:1px solid rgba(91,212,255,.28);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);overflow:hidden;pointer-events:auto}.vp-area-side[data-v-9d7e8d70]{position:absolute;z-index:8;right:calc(var(--screen-side-w, 24vw) + 16px);top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:6px;max-height:min(72vh,640px);overflow-y:auto;overflow-x:hidden;padding:4px;pointer-events:auto}.vp-area-side-item[data-v-9d7e8d70]{display:flex;align-items:center;gap:6px;min-width:108px;padding:8px 12px;border-radius:4px;border:1px solid rgba(91,212,255,.32);background:#081c3a9e;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);color:#ebf5fff2;cursor:pointer;font-size:12px;font-weight:600;white-space:nowrap}.vp-area-side-item[data-v-9d7e8d70] .room-ico{width:12px;height:12px;opacity:.9}.vp-area-side-item[data-v-9d7e8d70]:hover{border-color:#3ec8ff80;background:#1e5296b3}.vp-area-side-item.active[data-v-9d7e8d70]{border-color:#5bd4ffb3;background:#1a6fff8c;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-area-side-item.alarm .name[data-v-9d7e8d70]{color:#ffb0b0}.vp-mode-bar[data-v-9d7e8d70]{position:absolute;z-index:8;left:50%;bottom:clamp(12px,2vh,24px);transform:translate(-50%);display:flex;flex-direction:row;align-items:center;gap:4px;max-width:calc(100vw - 2 * var(--screen-side-w, clamp(280px, 24vw, 480px)) - 36px);overflow-x:auto;pointer-events:auto}.vp-mode-item[data-v-9d7e8d70]{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;min-width:0;padding:8px 12px;border-radius:4px;border:1px solid rgba(91,212,255,.32);background:#081c3ab8;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);color:#e6f0ffeb;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}.vp-mode-item[data-v-9d7e8d70] .room-ico{width:12px;height:12px;opacity:.9}.vp-mode-item[data-v-9d7e8d70]:hover{border-color:#5bd4ff80;background:#1e5296b3}.vp-mode-item.active[data-v-9d7e8d70]{border-color:#5bd4ffb3;background:#1a6fff8c;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-mode-item.alarm[data-v-9d7e8d70]{color:#ffb0b0}.vp-room-head[data-v-9d7e8d70]{display:flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;border-bottom:1px solid rgba(62,200,255,.12);flex-shrink:0}.vp-room-head[data-v-9d7e8d70] .pin{width:12px;height:12px;opacity:.85}.vp-room-head>div[data-v-9d7e8d70]{text-align:center}.vp-room-label[data-v-9d7e8d70]{font-size:11px;font-weight:600;color:#ffffffeb}.vp-room-sub[data-v-9d7e8d70]{display:block;margin-top:2px;font-size:9px;color:#b9d6f0b8}.vp-room-list[data-v-9d7e8d70]{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding:4px;display:flex;flex-direction:column;gap:2px}.vp-room-panel--fill .vp-room-list[data-v-9d7e8d70]{flex:0 0 auto;flex-direction:row;align-items:center;justify-content:center;overflow-x:auto;overflow-y:hidden;gap:8px;padding:0}.vp-room-item[data-v-9d7e8d70]{display:flex;align-items:center;justify-content:center;gap:5px;width:100%;border:1px solid rgba(62,200,255,.18);background:#163a6e73;border-radius:4px;padding:4px 6px;cursor:pointer;color:#ebf5fff2;transition:.15s}.vp-room-panel--fill .vp-room-item[data-v-9d7e8d70]{width:auto;flex:0 0 auto;min-width:88px;padding:8px 12px;background:#081c3a8c;border:1px solid rgba(91,212,255,.32);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.vp-room-item[data-v-9d7e8d70] .room-ico{width:12px;height:12px;flex:0 0 auto;opacity:.9}.vp-room-item[data-v-9d7e8d70]:hover{border-color:#3ec8ff6b;background:#1e52969e;color:#fff}.vp-room-item.active[data-v-9d7e8d70]{border-color:#5bd4ffa6;background:#1a6fff8c;color:#fff;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-room-item.alarm .name[data-v-9d7e8d70]{color:#ffb0b0}.vp-room-item .name[data-v-9d7e8d70]{font-size:11px;display:block;white-space:nowrap;line-height:1.25;text-align:center}.vp-room-panel--fill .vp-room-item .name[data-v-9d7e8d70]{font-size:12px;font-weight:600}.vp-tip[data-v-9d7e8d70]{right:14px;bottom:16px;font-size:11px;color:#b9d6f0}.vp-tip[data-v-9d7e8d70] .hand{width:14px;height:14px}.vp-tip b[data-v-9d7e8d70]{color:var(--cyan-lt);font-weight:600}.area[data-v-9d7e8d70]{font-size:12px;color:#fff}.sep[data-v-9d7e8d70]{width:1px;height:14px;background:#3ec8ff59}.view[data-v-9d7e8d70]{font-size:11px;color:var(--cyan-lt)}.mk[data-v-9d7e8d70]{position:absolute;z-index:5;display:flex;align-items:center;gap:6px;padding:5px 9px;border-radius:6px;background:#052433e0;border:1px solid rgba(47,214,161,.6);font-size:11px;color:#b9f5de;white-space:nowrap;cursor:pointer}.mk.err[data-v-9d7e8d70]{background:#3d0d14e6;border-color:#ff5252a6;color:#ffc9c9}.vp-corners[data-v-9d7e8d70]{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:4}.vp-corners i[data-v-9d7e8d70]{position:absolute;width:16px;height:16px;border:2px solid rgba(91,212,255,.7)}.vp-corners i[data-v-9d7e8d70]:nth-child(1){left:10px;top:10px;border-right:none;border-bottom:none}.vp-corners i[data-v-9d7e8d70]:nth-child(2){right:10px;top:10px;border-left:none;border-bottom:none}.vp-corners i[data-v-9d7e8d70]:nth-child(3){left:10px;bottom:10px;border-right:none;border-top:none}.vp-corners i[data-v-9d7e8d70]:nth-child(4){right:10px;bottom:10px;border-left:none;border-top:none}.stage--immersive[data-v-59a30f96]{background:#00060f;width:100%;height:100%}.stage--immersive[data-v-59a30f96]:before{display:none}.scene-layer[data-v-59a30f96]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.edge-mask[data-v-59a30f96]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:none}.edge[data-v-59a30f96]{position:absolute;display:block;pointer-events:none}.edge-t[data-v-59a30f96]{left:0;right:0;top:0;height:220px;background:linear-gradient(180deg,#000612eb,#000a1c8c 42%,#000a1c00)}.edge-b[data-v-59a30f96]{left:0;right:0;bottom:0;height:140px;background:linear-gradient(0deg,#000612d1,#000a1c66 48%,#000a1c00)}.edge-l[data-v-59a30f96]{left:0;top:0;bottom:0;width:calc(var(--screen-side-w, 24vw) + 40px);background:linear-gradient(90deg,#000816d1,#000c2073 38%,#000c2000)}.edge-r[data-v-59a30f96]{right:0;top:0;bottom:0;width:calc(var(--screen-side-w, 24vw) + 40px);background:linear-gradient(270deg,#000816d1,#000c2073 38%,#000c2000)}.ui-layer[data-v-59a30f96]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;display:flex;flex-direction:column;pointer-events:none}.screen-main--float[data-v-59a30f96]{flex:1;min-height:0;padding:8px 16px 14px;pointer-events:none}.screen-float-overlays[data-v-59a30f96]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:5;pointer-events:none}.screen-float-overlays[data-v-59a30f96]>*{pointer-events:auto}.screen-nav--side[data-v-59a30f96]{position:absolute;z-index:6;top:clamp(200px,26vh,280px);bottom:clamp(56px,8vh,88px);right:calc(var(--screen-side-w, 24vw) + 28px);width:clamp(88px,6vw,108px);height:auto!important;flex:none!important;display:flex;flex-direction:column;align-items:stretch;gap:6px;padding:0;border:none;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;pointer-events:auto;overflow-x:hidden;overflow-y:auto}.screen-nav--side[data-v-59a30f96] .nav-chip,.screen-nav--side .nav-chip[data-v-59a30f96]{display:flex;align-items:center;justify-content:center;flex:0 0 auto;width:100%;min-height:34px;padding:7px 6px;text-align:center;font-size:11px;line-height:1.25;white-space:normal;border-radius:4px;background:#081c3a8c;border:1px solid rgba(91,212,255,.32);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.weather-wrap[data-v-59a30f96],.clock-wrap[data-v-59a30f96]{position:static;transform:none;display:flex;align-items:baseline;gap:clamp(4px,.6vw,10px);white-space:nowrap;max-width:100%;overflow:hidden}@media(max-width:1280px){.weather-wrap .w-text[data-v-59a30f96],.weather-wrap .humid[data-v-59a30f96]{display:none}}@media(max-width:960px){.weather-wrap[data-v-59a30f96]{display:none}}.weather-wrap .place[data-v-59a30f96],.weather-wrap .temp[data-v-59a30f96]{font-size:16px;font-weight:600;font-family:var(--digital-font);color:#7cf0c4;line-height:1}.weather-wrap .w-text[data-v-59a30f96],.weather-wrap .humid[data-v-59a30f96]{font-size:12px;color:#7cf0c4}.clock-wrap .time[data-v-59a30f96]{font-size:16px;font-weight:600;font-family:var(--digital-font);color:var(--accent);text-shadow:0 0 .55em rgba(0,247,255,.45)}.clock-wrap .date[data-v-59a30f96]{font-size:12px;color:var(--panel-muted)}.admin-entry[data-v-59a30f96]{font-size:12px!important;letter-spacing:.12em!important;color:var(--accent)!important}.alarm-wrap[data-v-59a30f96]{position:relative;pointer-events:auto}.alarm-badge[data-v-59a30f96]{display:inline-flex;align-items:center;gap:6px;font:inherit;cursor:pointer}.alarm-badge.open[data-v-59a30f96]{border-color:#ff7878bf;background:#5010188c}.alarm-backdrop[data-v-59a30f96]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:200;background:transparent;pointer-events:auto}.alarm-dropdown[data-v-59a30f96]{position:absolute;z-index:201;width:min(360px,72vw);max-height:min(420px,60vh);display:flex;flex-direction:column;border-radius:6px;border:1px solid rgba(255,120,120,.35);background:linear-gradient(180deg,#1c0a10f5,#080e1cf5);box-shadow:0 12px 32px #00000073;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);overflow:hidden;pointer-events:auto}.alarm-dd-head[data-v-59a30f96]{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;font-size:12px;color:#ffc9c9;border-bottom:1px solid rgba(255,120,120,.22)}.alarm-dd-head b[data-v-59a30f96]{font-family:var(--digital-font);color:#ff8f8f}.alarm-dd-list[data-v-59a30f96]{flex:1;min-height:0;overflow:auto;padding:6px;display:flex;flex-direction:column;gap:4px}.alarm-dd-item[data-v-59a30f96]{display:flex;align-items:center;gap:8px;min-height:40px;padding:6px 8px;border-radius:5px;font-size:12px}.alarm-dd-item.red[data-v-59a30f96]{background:#ff52521f;border:1px solid rgba(255,82,82,.35)}.alarm-dd-item.amber[data-v-59a30f96]{background:#ffb4001a;border:1px solid rgba(255,180,0,.3)}.alarm-dd-item.calm[data-v-59a30f96]{background:#1a4d9938;border:1px solid transparent}.alarm-dd-item .a-txt[data-v-59a30f96]{flex:1;min-width:0}.alarm-dd-item .a-title[data-v-59a30f96]{color:#f2f7ff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.alarm-dd-item .a-sub[data-v-59a30f96]{margin-top:2px;font-size:10px;color:#b9d6f0b8}.alarm-dd-item .a-state[data-v-59a30f96]{flex-shrink:0;font-size:10px;padding:2px 6px;border-radius:3px;background:#00000047;color:#ffd0d0;white-space:nowrap}
.screen-header-hy[data-v-83363d93]{position:relative;width:100%;height:clamp(64px,7.8vh,84px);flex-shrink:0;pointer-events:auto}.banner[data-v-83363d93]{display:block;width:100%;height:100%;object-fit:cover;object-position:center top}h1[data-v-83363d93]{position:absolute;left:12%;right:12%;top:50%;transform:translateY(-55%);z-index:1;margin:0;height:auto;line-height:1.2;text-align:center;font-family:var(--title-font);font-size:clamp(16px,1.7vw,30px);font-weight:900;font-synthesis:style;letter-spacing:clamp(2px,.35vw,6px);color:#f4feff;font-style:italic;text-shadow:0 0 14px rgba(0,200,255,.45);pointer-events:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.slot-left[data-v-83363d93],.slot-right[data-v-83363d93]{position:absolute;top:0;bottom:0;z-index:2;display:flex;align-items:center;gap:clamp(6px,.8vw,12px);pointer-events:auto;max-width:min(36vw,420px)}.slot-left[data-v-83363d93]{left:clamp(8px,1.2vw,24px)}.slot-right[data-v-83363d93]{right:clamp(8px,1.2vw,24px);justify-content:flex-end}.near-layer[data-v-369dcccd]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:340;pointer-events:none}.near-backdrop[data-v-369dcccd]{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:auto;background:transparent}.near-dialog[data-v-369dcccd]{position:absolute;pointer-events:auto;display:flex;flex-direction:column;overflow:hidden;border-radius:6px;border:1px solid rgba(0,247,255,.4);background:#071426;box-shadow:0 12px 36px #00000080,0 0 0 1px #00000059}.near-head[data-v-369dcccd]{flex:0 0 36px;height:36px;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:0 8px 0 12px;border-bottom:1px solid rgba(0,247,255,.18);background:linear-gradient(180deg,#0c2a48fa,#06162afa);cursor:move;-webkit-user-select:none;user-select:none;touch-action:none}.near-head h3[data-v-369dcccd]{margin:0;min-width:0;flex:1;font-size:13px;font-weight:600;color:#e8fbff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none}.near-close[data-v-369dcccd]{flex:0 0 auto;width:28px;height:28px;border:none;border-radius:4px;background:transparent;color:#9ec8dc;font-size:18px;line-height:1;cursor:pointer}.near-close[data-v-369dcccd]:hover{color:#fff;background:#ffffff14}.near-body[data-v-369dcccd]{flex:1;min-height:0;background:#000}.near-body--values[data-v-369dcccd]{background:#071426;overflow:auto}.near-values[data-v-369dcccd]{list-style:none;margin:0;padding:8px 14px 12px}.near-values li[data-v-369dcccd]{display:flex;align-items:baseline;justify-content:space-between;gap:16px;min-height:32px;border-bottom:1px solid rgba(0,247,255,.12);font-size:13px}.near-values li[data-v-369dcccd]:last-child{border-bottom:none}.near-values span[data-v-369dcccd]{color:#8fb4c8;flex:0 0 auto}.near-values b[data-v-369dcccd]{color:#e8fbff;font-weight:600;text-align:right;word-break:break-all}.near-video[data-v-369dcccd]{display:block;width:100%;height:100%;object-fit:cover;background:#000}.viewport[data-v-e3a57494]{flex:1;min-width:0;position:relative;overflow:hidden;border-radius:10px;border:1px solid rgba(62,200,255,.4);background:linear-gradient(180deg,#0a2148,#041022);box-shadow:inset 0 0 0 1px #ffffff0a,0 14px 34px #02081780}.viewport--fill[data-v-e3a57494]{width:100%;height:100%;border:none;border-radius:0;box-shadow:none;background:#000}.scene[data-v-e3a57494],.ue-frame[data-v-e3a57494]{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;border:0;background:#000;transform:translateZ(0);contain:strict;content-visibility:auto}.vp-topbar[data-v-e3a57494],.vp-tip[data-v-e3a57494]{position:absolute;z-index:5;display:flex;align-items:center;gap:10px;padding:7px 12px;border-radius:7px;background:#081a3dd9;border:1px solid rgba(91,212,255,.42);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);pointer-events:none}.vp-topbar[data-v-e3a57494]{left:14px;top:14px}.vp-room-panel[data-v-e3a57494]{position:absolute;z-index:6;right:14px;top:14px;width:max-content;min-width:108px;max-width:148px;max-height:calc(100% - 72px);display:flex;flex-direction:column;border-radius:6px;background:#06122a8c;border:1px solid rgba(91,212,255,.28);-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);overflow:hidden;pointer-events:auto}.vp-area-side[data-v-e3a57494]{position:absolute;z-index:8;right:calc(var(--screen-side-w, 24vw) + 16px);top:50%;transform:translateY(-50%);display:flex;flex-direction:column;gap:6px;max-height:min(72vh,640px);overflow-y:auto;overflow-x:hidden;padding:4px;pointer-events:auto}.vp-area-side-item[data-v-e3a57494]{display:flex;align-items:center;gap:6px;min-width:108px;padding:8px 12px;border-radius:4px;border:1px solid rgba(91,212,255,.32);background:#081c3a9e;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);color:#ebf5fff2;cursor:pointer;font-size:12px;font-weight:600;white-space:nowrap}.vp-area-side-item[data-v-e3a57494] .room-ico{width:12px;height:12px;opacity:.9}.vp-area-side-item[data-v-e3a57494]:hover{border-color:#3ec8ff80;background:#1e5296b3}.vp-area-side-item.active[data-v-e3a57494]{border-color:#5bd4ffb3;background:#1a6fff8c;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-area-side-item.alarm .name[data-v-e3a57494]{color:#ffb0b0}.vp-mode-bar[data-v-e3a57494]{position:absolute;z-index:8;left:50%;bottom:clamp(12px,2vh,24px);transform:translate(-50%);display:flex;flex-direction:row;align-items:center;gap:4px;max-width:calc(100vw - 2 * var(--screen-side-w, clamp(280px, 24vw, 480px)) - 36px);overflow-x:auto;pointer-events:auto}.vp-mode-item[data-v-e3a57494]{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;min-width:0;padding:8px 12px;border-radius:4px;border:1px solid rgba(91,212,255,.32);background:#081c3ab8;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);color:#e6f0ffeb;font-size:12px;font-weight:600;cursor:pointer;white-space:nowrap}.vp-mode-item[data-v-e3a57494] .room-ico{width:12px;height:12px;opacity:.9}.vp-mode-item[data-v-e3a57494]:hover{border-color:#5bd4ff80;background:#1e5296b3}.vp-mode-item.active[data-v-e3a57494]{border-color:#5bd4ffb3;background:#1a6fff8c;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-mode-item.alarm[data-v-e3a57494]{color:#ffb0b0}.vp-room-head[data-v-e3a57494]{display:flex;align-items:center;justify-content:center;gap:6px;padding:7px 8px;border-bottom:1px solid rgba(62,200,255,.12);flex-shrink:0}.vp-room-head[data-v-e3a57494] .pin{width:12px;height:12px;opacity:.85}.vp-room-head>div[data-v-e3a57494]{text-align:center}.vp-room-label[data-v-e3a57494]{font-size:11px;font-weight:600;color:#ffffffeb}.vp-room-sub[data-v-e3a57494]{display:block;margin-top:2px;font-size:9px;color:#b9d6f0b8}.vp-room-list[data-v-e3a57494]{flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding:4px;display:flex;flex-direction:column;gap:2px}.vp-room-panel--fill .vp-room-list[data-v-e3a57494]{flex:0 0 auto;flex-direction:row;align-items:center;justify-content:center;overflow-x:auto;overflow-y:hidden;gap:8px;padding:0}.vp-room-item[data-v-e3a57494]{display:flex;align-items:center;justify-content:center;gap:5px;width:100%;border:1px solid rgba(62,200,255,.18);background:#163a6e73;border-radius:4px;padding:4px 6px;cursor:pointer;color:#ebf5fff2;transition:.15s}.vp-room-panel--fill .vp-room-item[data-v-e3a57494]{width:auto;flex:0 0 auto;min-width:88px;padding:8px 12px;background:#081c3a8c;border:1px solid rgba(91,212,255,.32);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.vp-room-item[data-v-e3a57494] .room-ico{width:12px;height:12px;flex:0 0 auto;opacity:.9}.vp-room-item[data-v-e3a57494]:hover{border-color:#3ec8ff6b;background:#1e52969e;color:#fff}.vp-room-item.active[data-v-e3a57494]{border-color:#5bd4ffa6;background:#1a6fff8c;color:#fff;box-shadow:inset 0 0 0 1px #5bd4ff26}.vp-room-item.alarm .name[data-v-e3a57494]{color:#ffb0b0}.vp-room-item .name[data-v-e3a57494]{font-size:11px;display:block;white-space:nowrap;line-height:1.25;text-align:center}.vp-room-panel--fill .vp-room-item .name[data-v-e3a57494]{font-size:12px;font-weight:600}.vp-tip[data-v-e3a57494]{right:14px;bottom:16px;font-size:11px;color:#b9d6f0}.vp-tip[data-v-e3a57494] .hand{width:14px;height:14px}.vp-tip b[data-v-e3a57494]{color:var(--cyan-lt);font-weight:600}.area[data-v-e3a57494]{font-size:12px;color:#fff}.sep[data-v-e3a57494]{width:1px;height:14px;background:#3ec8ff59}.view[data-v-e3a57494]{font-size:11px;color:var(--cyan-lt)}.mk[data-v-e3a57494]{position:absolute;z-index:5;display:flex;align-items:center;gap:6px;padding:5px 9px;border-radius:6px;background:#052433e0;border:1px solid rgba(47,214,161,.6);font-size:11px;color:#b9f5de;white-space:nowrap;cursor:pointer}.mk.err[data-v-e3a57494]{background:#3d0d14e6;border-color:#ff5252a6;color:#ffc9c9}.vp-corners[data-v-e3a57494]{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:4}.vp-corners i[data-v-e3a57494]{position:absolute;width:16px;height:16px;border:2px solid rgba(91,212,255,.7)}.vp-corners i[data-v-e3a57494]:nth-child(1){left:10px;top:10px;border-right:none;border-bottom:none}.vp-corners i[data-v-e3a57494]:nth-child(2){right:10px;top:10px;border-left:none;border-bottom:none}.vp-corners i[data-v-e3a57494]:nth-child(3){left:10px;bottom:10px;border-right:none;border-top:none}.vp-corners i[data-v-e3a57494]:nth-child(4){right:10px;bottom:10px;border-left:none;border-top:none}.stage--immersive[data-v-e06f39ec]{background:#00060f;width:100%;height:100%}.stage--immersive[data-v-e06f39ec]:before{display:none}.scene-layer[data-v-e06f39ec]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0}.edge-mask[data-v-e06f39ec]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;pointer-events:none}.edge[data-v-e06f39ec]{position:absolute;display:block;pointer-events:none}.edge-t[data-v-e06f39ec]{left:0;right:0;top:0;height:220px;background:linear-gradient(180deg,#000612eb,#000a1c8c 42%,#000a1c00)}.edge-b[data-v-e06f39ec]{left:0;right:0;bottom:0;height:140px;background:linear-gradient(0deg,#000612d1,#000a1c66 48%,#000a1c00)}.edge-l[data-v-e06f39ec]{left:0;top:0;bottom:0;width:calc(var(--screen-side-w, 24vw) + 40px);background:linear-gradient(90deg,#000816d1,#000c2073 38%,#000c2000)}.edge-r[data-v-e06f39ec]{right:0;top:0;bottom:0;width:calc(var(--screen-side-w, 24vw) + 40px);background:linear-gradient(270deg,#000816d1,#000c2073 38%,#000c2000)}.ui-layer[data-v-e06f39ec]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:2;display:flex;flex-direction:column;pointer-events:none}.screen-main--float[data-v-e06f39ec]{flex:1;min-height:0;padding:8px 16px 14px;pointer-events:none}.screen-float-overlays[data-v-e06f39ec]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:5;pointer-events:none}.screen-float-overlays[data-v-e06f39ec]>*{pointer-events:auto}.screen-nav--side[data-v-e06f39ec]{position:absolute;z-index:6;top:clamp(200px,26vh,280px);bottom:clamp(56px,8vh,88px);right:calc(var(--screen-side-w, 24vw) + 28px);width:clamp(88px,6vw,108px);height:auto!important;flex:none!important;display:flex;flex-direction:column;align-items:stretch;gap:6px;padding:0;border:none;border-radius:0;background:transparent;-webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:none;pointer-events:auto;overflow-x:hidden;overflow-y:auto}.screen-nav--side[data-v-e06f39ec] .nav-chip,.screen-nav--side .nav-chip[data-v-e06f39ec]{display:flex;align-items:center;justify-content:center;flex:0 0 auto;width:100%;min-height:34px;padding:7px 6px;text-align:center;font-size:11px;line-height:1.25;white-space:normal;border-radius:4px;background:#081c3a8c;border:1px solid rgba(91,212,255,.32);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}.weather-wrap[data-v-e06f39ec],.clock-wrap[data-v-e06f39ec]{position:static;transform:none;display:flex;align-items:baseline;gap:clamp(4px,.6vw,10px);white-space:nowrap;max-width:100%;overflow:hidden}@media(max-width:1280px){.weather-wrap .w-text[data-v-e06f39ec],.weather-wrap .humid[data-v-e06f39ec]{display:none}}@media(max-width:960px){.weather-wrap[data-v-e06f39ec]{display:none}}.weather-wrap .place[data-v-e06f39ec],.weather-wrap .temp[data-v-e06f39ec]{font-size:16px;font-weight:600;font-family:var(--digital-font);color:#7cf0c4;line-height:1}.weather-wrap .w-text[data-v-e06f39ec],.weather-wrap .humid[data-v-e06f39ec]{font-size:12px;color:#7cf0c4}.clock-wrap .time[data-v-e06f39ec]{font-size:16px;font-weight:600;font-family:var(--digital-font);color:var(--accent);text-shadow:0 0 .55em rgba(0,247,255,.45)}.clock-wrap .date[data-v-e06f39ec]{font-size:12px;color:var(--panel-muted)}.admin-entry[data-v-e06f39ec]{font-size:12px!important;letter-spacing:.12em!important;color:var(--accent)!important}.alarm-wrap[data-v-e06f39ec]{position:relative;pointer-events:auto}.alarm-badge[data-v-e06f39ec]{display:inline-flex;align-items:center;gap:6px;font:inherit;cursor:pointer}.alarm-badge.open[data-v-e06f39ec]{border-color:#ff7878bf;background:#5010188c}.alarm-backdrop[data-v-e06f39ec]{position:absolute;top:0;right:0;bottom:0;left:0;z-index:200;background:transparent;pointer-events:auto}.alarm-dropdown[data-v-e06f39ec]{position:absolute;z-index:201;width:min(360px,72vw);max-height:min(420px,60vh);display:flex;flex-direction:column;border-radius:6px;border:1px solid rgba(255,120,120,.35);background:linear-gradient(180deg,#1c0a10f5,#080e1cf5);box-shadow:0 12px 32px #00000073;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);overflow:hidden;pointer-events:auto}.alarm-dd-head[data-v-e06f39ec]{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;font-size:12px;color:#ffc9c9;border-bottom:1px solid rgba(255,120,120,.22)}.alarm-dd-head b[data-v-e06f39ec]{font-family:var(--digital-font);color:#ff8f8f}.alarm-dd-list[data-v-e06f39ec]{flex:1;min-height:0;overflow:auto;padding:6px;display:flex;flex-direction:column;gap:4px}.alarm-dd-item[data-v-e06f39ec]{display:flex;align-items:center;gap:8px;min-height:40px;padding:6px 8px;border-radius:5px;font-size:12px}.alarm-dd-item.red[data-v-e06f39ec]{background:#ff52521f;border:1px solid rgba(255,82,82,.35)}.alarm-dd-item.amber[data-v-e06f39ec]{background:#ffb4001a;border:1px solid rgba(255,180,0,.3)}.alarm-dd-item.calm[data-v-e06f39ec]{background:#1a4d9938;border:1px solid transparent}.alarm-dd-item .a-txt[data-v-e06f39ec]{flex:1;min-width:0}.alarm-dd-item .a-title[data-v-e06f39ec]{color:#f2f7ff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.alarm-dd-item .a-sub[data-v-e06f39ec]{margin-top:2px;font-size:10px;color:#b9d6f0b8}.alarm-dd-item .a-state[data-v-e06f39ec]{flex-shrink:0;font-size:10px;padding:2px 6px;border-radius:3px;background:#00000047;color:#ffd0d0;white-space:nowrap}
import{j as de,r as E,k as Z,l as Se,m as Fe,p as Ve,d as we,c as M,b as l,h as v,n as G,t as w,q as tt,s as Q,o as b,_ as _e,F as me,x as ve,L as Et,y as Tt,z as It,B as Ot,C as at,D as it,w as ae,E as $e,g as Lt,f as ie,T as rt,G as He,u as lt,H as q,a as Rt,I as nt,J as Pt,K as Nt,i as At}from"./index-BssDqbym.js";import{u as Me}from"./realtime-lmP-Cubp.js";import{u as Dt}from"./useClock-BjFim-x6.js";import{M as Vt,p as Bt,D as pe,c as ct,a as Ft,b as ut,d as We,f as X,u as Ht,e as Wt,g as jt,m as ot}from"./useRtengineBridge-DNIfWox5.js";import{A as se}from"./AppIcon-C7TEwW-P.js";import{t as z}from"./t-ChxyHC3f.js";import{u as zt}from"./useScreenTitle-DLVybyzQ.js";const Kt=900*1e3;function Xt(){const{t:e,locale:r}=de(),s=E(e("weather.place")),a=E("--"),u=E(e("weather.loading")),m=E("--");let T,y=!1;async function I(){try{const R=await Ve("/api/weather/macau");s.value=R.place||e("weather.place"),a.value=R.temp||"--",u.value=R.text||"—",m.value=R.humidity||"--",y=!0}catch{u.value=e("weather.empty"),y||(s.value=e("weather.place"))}}return Z(r,()=>{y?s.value||(s.value=e("weather.place")):(s.value=e("weather.place"),u.value=u.value==="—"?e("weather.empty"):e("weather.loading"))}),Se(()=>{I(),T=window.setInterval(()=>void I(),Kt)}),Fe(()=>{T&&window.clearInterval(T)}),{place:s,temp:a,text:u,humidity:m}}function Yt(){const e=E({position:"fixed",inset:"0",width:"100%",height:"100%",transform:"none",left:"0",top:"0"});function r(){const s=window.innerWidth,a=Math.round(Math.min(480,Math.max(280,s*.24)));document.documentElement.style.setProperty("--screen-side-w",`${a}px`),document.documentElement.style.setProperty("--screen-vw",`${s}px`),document.documentElement.style.setProperty("--screen-vh",`${window.innerHeight}px`)}return Se(()=>{r(),window.addEventListener("resize",r)}),Fe(()=>window.removeEventListener("resize",r)),{style:e}}const qt="/assets/header-bar-CT0XVael.png",Ut={class:"screen-header-hy"},Gt=["src"],Jt={class:"slot-left"},Qt={class:"slot-right"},Zt=we({__name:"ScreenHeader",props:{title:{}},setup(e){const{t:r,locale:s}=de(),a=Q(()=>String(s.value).startsWith("zh"));return(u,m)=>(b(),M("header",Ut,[l("img",{class:"banner",src:v(qt),alt:""},null,8,Gt),l("h1",{class:G({"is-cjk":a.value})},w(e.title||v(r)("screen.defaultTitle")),3),l("div",Jt,[tt(u.$slots,"left",{},void 0)]),l("div",Qt,[tt(u.$slots,"right",{},void 0)])]))}}),en=_e(Zt,[["__scopeId","data-v-35ef0672"]]),tn=["aria-label"],nn=["onClick"],on=we({__name:"LanguageSwitch",setup(e){const{t:r,locale:s}=de({useScope:"global"});function a(u){s.value=u,Tt.global.locale.value=u,It(u)}return(u,m)=>(b(),M("div",{class:"lang-switch",role:"group","aria-label":v(r)("screen.language")},[(b(!0),M(me,null,ve(v(Et),T=>(b(),M("button",{key:T.id,type:"button",class:G(["lang-btn",{active:v(s)===T.id}]),onClick:y=>a(T.id)},w(T.short),11,nn))),128))],8,tn))}}),sn=_e(on,[["__scopeId","data-v-88d8963f"]]),je=Ot("screenMode",()=>{const e=E("pressure");function r(s){e.value=s}return{mode:e,setMode:r}}),an=[{id:"seq",name:"测序区",viewpoint:"测序区",roomId:"seq"},{id:"lib-2",name:"文库制备区2",viewpoint:"文库制备区2",roomId:"lib-2"},{id:"lib-1",name:"文库制备区1",viewpoint:"文库制备区1",roomId:"lib-1"},{id:"sample-2",name:"样本制备区2",viewpoint:"样本制备区2",roomId:"sample-2"},{id:"sample-1",name:"样本制备区1",viewpoint:"样本制备区1",roomId:"sample-1"},{id:"consult",name:"咨询室",viewpoint:"咨询室",roomId:"recv"},{id:"prep",name:"准备区",viewpoint:"准备区",roomId:"reagent"},{id:"report",name:"报告室",viewpoint:"报告室",roomId:"report"}],rn={key:0,class:"near-layer"},ln=["aria-label"],cn=["title"],un=["aria-label"],dn=["src"],fn={key:1,class:"near-values"},mn={key:2,class:"near-switch"},vn={class:"near-switch-status"},pn={class:"near-switch-actions"},hn=["disabled"],yn=["disabled"],gn={key:0,class:"near-switch-err"},st=400,Ne=36,wn=we({__name:"MarkerNearDialog",props:{open:{type:Boolean},title:{},left:{},top:{},src:{default:"/cams/lab-seq.mp4"},kind:{default:"video"},lines:{default:()=>[]},switchOn:{type:[Boolean,null],default:null},switching:{type:Boolean,default:!1},switchError:{default:""}},emits:["close","control"],setup(e,{emit:r}){const{t:s}=de(),a=e,u=r,m=Q(()=>{if(a.kind==="switch")return Ne+120;if(a.kind==="values"){const f=Math.max(a.lines.length,1);return Math.min(420,Ne+f*36+16)}return 240}),T=E(0),y=E(0),I=E(!1);let R=0,N=0;function D(f,d){const p=window.innerWidth,H=window.innerHeight;return{left:Math.max(0,Math.min(Math.round(f),Math.max(0,p-st))),top:Math.max(0,Math.min(Math.round(d),Math.max(0,H-m.value)))}}function V(){const f=D(a.left,a.top);T.value=f.left,y.value=f.top}Z(()=>[a.open,a.left,a.top],([f])=>{f&&V()},{immediate:!0});const L=Q(()=>({left:`${T.value}px`,top:`${y.value}px`,width:`${st}px`,height:`${m.value}px`})),j=Q(()=>m.value-Ne);function _(f){f.key==="Escape"&&x()}function $(f){var p,H;if(f.button!==0||(H=(p=f.target)==null?void 0:p.closest)!=null&&H.call(p,".near-close"))return;f.currentTarget.setPointerCapture(f.pointerId),I.value=!0,R=f.clientX-T.value,N=f.clientY-y.value}function K(f){if(!I.value)return;const d=D(f.clientX-R,f.clientY-N);T.value=d.left,y.value=d.top}function O(f){if(I.value){I.value=!1;try{f.currentTarget.releasePointerCapture(f.pointerId)}catch{}}}function x(f){f==null||f.preventDefault(),f==null||f.stopPropagation(),I.value&&(I.value=!1),u("close")}return Z(()=>a.open,f=>{f?window.addEventListener("keydown",_):window.removeEventListener("keydown",_)}),at(()=>window.removeEventListener("keydown",_)),(f,d)=>(b(),it(rt,{to:"body"},[e.open?(b(),M("div",rn,[l("div",{class:"near-backdrop",onPointerdown:x,onClick:d[0]||(d[0]=ae(()=>{},["prevent","stop"]))},null,32),l("div",{class:"near-dialog",style:$e(L.value),role:"dialog","aria-label":e.title,onPointerdown:d[3]||(d[3]=ae(()=>{},["stop"])),onClick:d[4]||(d[4]=ae(()=>{},["stop"]))},[l("header",{class:"near-head",onPointerdown:$,onPointermove:K,onPointerup:O,onPointercancel:O},[l("h3",{title:e.title},w(e.title),9,cn),l("button",{class:"near-close",type:"button","aria-label":v(s)("screen.close"),onPointerdown:ae(x,["stop"]),onClick:ae(x,["stop","prevent"])}," × ",40,un)],32),l("div",{class:G(["near-body",{"near-body--values":e.kind==="values","near-body--switch":e.kind==="switch"}]),style:$e({height:`${j.value}px`})},[e.kind==="video"?(b(),M("video",{key:0,class:"near-video",src:e.src,autoplay:"",muted:"",loop:"",playsinline:"",controls:""},null,8,dn)):e.kind==="values"?(b(),M("ul",fn,[(b(!0),M(me,null,ve(e.lines,p=>(b(),M("li",{key:p.label},[l("span",null,w(p.label),1),l("b",null,w(p.value),1)]))),128))])):(b(),M("div",mn,[l("p",vn,[Lt(w(v(s)("screen.current"))+": ",1),l("b",{class:G({on:e.switchOn===!0,off:e.switchOn===!1})},w(e.switchOn==null?v(s)("screen.unknown"):e.switchOn?v(s)("screen.switchOn"):v(s)("screen.switchOff")),3)]),l("div",pn,[l("button",{type:"button",class:"sw-btn on",disabled:e.switching,onClick:d[1]||(d[1]=p=>u("control",!0))},w(v(s)("screen.switchOn")),9,hn),l("button",{type:"button",class:"sw-btn off",disabled:e.switching,onClick:d[2]||(d[2]=p=>u("control",!1))},w(v(s)("screen.switchOff")),9,yn)]),e.switchError?(b(),M("p",gn,w(e.switchError),1)):ie("",!0)]))],6)],44,ln)])):ie("",!0)]))}}),_n=_e(wn,[["__scopeId","data-v-63c7e0dc"]]),dt={leader:!0,leaderHeight:Ft,leaderThickness:2,leaderColor:"#00f7ff"},Ae=[...new Set(Object.values(pe))],ft="sm:",mt="sm:sensor:";function vt(e){return`${ft}${e.id}`}function kn(e){return`${mt}${e.id}`}function bn(e,r){const s=e.bind;if(s.kind==="room"){const a=r.rooms.find(u=>u.id===s.roomId);return`${X(a==null?void 0:a.temp)}℃
${X(a==null?void 0:a.humidity,0)}%
${X(a==null?void 0:a.pressure)}Pa`}if(s.kind==="fridge"){const a=r.fridges.find(u=>u.id===s.deviceId);return`${X(a==null?void 0:a.temp)}℃
${X(a==null?void 0:a.humidity,0)}%`}if(s.kind==="vav"){const a=r.vav.find(m=>m.id===s.deviceId),u=a!=null&&a.running?z("screen.running"):z("screen.stopped");return`${z("screen.status")}:${u}
${z("screen.faceVelocity")}:${X(a==null?void 0:a.faceVelocity)}m/s
${z("screen.airflow")}:${X(a==null?void 0:a.airflow,0)}`}if(s.kind==="neLight"){const a=(r.neLights||[]).find(m=>m.id===s.lightId),u=a!=null&&a.on?z("screen.switchOn"):z("screen.switchOff");return`${z("screen.status")}:${u}`}return e.label}function $n(e){var s,a;if(e.category==="lightN"||e.category==="lightE")return e.on==null?"—":e.on?z("screen.switchOn"):z("screen.switchOff");if(e.category==="fridge"){const u=e.values||{temp:null,humidity:null};return`${X(u.temp)}℃
${X(u.humidity,0)}%`}if(e.category==="vav"){const u=e.on==null?"—":e.on?z("screen.running"):z("screen.stopped");return`${z("screen.status")}:${u}
${z("screen.faceVelocity")}:${X((s=e.vav)==null?void 0:s.faceVelocity)}m/s
${z("screen.airflow")}:${X((a=e.vav)==null?void 0:a.airflow,0)}`}if(e.category==="camera"||e.category==="access")return e.name;const r=e.values||{temp:null,humidity:null,pressure:null};return`${X(r.temp)}℃
${X(r.humidity,0)}%
${X(r.pressure)}Pa`}function Sn(e,r){const s=e.mode==="pressure";return{id:vt(e),name:e.label,text:bn(e,r),showText:!0,type:s?"label":"marker",x:e.x,y:e.y,z:e.z,tag0:pe[e.mode],tag1:e.id,scale:ut,...s?{}:{icon:We[e.mode]},...dt}}const Mn={...We,camera:"cctv-blue.png",access:"access-control-blue.png"};function xn(e){const r=Mn[e.category]||We.pressure,s=(e.icon||"").trim();return s?e.category==="camera"&&s==="cctv.png"?"cctv-blue.png":s:r}function ne(e){const r=e.category in pe?pe[e.category]:e.category||"pressure",s=e.category==="camera"||e.category==="access",a=e.category==="pressure";return{id:kn(e),name:e.name,text:$n(e),showText:!s,type:a?"label":"marker",x:e.scene.x,y:e.scene.y,z:e.scene.z,tag0:r,tag1:e.id,scale:ut,...a?{icon:""}:{icon:xn(e)},...dt}}function oe(e,...r){return(e.sensors||[]).filter(s=>r.includes(s.category))}function Cn(e,r){return e==="pressure"?oe(r,"pressure").map(ne):e==="lightN"?oe(r,"lightN").map(ne):e==="lightE"?oe(r,"lightE").map(ne):e==="fridge"?oe(r,"fridge").map(ne):e==="vav"?oe(r,"vav").map(ne):e==="camera"?oe(r,"camera").map(ne):e==="access"?oe(r,"access").map(ne):e==="home"?oe(r,"pressure","lightN","lightE","fridge","vav","access","camera").map(ne):Bt(e).map(s=>Sn(s,r))}function En(e,r,s){const a=je(),u=Me(),{locale:m}=de(),{mode:T}=He(a);let y=[],I="",R="",N="",D="",V="",L,j,_=0;function $(){_=2,!j&&(j=window.setInterval(()=>{if(_-=1,r.value&&e.ready.value)for(const g of y)e.setMarkerVisible(g,!0);_<=0&&j&&(window.clearInterval(j),j=void 0)},800))}function K(g){return g==="home"?new Set(Ae):g==="e066"?new Set:g in pe?new Set([pe[g]]):new Set}function O(g){return[...g].sort().join(",")}function x(g,C=!1){var Y;const P=K(g),U=O(P),W=g===D,ue=U===V;if(!C&&W&&ue)return;if(D=g,V=U,C||!W||!ue)for(const F of Ae)P.has(F)?e.showPois(F):e.hidePois(F);const J=((Y=e.listMarkers)==null?void 0:Y.call(e))||[];for(const F of J){if(F.id.startsWith(ft)||F.id.startsWith(mt))continue;const he=ct(F);if(!he)continue;const xe=g==="home"||P.has(he)||P.has(F.tag0);e.setMarkerVisible(F.id,xe)}}function f(){for(const g of y)e.setMarkerVisible(g,!0)}function d(){for(const g of y)try{e.setMarkerVisible(g,!1),e.removeMarker(g)}catch{}for(const g of Vt)try{e.removeMarker(vt(g))}catch{}y=[],I="",R="",D="",V=""}function p(g){return[...g].sort((C,P)=>C.id.localeCompare(P.id)).map(C=>{const P=Number(C.x).toFixed(5),U=Number(C.y).toFixed(5),W=Number(C.z).toFixed(2);return`${C.id}|${C.icon||""}|${C.type}|${P},${U},${W}`}).join(";")}function H(g){return[...g].sort((C,P)=>C.id.localeCompare(P.id)).map(C=>`${C.id}|${C.text||""}`).join(";")}function B(g){for(const C of g)e.updateMarkerText&&C.text!=null?e.updateMarkerText(C.id,String(C.text)):e.updateMarker(C)}function re(g=!1){if(!r.value||!e.ready.value)return;const C=T.value,P=C!==N,U=u.snapshot,W=Cn(C,U),ue=p(W),J=H(W);if(!g&&!P&&ue===I){J!==R&&(B(W),R=J),N=C;return}if(g||P){d(),D="",V="";for(const Y of Ae)e.hidePois(Y)}else{const Y=new Set(W.map(F=>F.id));for(const F of y)Y.has(F)||(e.setMarkerVisible(F,!1),e.removeMarker(F))}W.length&&(g||P||!y.length||W.length!==y.length?e.addMarkers(W):B(W)),y=W.map(Y=>Y.id),I=ue,R=J,N=C,x(C,g||P),f(),(g||P)&&window.setTimeout(()=>f(),400)}function le(){window.clearTimeout(L),L=window.setTimeout(()=>re(!1),1200)}async function ce(){re(!0),$()}return Z([T,r,()=>e.ready.value],()=>{window.clearTimeout(L),L=window.setTimeout(()=>{ce()},50)},{flush:"post"}),Z(()=>u.snapshot.ts,()=>le()),Z(m,()=>{R="",le()}),{clearModeMarkers:d,syncModePois:ce}}const Tn=[1,1,1,1],In=[.45,1,.55,1],pt="spot:",On=3.6,Ln=9e4,Rn=55,Pn=18,Nn=42,An=-90;function Dn(e){return e==="lightN"||e==="lightE"}function Be(e){return`${pt}${e}`}function Vn(e,r){const s=e.sensors||[];return r==="lightN"?s.filter(a=>a.category==="lightN"):r==="lightE"?s.filter(a=>a.category==="lightE"):[]}function Bn(e,r){var u,m,T;const s=e.category==="lightE",a=Number((u=e.scene)==null?void 0:u.z)||51;return{id:Be(e.id),name:e.name,type:"spot",x:Number((m=e.scene)==null?void 0:m.x)||0,y:Number((T=e.scene)==null?void 0:T.y)||0,z:a+On,yaw:0,pitch:An,roll:0,intensity:r?Ln:0,attenuationRadius:Rn,innerConeAngle:Pn,outerConeAngle:Nn,color:s?In:Tn,useTemperature:!1,castShadows:!0,visible:r,tag0:"facility-spot",tag1:e.category,tag2:e.id}}function Fn(e,r){const s=je(),a=Me(),{mode:u}=He(s);let m="";const T=new Map;let y=[],I=!1,R;function N(){for(const _ of y)try{e.setLightVisible(_,!1),e.removeLight(_)}catch{}y=[],T.clear()}function D(_,$=!1){!$&&_===I||(e.applyDayNight(_),I=_)}function V(_,$,K){const O=Be(_.id),x=Bn(_,$);K||!y.includes(O)?(e.addLight(x),y.includes(O)||y.push(O)):e.updateLight({id:O,type:"spot",intensity:x.intensity,color:x.color,visible:$,x:x.x,y:x.y,z:x.z,yaw:x.yaw,pitch:x.pitch,roll:x.roll,attenuationRadius:x.attenuationRadius,innerConeAngle:x.innerConeAngle,outerConeAngle:x.outerConeAngle}),e.setLightVisible(O,$),T.set(_.id,$)}function L(_=!1){if(!r.value||!e.ready.value)return;const $=u.value,K=Dn($),O=$!==m;if(!K){(I||y.length||O)&&(N(),D(!1,!0)),m=$;return}D(!0,_||O);const x=Vn(a.snapshot,$);if(_||O){N();for(const d of x)V(d,d.on===!0,!0);m=$;return}const f=new Set(x.map(d=>d.id));for(const d of x){const p=d.on===!0;T.get(d.id)===p&&y.includes(Be(d.id))||V(d,p,!1)}for(const d of[...y]){const p=d.slice(pt.length);f.has(p)||(e.setLightVisible(d,!1),e.removeLight(d),y=y.filter(H=>H!==d),T.delete(p))}m=$}function j(){window.clearTimeout(R),R=window.setTimeout(()=>L(!1),80)}return Z([u,r,()=>e.ready.value],()=>{window.clearTimeout(R),R=window.setTimeout(()=>L(!0),40)},{flush:"post"}),Z(()=>(a.snapshot.sensors||[]).filter($=>$.category==="lightN"||$.category==="lightE").map($=>`${$.id}:${$.on===!0?1:0}`).join(";"),()=>j()),{syncLightEffects:(_=!1)=>L(_),clearSpots:N}}const Hn={key:0,class:"vp-corners"},Wn={key:1,class:"vp-topbar"},jn={class:"area"},zn={class:"view"},Kn=["aria-label"],Xn=["onClick"],Yn={class:"name"},qn=["aria-label"],Un=["onClick"],Gn={key:3,class:"vp-room-panel"},Jn={class:"vp-room-head"},Qn={class:"vp-room-label"},Zn={class:"vp-room-sub"},eo={class:"vp-room-list"},to={class:"name"},no=["onClick"],oo={class:"name"},so=["src"],ao={key:6,class:"vp-tip"},io={key:0},ro={key:1},De="overview",lo="主视图",co="全景总览",uo=we({__name:"SceneViewport",props:{areaLabel:{default:""},layout:{default:"inset"}},setup(e){const r=e,s=Me(),a=je(),u=lt(),{t:m}=de(),{mode:T}=He(a),y="/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/gis/gis.html?scene=mvlpj2yt6379aa29",I=Q(()=>!!y),R=E(null),N=E(null),D=E(""),V=E([]),L=E(!1),j=E(""),_=E("video"),$=E([]),K=E(null),O=E(null),x=E(null),f=E(!1),d=E(""),p=E(120),H=E(120);let B=0;const re=E(null),le=E(!1);let ce=!1,g=!1,C=!1,P=null;const U=E(null);function W(){var t,n;try{return((n=(t=N.value)==null?void 0:t.contentDocument)==null?void 0:n.querySelector("video"))??null}catch{return null}}function ue(t,n){var ge;const o=W(),i=(ge=N.value)==null?void 0:ge.getBoundingClientRect();if(!i)return null;const h=(o==null?void 0:o.clientWidth)||i.width,k=(o==null?void 0:o.clientHeight)||i.height,c=(o==null?void 0:o.videoWidth)||0,S=(o==null?void 0:o.videoHeight)||0;if(!c||!S||h<=0||k<=0)return{x:t,y:n};const A=o?getComputedStyle(o).objectFit:"fill";if(A==="contain"||A==="scale-down"){const ee=Math.min(h/c,k/S),Oe=c*ee,Le=S*ee,Re=(h-Oe)/2,Pe=(k-Le)/2;return{x:Re+t*ee,y:Pe+n*ee}}if(A==="cover"){const ee=Math.max(h/c,k/S),Oe=c*ee,Le=S*ee,Re=(h-Oe)/2,Pe=(k-Le)/2;return{x:Re+t*ee,y:Pe+n*ee}}return{x:t/c*h,y:n/S*k}}function J(t){const n=N.value;if(!n)return null;const o=n.getBoundingClientRect(),i=getComputedStyle(n),h=parseFloat(i.borderLeftWidth)||0,k=parseFloat(i.borderTopWidth)||0;return{left:o.left+h+t.x,top:o.top+k+t.y}}function Y(t){const n=J({x:t.clientX,y:t.clientY});n&&(U.value=n),re.value={x:t.clientX,y:t.clientY}}function F(){var n;he();const t=(n=N.value)==null?void 0:n.contentDocument;t&&(t.addEventListener("pointerdown",Y,!0),t.addEventListener("click",Y,!0),P=t)}function he(){P&&(P.removeEventListener("pointerdown",Y,!0),P.removeEventListener("click",Y,!0),P=null)}function xe(){return{left:Math.max(0,Math.round(window.innerWidth/2-200)),top:Math.max(0,Math.round(window.innerHeight/2-120))}}function ze(t){if(!t||typeof t!="object")return null;const n=[t],o=t;o.data&&typeof o.data=="object"&&n.push(o.data),o.metaData&&typeof o.metaData=="object"&&n.push(o.metaData);for(const i of n){const h=Number(i.screenX??i.clientX??i.mouseX??i.px??i.screen_x??i.ScreenX??i.viewportX),k=Number(i.screenY??i.clientY??i.mouseY??i.py??i.screen_y??i.ScreenY??i.viewportY);if(Number.isFinite(h)&&Number.isFinite(k)&&(h!==0||k!==0))return{x:h,y:k}}return null}function Ke(t){var c;const n=(c=N.value)==null?void 0:c.getBoundingClientRect();if(!n)return null;const o=W(),i=(o==null?void 0:o.videoWidth)||0,h=(o==null?void 0:o.videoHeight)||0;if(i>n.width+8&&h>n.height+8&&(t.x>n.width+1||t.y>n.height+1)&&t.x>=0&&t.y>=0&&t.x<=i+2&&t.y<=h+2){const S=ue(t.x,t.y);return S?J(S):null}return t.x>=0&&t.y>=0&&t.x<=n.width+2&&t.y<=n.height+2?J(t):t.x>=0&&t.y>=0&&t.x<=window.innerWidth&&t.y<=window.innerHeight?{left:t.x,top:t.y}:null}function ht(t,n){var h,k;if(U.value){const c=U.value;return U.value=null,c}const o=re.value;if(o){const c=J(o);if(c)return c}const i=ze(n);if(i){const c=Ke(i);if(c)return c}if(t)try{const c=(h=N.value)==null?void 0:h.contentWindow,S=(k=c==null?void 0:c.$gisObj)==null?void 0:k.getMarker;if(typeof S=="function"){const A=S.call(c==null?void 0:c.$gisObj,t),ge=ze(A);if(ge)return Ke(ge)}}catch{}return null}function Ce(t,n,o){if(Date.now()<B)return;const i=ht(n,o)||xe();j.value=t,p.value=Math.round(i.left),H.value=Math.round(i.top),L.value=!0}function yt(){L.value=!1,O.value=null,d.value="",f.value=!1,B=Date.now()+400,U.value=null}function gt(t,n){const o=s.snapshot.sensors||[],i=[t.tag1,n,t.id].map(c=>String(c||"").replace(/^sm:sensor:/i,"").trim()).filter(Boolean);for(const c of i){const S=o.find(A=>(A.category==="lightN"||A.category==="lightE")&&(A.id===c||A.code===c));if(S)return S}const h=(t.name||"").trim();if(h){const c=o.find(S=>(S.category==="lightN"||S.category==="lightE")&&(S.name===h||S.name.includes(h)||h.includes(S.name)));if(c)return c}const k=String(t.tag1||"").trim();if(k){const c=k.replace(/^l[ne]-/,A=>A==="ln-"?"n-":"e-"),S=o.find(A=>(A.category==="lightN"||A.category==="lightE")&&(A.code===k||A.code===c));if(S)return S}return null}async function wt(t){if(O.value){if(!u.token){d.value=m("screen.loginToControl");return}f.value=!0,d.value="";try{await Ve(`/api/sensors/${O.value}/control`,{method:"POST",token:u.token,body:JSON.stringify({on:t})}),x.value=t;const n=O.value,o=(s.snapshot.sensors||[]).map(i=>i.id===n||i.code===n?{...i,on:t}:i);s.setSnapshot({...s.snapshot,ts:Date.now(),sensors:o}),window.setTimeout(()=>qe(),0)}catch(n){d.value=n instanceof Error?n.message:m("screen.controlFailed")}finally{f.value=!1}}}async function _t(){if(!(!I.value||C||g)){g=!0;try{await jt(void 0,y),a.setMode("pressure"),await Ge(),Ee(!0),ye(),await ke(),Ie(co),window.setTimeout(()=>{ce||Ee(!0),ye(),ke()},1500),window.setTimeout(()=>{ke()},3500)}catch{Ee(!0)}finally{g=!1,C=!0}}}function ye(){for(const t of V.value)t.scenePoint&&te.setMarkerVisible(t.id,!1)}function Ee(t=!1){if(I.value&&!(ce&&!t)){for(const n of V.value)if(n.scenePoint)try{te.setMarkerVisible(n.id,!1),te.removeMarker(n.id)}catch{}ce=!0}}function Te(t){return String(t||"").trim().replace(/^cam:/i,"")}function Xe(t){const n=t.trim();return!!(!n||/^cam:/i.test(n)||/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(n)||/^[0-9a-f]{16,}$/i.test(n))}function kt(t,n){const o=[n,t.id,t.tag1,t.tag2,t.name].map(Te).filter(Boolean);for(const h of o){const k=V.value.find(c=>c.id===h);if(k)return k}const i=(t.name||"").trim();if(i&&!Xe(i)){const h=V.value.find(k=>k.name===i||k.location===i);if(h)return h}return null}function bt(t,n,o){const i=((t==null?void 0:t.name)||(t==null?void 0:t.location)||"").trim();if(i)return i;const h=(n.name||"").trim(),k=new Set([o,n.id,n.tag1,n.tag0,n.tag2].map(Te).filter(Boolean));return h&&!Xe(h)&&!k.has(Te(h))?h:m("screen.camPreview")}function $t(t){if(Date.now()<B||L.value)return;const{markerId:n,marker:o,raw:i}=t;if(!n&&!o.id&&!o.tag0&&!o.name)return;const h=kt(o,n),k=ct(o);if(K.value=o,k==="camera"||h){_.value="video",$.value=[],O.value=null,Ce(bt(h,o,n),n||o.id,i);return}const c=gt(o,n);if(c||k==="lightN"||k==="lightE"){_.value="switch",$.value=[],O.value=(c==null?void 0:c.id)||(c==null?void 0:c.code)||null,x.value=(c==null?void 0:c.on)??null,d.value=c?"":m("screen.lightNotBound"),Ce((c==null?void 0:c.name)||o.name||m("screen.lightControl"),n||o.id,i);return}const S=ot(o,s.snapshot);S&&(_.value="values",$.value=S.lines,O.value=null,Ce(S.title,n||o.id,i))}const te=Ht({iframeRef:N,cloudUrl:y,onReady:()=>{_t(),F(),ke(),qe()},onMouseClick:$t}),Ye=Q(()=>r.layout==="fill"&&I.value),{syncModePois:ke}=En(te,Ye),{syncLightEffects:qe}=Fn(te,Ye);function Ue(t){return t.filter(n=>n.enabled&&n.scenePoint).map(n=>{const o=n.scenePoint;return`${n.id}:${o.x},${o.y},${o.z},${o.icon||""}`}).sort().join("|")}async function Ge(){try{const n=(await Ve("/api/video/devices")).devices||[],o=Ue(V.value)!==Ue(n);V.value=n,o&&(ce=!1)}catch{}}function St(){F(),window.setTimeout(()=>te.markReady(),2500)}function Mt(t){for(const n of Object.getOwnPropertySymbols(t)){const o=t[n];if(o&&typeof o=="object"&&typeof o.initializePan=="function"&&typeof o.onMouseDown=="function")return o}return null}function be(){const t=R.value;if(!t)return!1;const n=Mt(t);if(!(n!=null&&n.onMouseDown)||n.__mouseSwapped)return!!(n!=null&&n.__mouseSwapped);const o=n.onMouseDown.bind(n);return n.onMouseDown=i=>{const h=i.button===0?2:i.button===2?0:i.button,k=new Proxy(i,{get(c,S){if(S==="button")return h;const A=Reflect.get(c,S,c);return typeof A=="function"?A.bind(c):A}});o(k)},n.__mouseSwapped=!0,!0}function Je(){be()||requestAnimationFrame(()=>{be()||window.setTimeout(()=>be(),300)})}const fe=Q(()=>{const n=r.layout==="fill"&&I.value?null:s.snapshot.rooms;return an.map(o=>{const i=n==null?void 0:n.find(h=>h.id===o.roomId);return{id:o.id,name:o.name,viewpoint:o.viewpoint,roomId:o.roomId,temp:(i==null?void 0:i.temp)??null,humidity:(i==null?void 0:i.humidity)??null,pressure:(i==null?void 0:i.pressure)??null,alarms:(i==null?void 0:i.alarms)??[]}})}),Qe=Q(()=>fe.value.find(t=>t.id===D.value)||fe.value.find(t=>t.roomId===s.selectedRoomId)||fe.value[0]),xt=Q(()=>m("screen.modeRtengine"));function Ie(t){t&&te.flyToBookmark(t)}function Ze(t){const n=fe.value.find(o=>o.id===t);n&&(D.value=n.id,s.selectRoom(n.roomId),I.value&&Ie(n.viewpoint))}function et(){D.value=De,I.value&&Ie(lo)}function Ct(t){a.setMode(t),ye(),window.setTimeout(()=>ye(),300)}return Z(T,()=>ye()),Z(()=>s.snapshot.ts,()=>{if(!L.value||!K.value)return;if(_.value==="switch"&&O.value){const n=(s.snapshot.sensors||[]).find(o=>o.id===O.value||o.code===O.value);n&&!f.value&&(x.value=n.on??null);return}if(_.value!=="values")return;const t=ot(K.value,s.snapshot);t&&($.value=t.lines)}),Se(()=>{if(Ge(),r.layout==="fill"&&(le.value=!!document.getElementById("screen-float-overlays"),le.value||requestAnimationFrame(()=>{le.value=!!document.getElementById("screen-float-overlays")})),I.value){window.setTimeout(()=>te.markReady(),6e3);return}const t=R.value;t==null||t.addEventListener("load",Je),be()}),at(()=>{var t;(t=R.value)==null||t.removeEventListener("load",Je),he()}),(t,n)=>(b(),M("div",{class:G(["viewport",{"viewport--fill":r.layout==="fill"}])},[r.layout!=="fill"?(b(),M("div",Hn,[...n[1]||(n[1]=[l("i",null,null,-1),l("i",null,null,-1),l("i",null,null,-1),l("i",null,null,-1)])])):ie("",!0),r.layout!=="fill"?(b(),M("div",Wn,[q(se,{name:"pin"}),l("span",jn,w(e.areaLabel||`${v(m)("screen.currentArea")}:${Qe.value?v(m)(`areas.${Qe.value.id}`):"—"}`),1),n[2]||(n[2]=l("span",{class:"sep"},null,-1)),l("span",zn,w(xt.value),1)])):ie("",!0),r.layout==="fill"&&le.value?(b(),it(rt,{key:2,to:"#screen-float-overlays",defer:""},[l("div",{class:"vp-area-side","aria-label":v(m)("screen.deviceCategory")},[(b(!0),M(me,null,ve(v(Wt),o=>(b(),M("button",{key:o.id,type:"button",class:G(["vp-area-side-item",{active:o.id===v(T)}]),onClick:i=>Ct(o.id)},[l("span",Yn,w(v(m)(`modes.${o.id}`)),1)],10,Xn))),128))],8,Kn),l("div",{class:"vp-mode-bar","aria-label":v(m)("screen.areaFly")},[l("button",{type:"button",class:G(["vp-mode-item",{active:D.value===De}]),onClick:et},[q(se,{name:"pin","class-name":"room-ico"}),l("span",null,w(v(m)("screen.overview")),1)],2),(b(!0),M(me,null,ve(fe.value,o=>(b(),M("button",{key:o.id,type:"button",class:G(["vp-mode-item",{active:o.id===D.value,alarm:o.alarms.length>0}]),onClick:i=>Ze(o.id)},[q(se,{name:"pin","class-name":"room-ico"}),l("span",null,w(v(m)(`areas.${o.id}`)),1)],10,Un))),128))],8,qn)])):r.layout!=="fill"?(b(),M("div",Gn,[l("div",Jn,[q(se,{name:"pin"}),l("div",null,[l("div",Qn,w(v(m)("screen.areaNav")),1),l("div",Zn,w(v(m)("screen.clickFly")),1)])]),l("div",eo,[l("button",{type:"button",class:G(["vp-room-item",{active:D.value===De}]),onClick:et},[q(se,{name:"pin","class-name":"room-ico"}),l("span",to,w(v(m)("screen.overview")),1)],2),(b(!0),M(me,null,ve(fe.value,o=>(b(),M("button",{key:o.id,type:"button",class:G(["vp-room-item",{active:o.id===D.value,alarm:o.alarms.length>0}]),onClick:i=>Ze(o.id)},[q(se,{name:"pin","class-name":"room-ico"}),l("span",oo,w(v(m)(`areas.${o.id}`)),1)],10,no))),128))])])):ie("",!0),I.value?(b(),M("iframe",{key:4,ref_key:"cloudFrameRef",ref:N,class:"ue-frame",src:v(y),title:"RTEngineHD Cloud Render",allow:"autoplay; fullscreen; microphone; camera; clipboard-read; clipboard-write; display-capture",allowfullscreen:"",referrerpolicy:"no-referrer-when-downgrade",onLoad:St},null,40,so)):(b(),M("model-viewer",{key:5,ref_key:"viewerRef",ref:R,class:"scene",src:"/models/scene-model.glb","camera-controls":"","auto-rotate":"","shadow-intensity":"0.6",exposure:"1.1","interaction-prompt":"none",onContextmenu:n[0]||(n[0]=ae(()=>{},["prevent"]))},null,544)),r.layout!=="fill"?(b(),M("div",ao,[q(se,{name:"hand","class-name":"hand"}),I.value?(b(),M("span",io,w(v(m)("screen.tipCloud")),1)):(b(),M("span",ro,w(v(m)("screen.tipLocal")),1))])):ie("",!0),q(_n,{open:L.value,title:j.value,kind:_.value,lines:$.value,"switch-on":x.value,switching:f.value,"switch-error":d.value,left:p.value,top:H.value,src:"/cams/lab-seq.mp4",onClose:yt,onControl:wt},null,8,["open","title","kind","lines","switch-on","switching","switch-error","left","top"])],2))}}),fo=_e(uo,[["__scopeId","data-v-9d7e8d70"]]),mo={class:"scene-layer"},vo={class:"ui-layer"},po={class:"weather-wrap"},ho={class:"place"},yo={class:"temp"},go={class:"w-text"},wo={class:"humid"},_o={class:"clock-wrap"},ko={class:"time"},bo={class:"date"},$o={class:"alarm-wrap"},So=["aria-expanded"],Mo={class:"screen-main screen-main--float"},xo=["aria-label"],Co={class:"alarm-dd-head"},Eo={class:"alarm-dd-list"},To={class:"a-txt"},Io={class:"a-title"},Oo={class:"a-sub"},Lo={class:"a-state"},Ro=we({__name:"ScreenLayout",setup(e){const r=lt(),s=Me(),a=At(),{t:u}=de(),{time:m,date:T}=Dt(),{place:y,temp:I,text:R,humidity:N}=Xt(),{style:D}=Yt(),{title:V}=zt(),L=E(!1),j=E(null),_=E({}),$=Q(()=>{const d=s.snapshot.pointAlarms||[];return d.length?d.slice(0,12).map(p=>({level:p.level==="red"?"red":"amber",title:p.message,sub:p.name||u("screen.pointOverLimit"),state:u("screen.watching")})):[{level:"calm",title:u("screen.systemOk"),sub:u("screen.monitoring"),state:u("screen.normal")}]});Se(()=>{s.connect(),r.isLoggedIn&&!r.user&&r.fetchMe().catch(()=>{}),window.addEventListener("keydown",K)}),Fe(()=>{s.disconnect(),window.removeEventListener("keydown",K)});function K(d){d.key==="Escape"&&(L.value=!1)}function O(){const d=j.value,p=d==null?void 0:d.closest(".stage");if(!d||!p)return;const H=d.getBoundingClientRect(),B=p.getBoundingClientRect();_.value={top:`${Math.round(H.bottom-B.top+8)}px`,right:`${Math.round(B.right-H.right)}px`}}async function x(){L.value=!L.value,L.value&&(await Nt(),O())}function f(){r.isLoggedIn?a.push("/admin"):a.push({path:"/login",query:{redirect:"/admin"}})}return(d,p)=>{const H=Pt("RouterView");return b(),M("div",{class:"stage stage--immersive",style:$e(v(D))},[p[3]||(p[3]=l("div",{id:"screen-float-overlays",class:"screen-float-overlays"},null,-1)),l("div",mo,[q(fo,{layout:"fill"})]),p[4]||(p[4]=Rt('<div class="edge-mask" aria-hidden="true" data-v-59a30f96><i class="edge edge-t" data-v-59a30f96></i><i class="edge edge-b" data-v-59a30f96></i><i class="edge edge-l" data-v-59a30f96></i><i class="edge edge-r" data-v-59a30f96></i></div>',1)),l("div",vo,[q(en,{title:v(V)},{left:nt(()=>[l("div",po,[l("span",ho,w(v(y)),1),l("span",yo,w(v(I)),1),l("span",go,w(v(R)),1),l("span",wo,w(v(u)("screen.humidityPrefix"))+":"+w(v(N)),1)])]),right:nt(()=>[l("div",_o,[l("span",ko,w(v(m)),1),l("span",bo,w(v(T)),1)]),q(sn),l("div",$o,[l("button",{ref_key:"alarmBtnRef",ref:j,type:"button",class:G(["alarm-badge",{open:L.value}]),"aria-haspopup":"true","aria-expanded":L.value,onClick:ae(x,["stop"])},[p[2]||(p[2]=l("span",{class:"dot red"},null,-1)),l("span",null,w(v(u)("screen.alarm"))+" "+w(v(s).alarmCount),1)],10,So)]),l("button",{class:"tops-logout admin-entry",type:"button",onClick:f},w(v(u)("screen.admin")),1)]),_:1},8,["title"]),l("main",Mo,[q(H)])]),L.value?(b(),M("div",{key:0,class:"alarm-backdrop",onClick:p[0]||(p[0]=B=>L.value=!1)})):ie("",!0),L.value?(b(),M("div",{key:1,class:"alarm-dropdown",role:"dialog","aria-label":v(u)("screen.alarmList"),style:$e(_.value),onClick:p[1]||(p[1]=ae(()=>{},["stop"]))},[l("div",Co,[l("span",null,w(v(u)("screen.currentAlarms")),1),l("b",null,w(v(s).alarmCount),1)]),l("div",Eo,[(b(!0),M(me,null,ve($.value,(B,re)=>(b(),M("div",{key:`${B.title}-${re}`,class:G(["alarm-dd-item",B.level])},[q(se,{name:B.level==="red"?"alarm-warn":B.level==="amber"?"alarm-amber":"alarm-ok"},null,8,["name"]),l("div",To,[l("div",Io,w(B.title),1),l("div",Oo,w(B.sub),1)]),l("div",Lo,w(B.state),1)],2))),128))])],12,xo)):ie("",!0)],4)}}}),Ho=_e(Ro,[["__scopeId","data-v-59a30f96"]]);export{Ho as default};
.mask[data-v-a9087e36]{position:fixed;top:0;right:0;bottom:0;left:0;z-index:80;background:#000814b8;display:grid;place-items:center;padding:24px}.dialog[data-v-a9087e36]{width:min(1440px,98vw);height:min(860px,94vh);display:flex;flex-direction:column;background:#071426;border:1px solid rgba(0,247,255,.28);border-radius:8px;overflow:hidden;box-shadow:0 20px 60px #00000073}.head[data-v-a9087e36]{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid rgba(0,247,255,.16)}.head h3[data-v-a9087e36]{margin:0;font-size:16px;color:#f4feff;letter-spacing:.06em}.hint[data-v-a9087e36]{margin:0;padding:8px 16px;font-size:12px;color:#7eb6d6;background:#00284859}.body[data-v-a9087e36]{flex:1;min-height:0;display:grid;grid-template-columns:280px 1fr}.icon-pane[data-v-a9087e36]{display:flex;flex-direction:column;min-height:0;border-right:1px solid rgba(0,247,255,.14);background:#001024a6}.icon-head[data-v-a9087e36]{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 12px;font-size:12px;color:#f4feff;border-bottom:1px solid rgba(0,247,255,.12)}.icon-search[data-v-a9087e36]{width:120px;height:28px;border-radius:4px;border:1px solid rgba(0,247,255,.25);background:#00000059;color:#d7f4ff;padding:0 8px;font-size:12px}.icon-err[data-v-a9087e36]{margin:8px 12px 0;font-size:12px;color:#ffb0b0}.icon-grid[data-v-a9087e36]{flex:1;min-height:0;overflow:auto;padding:8px;display:grid;grid-template-columns:repeat(3,1fr);gap:8px;align-content:start}.icon-item[data-v-a9087e36]{display:flex;align-items:center;justify-content:center;min-height:88px;padding:10px 6px;border-radius:6px;border:1px solid rgba(0,247,255,.16);background:#081c3873;cursor:pointer}.icon-item img[data-v-a9087e36]{width:52px;height:52px;object-fit:contain}.icon-item[data-v-a9087e36]:hover{border-color:#00f7ff73}.icon-item.active[data-v-a9087e36]{border-color:#00f7ff;background:#0064a059;color:#fff;box-shadow:0 0 0 1px #00f7ff40 inset}.icon-current[data-v-a9087e36]{display:flex;align-items:center;gap:8px;padding:8px 12px;border-top:1px solid rgba(0,247,255,.12);font-size:11px;color:#7eb6d6}.icon-current img[data-v-a9087e36]{width:22px;height:22px;object-fit:contain}.icon-current b[data-v-a9087e36]{color:#f4feff;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-only-pane[data-v-a9087e36]{padding-bottom:12px}.text-only-tip[data-v-a9087e36]{margin:12px;font-size:12px;line-height:1.55;color:#7eb6d6}.text-only-sample[data-v-a9087e36]{margin:0 12px;padding:12px;border-radius:6px;border:1px solid rgba(0,247,255,.28);background:#00284873;color:#00f7ff;font-family:var(--digital-font, ui-monospace, monospace);font-size:14px;line-height:1.45;white-space:pre-wrap}.frame-wrap[data-v-a9087e36]{min-height:0;background:#000}.frame[data-v-a9087e36]{width:100%;height:100%;border:0;display:block}.foot[data-v-a9087e36]{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-top:1px solid rgba(0,247,255,.16)}.coords[data-v-a9087e36]{font-family:var(--digital-font);font-size:13px;color:var(--accent)}.coords.muted[data-v-a9087e36]{color:var(--panel-muted)}.actions[data-v-a9087e36]{display:flex;gap:8px}.admin-list-page[data-v-03b146a4]{min-height:0}.list-panel[data-v-03b146a4]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.head-actions[data-v-03b146a4]{display:flex;align-items:center;gap:10px}.filter[data-v-03b146a4]{min-width:120px;border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;color:#eaf4ff;padding:6px 10px}.desc[data-v-03b146a4]{margin:0 0 10px;font-size:12px;color:var(--panel-muted);line-height:1.5}.table-wrap[data-v-03b146a4]{flex:1;min-height:0;overflow:auto}.mono[data-v-03b146a4]{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px}.binds[data-v-03b146a4]{max-width:360px;font-size:12px;color:var(--panel-muted)}.ops[data-v-03b146a4]{display:flex;gap:6px;white-space:nowrap}.muted[data-v-03b146a4]{color:var(--panel-muted)}.msg.ok[data-v-03b146a4]{color:var(--ok);font-size:13px;margin-bottom:8px}.msg.err[data-v-03b146a4]{color:#ffb0b0;font-size:13px;margin:8px 0}.btn.danger[data-v-03b146a4]{color:#ffb0b0}.modal-mask[data-v-03b146a4]{position:fixed;top:0;right:0;bottom:0;left:0;background:#04080eb8;display:flex;align-items:center;justify-content:center;z-index:50}.modal[data-v-03b146a4]{width:min(720px,94vw);max-height:90vh;overflow:auto}.form-grid[data-v-03b146a4]{display:grid;grid-template-columns:1fr 1fr;gap:12px}.form-grid.roles[data-v-03b146a4]{grid-template-columns:1fr}.field label[data-v-03b146a4]{display:block;font-size:12px;color:var(--panel-muted);margin-bottom:4px}.field input[data-v-03b146a4],.field select[data-v-03b146a4]{width:100%;border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;color:#eaf4ff;padding:8px 10px}.field.check[data-v-03b146a4]{display:flex;align-items:end}.field.check label[data-v-03b146a4]{display:flex;align-items:center;gap:8px;color:#eaf4ff}.sub[data-v-03b146a4]{margin:16px 0 8px;font-size:13px;color:#eaf4ff}.comm-hint[data-v-03b146a4]{margin:-4px 0 10px;font-size:12px;color:var(--panel-muted);line-height:1.45}.modal-actions[data-v-03b146a4]{margin-top:14px;display:flex;gap:10px}
import{d as se,r as g,k as ee,l as ae,C as _e,c as a,w as ie,b as t,t as d,e as h,v as E,f as _,F as S,x as B,g as K,h as L,n as le,s as Q,o as i,_ as re,u as we,P as te,Q as xe,a as Ce,H as $e,R as Ee,p as F}from"./index-BssDqbym.js";import{u as Ie,h as Pe,r as Se,g as Te,i as Ve,a as Ne,d as Re}from"./useRtengineBridge-DNIfWox5.js";import"./t-ChxyHC3f.js";const Oe={class:"head"},Ue={class:"hint"},Ae={class:"body"},Me={key:0,class:"icon-pane"},Fe={class:"icon-head"},Le={key:0,class:"icon-err"},Ye={class:"icon-grid"},Xe=["title","aria-label","onClick"],Ze=["src","alt"],He={class:"icon-current"},De=["src"],Be={key:1,class:"icon-pane text-only-pane"},ze={class:"text-only-sample"},Ge={class:"frame-wrap"},Je=["src"],je={class:"foot"},qe={key:0,class:"coords"},Ke={key:1,class:"coords muted"},Qe={class:"actions"},We=["disabled"],ne="__pick_preview__",et=se({__name:"ScenePickDialog",props:{open:{type:Boolean},title:{},initial:{},pickHint:{default:"场景加载后,点击地面拾取位置"},defaultIcon:{default:"cctv-blue.png"},preferredIcons:{default:()=>["cctv-blue.png","cctv-green.png","cctv-orange.png","cctv-red.png","cctv.png","ai-camera-blue.png","ai-camera-green.png","ai-camera-orange.png","ai-camera-red.png"]},markerType:{default:"marker"},previewText:{default:""},showText:{type:Boolean,default:!0},textOnly:{type:Boolean,default:!1},previewName:{default:"打点预览"}},emits:["close","save"],setup(z,{emit:G}){var Z;const r=z,U=G,A=Pe(),j=g(null),b=g(r.initial?{...r.initial}:null),k=g(r.textOnly?"":((Z=r.initial)==null?void 0:Z.icon)||r.defaultIcon),x=g([]),M=g(""),v=g(""),C=g(r.pickHint),w=Q(()=>r.textOnly||r.markerType==="label"),T=Q(()=>{const u=r.preferredIcons||[],s=v.value.trim().toLowerCase();let m=x.value.slice();return m.sort(($,O)=>{const J=u.indexOf($),H=u.indexOf(O);return J>=0||H>=0?(J<0?999:J)-(H<0?999:H):$.localeCompare(O)}),s&&(m=m.filter($=>$.toLowerCase().includes(s))),m}),p=Ie({iframeRef:j,cloudUrl:A,onMouseClick:({point:u,markerId:s})=>{if(u){const m=w.value?"":k.value;b.value={...u,icon:m},C.value=s?`已拾取(对象 ${s})· 效果已按设备类型预览`:`已拾取 X=${u.x.toFixed(6)} Y=${u.y.toFixed(6)} Z=${u.z.toFixed(2)}`,I()}},onReady:()=>{C.value=w.value?"引擎已就绪 · 点击地面放置文字标签":"引擎已就绪 · 正在加载预设图标…",p.setPickMode(!0),p.showScenePresets(),N(!0),b.value&&I()}});function Y(){const u=b.value;if(!u)return null;const s=w.value,m=(r.previewText||r.previewName||r.title||"预览").trim();return{id:ne,name:r.previewName||r.title||"打点预览",text:m,showText:s?!0:r.showText,type:s?"label":r.markerType||"marker",x:u.x,y:u.y,z:u.z,tag0:"pick-preview",tag1:ne,scale:.5,icon:s?"":(k.value||"").trim(),leader:!0,leaderHeight:Ne,leaderThickness:2,leaderColor:"#00f7ff"}}function I(){const u=Y();!u||!p.ready.value||p.updateMarker(u)}function V(){try{p.removeMarker(ne)}catch{}}async function N(u=!1){if(w.value){x.value=[],k.value="",u&&(C.value="已就绪 · 点击地面放置文字标签(不显示图标)");return}M.value="";try{if(x.value=u?await Te(void 0,A):await Ve(A),!x.value.includes(k.value)&&x.value.length){const m=(r.preferredIcons||[]).find(O=>x.value.includes(O)),$=x.value.find(O=>/cctv|camera|speedometer|temperature|motor|electricity|access/i.test(O));k.value=m||$||x.value[0]}u&&(C.value=`已加载 ${x.value.length} 个场景预设图标 · 点击地面拾取`),I()}catch(s){M.value=s instanceof Error?s.message:"图标列表加载失败"}}ee(()=>r.open,u=>{var s;u?(b.value=r.initial?{...r.initial}:null,k.value=w.value?"":((s=r.initial)==null?void 0:s.icon)||r.defaultIcon,C.value=r.pickHint,N(),window.setTimeout(()=>{p.setPickMode(!0),I()},1500)):(V(),p.setPickMode(!1))}),ee(k,u=>{w.value||b.value&&(b.value={...b.value,icon:u},I())}),ee(()=>[r.previewText,r.markerType,r.showText,r.textOnly],()=>I()),ae(()=>{r.open&&(N(),window.setTimeout(()=>{p.setPickMode(!0),I()},1500))}),_e(()=>{V(),p.setPickMode(!1)});function R(){if(!b.value){C.value="请先在场景中点击拾取位置";return}const u=w.value?"":k.value;U("save",{...b.value,icon:u})}function X(){V(),b.value=null,C.value="已清除,请重新点击拾取"}function y(u){return Se(u,A)}return(u,s)=>z.open?(i(),a("div",{key:0,class:"mask",onClick:s[3]||(s[3]=ie(m=>U("close"),["self"]))},[t("div",{class:le(["dialog",{"no-icons":w.value}])},[t("div",Oe,[t("h3",null,d(z.title||"三维场景打点"),1),t("button",{class:"btn ghost",type:"button",onClick:s[0]||(s[0]=m=>U("close"))},"关闭")]),t("p",Ue,d(C.value),1),t("div",Ae,[w.value?(i(),a("aside",Be,[s[6]||(s[6]=t("div",{class:"icon-head"},[t("span",null,"显示效果")],-1)),s[7]||(s[7]=t("p",{class:"text-only-tip"}," 本类型为大屏文字标签:场景中只显示读数文字,不挂图标。点击地面即可预览落点效果。 ",-1)),t("pre",ze,d(z.previewText||`—℃
—%
—Pa`),1)])):(i(),a("aside",Me,[t("div",Fe,[s[4]||(s[4]=t("span",null,"引擎图标",-1)),h(t("input",{"onUpdate:modelValue":s[1]||(s[1]=m=>v.value=m),class:"icon-search",placeholder:"筛选…"},null,512),[[E,v.value]])]),M.value?(i(),a("p",Le,d(M.value),1)):_("",!0),t("div",Ye,[(i(!0),a(S,null,B(T.value,m=>(i(),a("button",{key:m,type:"button",class:le(["icon-item",{active:k.value===m}]),title:m,"aria-label":m,onClick:$=>k.value=m},[t("img",{src:y(m),alt:m,loading:"lazy"},null,8,Ze)],10,Xe))),128))]),t("div",He,[s[5]||(s[5]=K(" 当前: ",-1)),k.value?(i(),a("img",{key:0,src:y(k.value),alt:""},null,8,De)):_("",!0),t("b",null,d(k.value||"—"),1)])])),t("div",Ge,[t("iframe",{ref_key:"iframeRef",ref:j,class:"frame",src:L(A),title:"RTEngine pick",allow:"autoplay; fullscreen; microphone; camera; clipboard-read; clipboard-write; display-capture",allowfullscreen:"",referrerpolicy:"no-referrer-when-downgrade"},null,8,Je)])]),t("div",je,[b.value?(i(),a("div",qe," X "+d(b.value.x.toFixed(6))+" · Y "+d(b.value.y.toFixed(6))+" · Z "+d(b.value.z.toFixed(2)),1)):(i(),a("div",Ke,"尚未拾取")),t("div",Qe,[t("button",{class:"btn ghost",type:"button",onClick:X},"清除"),t("button",{class:"btn ghost",type:"button",onClick:s[2]||(s[2]=m=>U("close"))},"取消"),t("button",{class:"btn",type:"button",disabled:!b.value,onClick:R},"保存点位",8,We)])])],2)])):_("",!0)}}),tt=re(et,[["__scopeId","data-v-a9087e36"]]),nt={class:"page-fill admin-list-page"},ot={class:"panel list-panel"},lt={class:"panel-head"},st={class:"head-actions"},at=["value"],it=["disabled"],rt={key:0,class:"msg ok"},ut={key:1,class:"msg err"},ct={class:"table-wrap"},dt={class:"table"},pt={class:"mono"},mt=["disabled","onClick"],vt={class:"mono"},ft={class:"binds"},yt={key:0},gt={key:1},bt={class:"ops"},kt=["onClick"],ht=["onClick"],_t=["onClick"],wt={key:3,class:"muted"},xt={key:0},Ct={class:"modal panel"},$t={class:"panel-head"},Et={class:"panel-title"},It={class:"form-grid"},Pt={class:"field"},St={class:"field"},Tt={class:"field"},Vt=["value"],Nt={class:"field check"},Rt={class:"field"},Ot={class:"field"},Ut={class:"field"},At={class:"form-grid"},Mt={class:"field"},Ft={class:"field"},Lt={class:"field"},Yt={class:"field"},Xt={class:"field"},Zt={class:"form-grid roles"},Ht=["onUpdate:modelValue"],Dt=["value"],Bt={key:2,class:"msg err"},zt={class:"modal-actions"},Gt=["disabled"],Jt=se({__name:"SensorsView",setup(z){const G={pressure:"压差",lightN:"普通照明(N电)",lightE:"应急照明(E电)",fridge:"冰箱",vav:"通风柜",camera:"摄像头",access:"门禁",other:"其它"},r={temp:"温度",humidity:"湿度",pressure:"压差",value:"数值",status:"开关/开停",faceVelocity:"面风速",sashHeight:"视窗高度",airflow:"风量",alarmCode:"报警码"},U=["temp","humidity","pressure"],A=["status"],j=["temp","humidity"],b=["status","faceVelocity","sashHeight","airflow","alarmCode"];function k(n){return n==="pressure"?U:n==="lightN"||n==="lightE"?A:n==="fridge"?j:n==="vav"?b:n==="camera"||n==="access"?[]:U}const x={pressure:[],lightN:["electricity-meter-blue.png","electricity-meter-orange.png"],lightE:["electricity-meter-orange.png","electricity-meter-blue.png"],fridge:["temperature-sensor-orange.png","temperature-sensor-blue.png"],vav:["motor-green.png","motor-blue.png"],camera:["cctv-blue.png","cctv-green.png","cctv-orange.png","ai-camera-blue.png"],access:["access-control-blue.png","access-control-green.png","access-control-orange.png"]},M={...Re,camera:"cctv-blue.png",access:"access-control-blue.png"},v=we(),C=g(!1),w=g(!1),T=g(""),p=g(""),Y=g([]),I=g([]),V=g(""),N=g(!1),R=g(null),X=g(!1),y=g(null);function Z(n){return n==="pressure"?"":M[n]||"cctv-blue.png"}function u(n){var c;if(n.category==="pressure")return"";const e=(c=n.meta)==null?void 0:c.icon;return typeof e=="string"&&e.trim()?e.trim():Z(n.category)}function s(n){return n?{x:n.sceneX,y:n.sceneY,z:n.sceneZ,icon:u(n)}:null}function m(n){return n?n.category==="pressure"?`—℃
—%
—Pa`:n.category==="lightN"||n.category==="lightE"?"状态:—":n.category==="fridge"?`—℃
—%`:n.category==="vav"?`状态:—
面风速:—m/s
风量:—`:n.name:""}function $(n){return(n==null?void 0:n.category)==="pressure"}function O(n){return n?n.category!=="camera"&&n.category!=="access":!0}function J(n){return n?x[n.category]||Object.values(M):x.pressure}function H(){return{ip:"",protocol:"海康威视",port:"8000",username:"admin",password:""}}function W(n){return n==="camera"||n==="access"}function P(n,e,c=""){const o=n==null?void 0:n[e];return o==null?c:String(o)}const l=Ee({code:"",name:"",category:"pressure",enabled:!0,sceneX:0,sceneY:0,sceneZ:51,roles:{temp:"",humidity:"",pressure:"",status:"",faceVelocity:"",sashHeight:"",airflow:"",alarmCode:""},comm:H()}),oe=Q(()=>V.value?Y.value.filter(n=>n.category===V.value):Y.value),ue=Q(()=>I.value.filter(n=>n.enabled).slice().sort((n,e)=>n.name.localeCompare(e.name,"zh-CN")));function ce(n){const e=n.lastEng==null?"—":String(n.lastEng);return`${n.name}(${n.itemId} · ${e})`}function de(n){var e;return(e=n.points)!=null&&e.length?n.points.map(c=>`${r[c.role]||c.role}:${c.pointName||c.itemId||c.pointId.slice(0,8)}`).join(" · "):"未绑定"}async function D(){C.value=!0,p.value="";try{const[n,e]=await Promise.all([F("/api/sensors",{token:v.token}),F("/api/devices/points",{token:v.token})]);Y.value=n.sensors||[],I.value=e.points||[]}catch(n){p.value=n instanceof Error?n.message:"加载失败"}finally{C.value=!1}}function pe(){v.isAdmin&&(R.value=null,l.code="",l.name="",l.category=V.value||"pressure",l.enabled=!0,l.sceneX=133.543,l.sceneY=22.1972,l.sceneZ=51,l.roles={temp:"",humidity:"",pressure:"",status:"",faceVelocity:"",sashHeight:"",airflow:"",alarmCode:""},l.comm=H(),p.value="",N.value=!0)}function me(n){if(!v.isAdmin)return;R.value=n.id,l.code=n.code,l.name=n.name,l.category=n.category,l.enabled=n.enabled,l.sceneX=n.sceneX,l.sceneY=n.sceneY,l.sceneZ=n.sceneZ,l.roles={temp:"",humidity:"",pressure:"",status:"",faceVelocity:"",sashHeight:"",airflow:"",alarmCode:""};for(const c of n.points||[])l.roles[c.role]=c.pointId;const e=n.meta||{};l.comm={ip:P(e,"ip"),protocol:P(e,"protocol","海康威视"),port:P(e,"port","8000"),username:P(e,"username","admin"),password:P(e,"password")},p.value="",N.value=!0}function ve(n){const e={...n||{}};if(!W(l.category))return delete e.ip,delete e.protocol,delete e.port,delete e.username,delete e.password,e;e.ip=l.comm.ip.trim(),e.protocol=l.comm.protocol.trim()||"海康威视";const c=Number(l.comm.port);return e.port=Number.isFinite(c)&&c>0?c:8e3,e.username=l.comm.username.trim(),e.password=l.comm.password,e}function q(){N.value=!1,p.value=""}function fe(){return[...k(l.category)].filter(e=>l.roles[e]).map((e,c)=>({role:e,pointId:l.roles[e],sort:c}))}async function ye(){if(!v.isAdmin)return;const n=l.code.trim(),e=l.name.trim();if(!n||!e){p.value="编码与名称必填";return}w.value=!0,p.value="",T.value="";const c=R.value?Y.value.find(f=>f.id===R.value):void 0,o={code:n,name:e,category:l.category,enabled:l.enabled,sceneX:Number(l.sceneX),sceneY:Number(l.sceneY),sceneZ:Number(l.sceneZ),points:fe(),meta:ve(c==null?void 0:c.meta)};try{R.value?(await F(`/api/sensors/${R.value}`,{method:"PUT",token:v.token,body:JSON.stringify(o)}),T.value="设施已更新"):(await F("/api/sensors",{method:"POST",token:v.token,body:JSON.stringify(o)}),T.value="设施已创建"),q(),await D()}catch(f){p.value=f instanceof Error?f.message:"保存失败"}finally{w.value=!1}}async function ge(n){if(v.isAdmin)try{await F(`/api/sensors/${n.id}`,{method:"PUT",token:v.token,body:JSON.stringify({enabled:!n.enabled})}),await D()}catch(e){p.value=e instanceof Error?e.message:"更新失败"}}async function be(n){if(v.isAdmin&&window.confirm(`确定删除设施「${n.name}」?`))try{await F(`/api/sensors/${n.id}`,{method:"DELETE",token:v.token}),T.value="已删除",await D()}catch(e){p.value=e instanceof Error?e.message:"删除失败"}}function ke(n){v.isAdmin&&(y.value=n,X.value=!0)}async function he(n){if(!y.value)return;const e=y.value,c=e.category==="pressure"?"":(n.icon||"").trim()||Z(e.category),o={...e.meta||{},icon:c};try{await F(`/api/sensors/${e.id}`,{method:"PUT",token:v.token,body:JSON.stringify({sceneX:n.x,sceneY:n.y,sceneZ:n.z,meta:o})}),T.value=`已保存「${e.name}」三维点位`,X.value=!1,y.value=null,await D()}catch(f){p.value=f instanceof Error?f.message:"保存点位失败"}}return ae(D),(n,e)=>{var c;return i(),a("div",nt,[t("section",ot,[t("div",lt,[e[15]||(e[15]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"设施管理")],-1)),t("div",st,[h(t("select",{"onUpdate:modelValue":e[0]||(e[0]=o=>V.value=o),class:"filter"},[e[14]||(e[14]=t("option",{value:""},"全部分类",-1)),(i(),a(S,null,B(G,(o,f)=>t("option",{key:f,value:f},d(o),9,at)),64))],512),[[te,V.value]]),t("button",{class:"btn ghost",type:"button",disabled:C.value,onClick:D},"刷新",8,it),L(v).isAdmin?(i(),a("button",{key:0,class:"btn",type:"button",onClick:pe},"新建设施")):_("",!0)])]),e[18]||(e[18]=t("p",{class:"desc"}," 设施含压差、照明 N/E 电、冰箱、通风柜、摄像头、门禁(后四类与交底表对齐)。摄像头/门禁可编辑通信参数(IP、协议、管理端口、用户名、密码),并通过「三维打点」调整坐标与图标。 ",-1)),T.value?(i(),a("p",rt,d(T.value),1)):_("",!0),p.value&&!N.value?(i(),a("p",ut,d(p.value),1)):_("",!0),t("div",ct,[t("table",dt,[e[17]||(e[17]=t("thead",null,[t("tr",null,[t("th",null,"名称"),t("th",null,"编码"),t("th",null,"分类"),t("th",null,"启用"),t("th",null,"坐标"),t("th",null,"绑定点位 / 通信"),t("th",null,"操作")])],-1)),t("tbody",null,[(i(!0),a(S,null,B(oe.value,o=>(i(),a("tr",{key:o.id},[t("td",null,d(o.name),1),t("td",pt,d(o.code),1),t("td",null,d(G[o.category]||o.category),1),t("td",null,[t("button",{class:"btn ghost",type:"button",disabled:!L(v).isAdmin,onClick:f=>ge(o)},d(o.enabled?"是":"否"),9,mt)]),t("td",vt,d(o.sceneX.toFixed(6))+", "+d(o.sceneY.toFixed(6))+", "+d(o.sceneZ),1),t("td",ft,[W(o.category)?(i(),a(S,{key:0},[K(d(P(o.meta,"ip")||"未配置 IP")+" ",1),P(o.meta,"port")?(i(),a("span",yt," · :"+d(P(o.meta,"port")),1)):_("",!0),P(o.meta,"protocol")?(i(),a("span",gt," · "+d(P(o.meta,"protocol")),1)):_("",!0)],64)):(i(),a(S,{key:1},[K(d(de(o)),1)],64))]),t("td",bt,[L(v).isAdmin?(i(),a("button",{key:0,class:"btn ghost",type:"button",onClick:f=>ke(o)}," 三维打点 ",8,kt)):_("",!0),L(v).isAdmin?(i(),a("button",{key:1,class:"btn ghost",type:"button",onClick:f=>me(o)}," 编辑 ",8,ht)):_("",!0),L(v).isAdmin?(i(),a("button",{key:2,class:"btn ghost danger",type:"button",onClick:f=>be(o)}," 删除 ",8,_t)):_("",!0),L(v).isAdmin?_("",!0):(i(),a("span",wt,"—"))])]))),128)),oe.value.length?_("",!0):(i(),a("tr",xt,[...e[16]||(e[16]=[t("td",{colspan:"7",class:"muted"},"暂无设施",-1)])]))])])])]),N.value?(i(),a("div",{key:0,class:"modal-mask",onClick:ie(q,["self"])},[t("div",Ct,[t("div",$t,[t("div",Et,[e[19]||(e[19]=t("div",{class:"vbar"},null,-1)),t("h3",null,d(R.value?"编辑设施":"新建设施"),1)]),t("button",{class:"btn ghost",type:"button",onClick:q},"关闭")]),t("div",It,[t("div",Pt,[e[20]||(e[20]=t("label",null,"编码",-1)),h(t("input",{"onUpdate:modelValue":e[1]||(e[1]=o=>l.code=o),type:"text",placeholder:"p-seq"},null,512),[[E,l.code]])]),t("div",St,[e[21]||(e[21]=t("label",null,"名称",-1)),h(t("input",{"onUpdate:modelValue":e[2]||(e[2]=o=>l.name=o),type:"text",placeholder:"测序区压差"},null,512),[[E,l.name]])]),t("div",Tt,[e[22]||(e[22]=t("label",null,"分类",-1)),h(t("select",{"onUpdate:modelValue":e[3]||(e[3]=o=>l.category=o)},[(i(),a(S,null,B(G,(o,f)=>t("option",{key:f,value:f},d(o),9,Vt)),64))],512),[[te,l.category]])]),t("div",Nt,[t("label",null,[h(t("input",{"onUpdate:modelValue":e[4]||(e[4]=o=>l.enabled=o),type:"checkbox"},null,512),[[xe,l.enabled]]),e[23]||(e[23]=K(" 启用 ",-1))])]),t("div",Rt,[e[24]||(e[24]=t("label",null,"场景 X (lng)",-1)),h(t("input",{"onUpdate:modelValue":e[5]||(e[5]=o=>l.sceneX=o),type:"number",step:"0.0000001"},null,512),[[E,l.sceneX,void 0,{number:!0}]])]),t("div",Ot,[e[25]||(e[25]=t("label",null,"场景 Y (lat)",-1)),h(t("input",{"onUpdate:modelValue":e[6]||(e[6]=o=>l.sceneY=o),type:"number",step:"0.0000001"},null,512),[[E,l.sceneY,void 0,{number:!0}]])]),t("div",Ut,[e[26]||(e[26]=t("label",null,"场景 Z (height)",-1)),h(t("input",{"onUpdate:modelValue":e[7]||(e[7]=o=>l.sceneZ=o),type:"number",step:"0.1"},null,512),[[E,l.sceneZ,void 0,{number:!0}]])])]),W(l.category)?(i(),a(S,{key:0},[e[33]||(e[33]=t("h4",{class:"sub"},"通信参数",-1)),e[34]||(e[34]=t("p",{class:"comm-hint"},"参考交底表:IP 通道地址、协议、管理端口、用户名、密码。",-1)),t("div",At,[t("div",Mt,[e[27]||(e[27]=t("label",null,"IP 通道地址",-1)),h(t("input",{"onUpdate:modelValue":e[8]||(e[8]=o=>l.comm.ip=o),type:"text",placeholder:"192.168.10.150",autocomplete:"off"},null,512),[[E,l.comm.ip]])]),t("div",Ft,[e[28]||(e[28]=t("label",null,"协议",-1)),h(t("input",{"onUpdate:modelValue":e[9]||(e[9]=o=>l.comm.protocol=o),type:"text",placeholder:"海康威视",list:"comm-protocol-list"},null,512),[[E,l.comm.protocol]]),e[29]||(e[29]=Ce('<datalist id="comm-protocol-list" data-v-03b146a4><option value="海康威视" data-v-03b146a4></option><option value="sdk" data-v-03b146a4></option><option value="rtsp" data-v-03b146a4></option><option value="isapi" data-v-03b146a4></option></datalist>',1))]),t("div",Lt,[e[30]||(e[30]=t("label",null,"管理端口",-1)),h(t("input",{"onUpdate:modelValue":e[10]||(e[10]=o=>l.comm.port=o),type:"text",placeholder:"8000",inputmode:"numeric"},null,512),[[E,l.comm.port]])]),t("div",Yt,[e[31]||(e[31]=t("label",null,"用户名",-1)),h(t("input",{"onUpdate:modelValue":e[11]||(e[11]=o=>l.comm.username=o),type:"text",placeholder:"admin",autocomplete:"username"},null,512),[[E,l.comm.username]])]),t("div",Xt,[e[32]||(e[32]=t("label",null,"密码",-1)),h(t("input",{"onUpdate:modelValue":e[12]||(e[12]=o=>l.comm.password=o),type:"password",placeholder:"设备登录密码",autocomplete:"new-password"},null,512),[[E,l.comm.password]])])])],64)):(i(),a(S,{key:1},[e[36]||(e[36]=t("h4",{class:"sub"},"点位绑定",-1)),t("div",Zt,[(i(!0),a(S,null,B(k(l.category),o=>(i(),a("div",{key:o,class:"field"},[t("label",null,d(r[o]||o),1),h(t("select",{"onUpdate:modelValue":f=>l.roles[o]=f},[e[35]||(e[35]=t("option",{value:""},"— 未选择 —",-1)),(i(!0),a(S,null,B(ue.value,f=>(i(),a("option",{key:f.id,value:f.id},d(ce(f)),9,Dt))),128))],8,Ht),[[te,l.roles[o]]])]))),128))])],64)),p.value?(i(),a("p",Bt,d(p.value),1)):_("",!0),t("div",zt,[t("button",{class:"btn",type:"button",disabled:w.value,onClick:ye},d(w.value?"保存中…":"保存"),9,Gt),t("button",{class:"btn ghost",type:"button",onClick:q},"取消")])])])):_("",!0),$e(tt,{open:X.value,title:y.value?`打点 · ${y.value.name}`:"设施三维打点",initial:s(y.value),"pick-hint":$(y.value)?"场景加载后,点击地面放置压差文字标签(不显示图标)":"场景加载后,点击地面拾取设施位置;左侧可选该类默认图标","default-icon":y.value?Z(y.value.category):"cctv-blue.png","preferred-icons":J(y.value),"marker-type":$(y.value)?"label":"marker","text-only":$(y.value),"preview-text":m(y.value),"preview-name":((c=y.value)==null?void 0:c.name)||"设施","show-text":O(y.value),onClose:e[13]||(e[13]=o=>X.value=!1),onSave:he},null,8,["open","title","initial","pick-hint","default-icon","preferred-icons","marker-type","text-only","preview-text","preview-name","show-text"])])}}}),Qt=re(Jt,[["__scopeId","data-v-03b146a4"]]);export{Qt as default};
.admin-list-page[data-v-64a5b5b8]{min-height:0}.list-panel[data-v-64a5b5b8]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.head-actions[data-v-64a5b5b8]{display:flex;align-items:center;gap:10px}.table-wrap[data-v-64a5b5b8]{flex:1;min-height:0;overflow:auto}.muted[data-v-64a5b5b8]{color:var(--panel-muted)}.hint[data-v-64a5b5b8]{margin-top:12px;font-size:12px;color:var(--panel-muted)}.msg.ok[data-v-64a5b5b8]{color:var(--ok);font-size:13px;margin-bottom:8px}.msg.err[data-v-64a5b5b8]{color:#ffb0b0;font-size:13px;margin:8px 0}.desc[data-v-64a5b5b8]{margin:0 0 12px;font-size:12px;color:var(--panel-muted);line-height:1.6}.presets[data-v-64a5b5b8]{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}.preset[data-v-64a5b5b8]{border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;color:var(--panel-muted);padding:6px 12px;font-size:12px;cursor:pointer;font-weight:600}.preset.active[data-v-64a5b5b8]{background:#3dbeff38;color:#eaf4ff;border-color:#3dbeff8c}.poll-form[data-v-64a5b5b8]{grid-template-columns:1fr 1fr}.title-form[data-v-64a5b5b8]{grid-template-columns:1fr}.modal-mask[data-v-64a5b5b8]{position:fixed;top:0;right:0;bottom:0;left:0;background:#04080eb8;display:flex;align-items:center;justify-content:center;z-index:50}.modal[data-v-64a5b5b8]{width:min(560px,92vw);max-height:90vh;overflow:auto}.modal-actions[data-v-64a5b5b8]{margin-top:14px;display:flex;gap:10px}
import{d as D,u as U,j as V,c as n,b as e,n as C,h,t as i,f as r,F as w,z as P,w as z,r as c,B as L,l as S,o,_ as R}from"./index-Bs_x-_cK.js";const j={class:"page-fill admin-list-page"},I={class:"panel list-panel"},G={class:"panel-head"},J={class:"head-actions"},O={key:0,class:"msg ok"},T={key:1,class:"msg err"},q={class:"table-wrap"},H={class:"table"},K={key:1,class:"muted"},Q={key:2,class:"hint"},W={class:"modal panel"},X={class:"presets"},Y=["onClick"],Z={class:"form-grid poll-form"},ee={class:"field"},le=["value"],te={class:"field"},se=["value"],ae={key:0,class:"msg err"},ne={class:"modal-actions"},oe=["disabled"],ue=D({__name:"SettingsView",setup(ie){const u=U(),A="rtengine",E="/rtengine/gis.html?scene=mvlpj2yt6379aa29",a=c(null),v=c(2e3),b=c(2),p=c(!1),y=c(""),d=c(""),_=c(!1),x=[{label:"1 秒",ms:1e3},{label:"2 秒",ms:2e3},{label:"5 秒",ms:5e3},{label:"10 秒",ms:1e4},{label:"30 秒",ms:3e4},{label:"1 分钟",ms:6e4}],N=L(()=>{var t,l,s,f,M;return[{key:"user",label:"当前用户",value:`${((t=u.user)==null?void 0:t.displayName)||"—"} (${((l=u.user)==null?void 0:l.username)||"—"})`},{key:"viewport",label:"三维视口模式",value:A},{key:"ue",label:"云渲染 / UE 地址",value:E},{key:"dataMode",label:"数据采集模式",value:((s=a.value)==null?void 0:s.dataMode)==="modbus"?"Modbus 实采":((f=a.value)==null?void 0:f.dataMode)==="gateway"?"网关实采":"Mock 模拟"},{key:"retention",label:"采集数据保留",value:`${((M=a.value)==null?void 0:M.collectRetentionDays)??"—"} 天`},{key:"poll",label:"数据采集频率",value:a.value?`${a.value.collectPollMs/1e3} 秒`:"—",editable:!0},{key:"access",label:"门禁桥接",value:"ACCESS_BRIDGE_URL 未配置时使用 Mock"}]});function m(t){v.value=t,b.value=+(t/1e3).toFixed(t%1e3===0?0:1)}function B(t){const l=Math.max(.5,Math.min(600,t||.5));b.value=l,v.value=Math.round(l*1e3)}function g(){u.isAdmin&&(a.value&&m(a.value.collectPollMs),d.value="",_.value=!0)}function k(){_.value=!1,d.value=""}async function $(){y.value="";try{const t=await S("/api/settings",{token:u.token});a.value=t,m(t.collectPollMs)}catch(t){d.value=t instanceof Error?t.message:"加载失败"}}async function F(){if(u.isAdmin){p.value=!0,d.value="";try{const t=await S("/api/settings/collect-poll",{method:"PUT",token:u.token,body:JSON.stringify({collectPollMs:v.value})});a.value=t,m(t.collectPollMs),y.value=`采集频率已更新为 ${b.value} 秒`,k()}catch(t){d.value=t instanceof Error?t.message:"保存失败"}finally{p.value=!1}}}return V($),(t,l)=>(o(),n("div",j,[e("section",I,[e("div",G,[l[2]||(l[2]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"系统设置")],-1)),e("div",J,[e("div",{class:C(["badge",h(u).isAdmin?"":"amber"])},i(h(u).isAdmin?"管理员":"只读"),3),h(u).isAdmin?(o(),n("button",{key:0,class:"btn",type:"button",onClick:g}," 编辑采集频率 ")):r("",!0)])]),y.value?(o(),n("p",O,i(y.value),1)):r("",!0),d.value&&!_.value?(o(),n("p",T,i(d.value),1)):r("",!0),e("div",q,[e("table",H,[l[3]||(l[3]=e("thead",null,[e("tr",null,[e("th",null,"配置项"),e("th",null,"当前值"),e("th",null,"操作")])],-1)),e("tbody",null,[(o(!0),n(w,null,P(N.value,s=>(o(),n("tr",{key:s.key},[e("td",null,i(s.label),1),e("td",null,i(s.value),1),e("td",null,[s.editable&&h(u).isAdmin?(o(),n("button",{key:0,class:"btn ghost",type:"button",onClick:g}," 编辑 ")):(o(),n("span",K,"—"))])]))),128))])])]),a.value?(o(),n("p",Q," 最近更新:"+i(a.value.updatedBy||"—")+" · "+i(new Date(a.value.updatedAt).toLocaleString("zh-CN",{hour12:!1})),1)):r("",!0)]),_.value?(o(),n("div",{key:0,class:"modal-mask",onClick:z(k,["self"])},[e("div",W,[e("div",{class:"panel-head"},[l[4]||(l[4]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"编辑采集频率")],-1)),e("button",{class:"btn ghost",type:"button",onClick:k},"关闭")]),l[7]||(l[7]=e("p",{class:"desc"}," 控制服务端轮询周期,保存后立即生效。允许范围 0.5–600 秒。 ",-1)),e("div",X,[(o(),n(w,null,P(x,s=>e("button",{key:s.ms,type:"button",class:C(["preset",{active:v.value===s.ms}]),onClick:f=>m(s.ms)},i(s.label),11,Y)),64))]),e("div",Z,[e("div",ee,[l[5]||(l[5]=e("label",null,"周期(秒)",-1)),e("input",{value:b.value,type:"number",min:"0.5",max:"600",step:"0.5",onChange:l[0]||(l[0]=s=>B(Number(s.target.value)))},null,40,le)]),e("div",te,[l[6]||(l[6]=e("label",null,"周期(毫秒)",-1)),e("input",{value:v.value,type:"number",min:"500",max:"600000",step:"100",onChange:l[1]||(l[1]=s=>m(Number(s.target.value)))},null,40,se)])]),d.value?(o(),n("p",ae,i(d.value),1)):r("",!0),e("div",ne,[e("button",{class:"btn",type:"button",disabled:p.value,onClick:F},i(p.value?"保存中…":"保存并生效"),9,oe),e("button",{class:"btn ghost",type:"button",onClick:k},"取消")])])])):r("",!0)]))}}),ce=R(ue,[["__scopeId","data-v-ed6d7751"]]);export{ce as default};
import{d as J,u as O,l as j,c as o,b as e,n as D,h as f,t as d,f as c,F as U,x as $,w as T,e as G,v as q,a1 as H,r,s as Q,p as E,o as i,_ as W}from"./index-BssDqbym.js";import{D as w,p as X}from"./useScreenTitle-DLVybyzQ.js";const Y={class:"page-fill admin-list-page"},Z={class:"panel list-panel"},ee={class:"panel-head"},te={class:"head-actions"},le={key:0,class:"msg ok"},se={key:1,class:"msg err"},ae={class:"table-wrap"},ne={class:"table"},oe=["onClick"],ie={key:1,class:"muted"},ue={key:2,class:"hint"},de={class:"modal panel"},ce={class:"form-grid title-form"},re={class:"field"},ve=["onKeydown"],pe={class:"hint"},be={key:0,class:"msg err"},me={class:"modal-actions"},ye=["disabled"],fe={class:"modal panel"},_e={class:"presets"},he=["onClick"],ke={class:"form-grid poll-form"},ge={class:"field"},Ce=["value"],Me={class:"field"},we=["value"],Te={key:0,class:"msg err"},Ee={class:"modal-actions"},Ae=["disabled"],Se=J({__name:"SettingsView",setup(xe){const u=O(),F="rtengine",B="/rtengine/gis.html?scene=mvlpj2yt6379aa29",n=r(null),b=r(2e3),_=r(2),p=r(w),v=r(!1),m=r(""),a=r(""),h=r(!1),k=r(!1),L=[{label:"1 秒",ms:1e3},{label:"2 秒",ms:2e3},{label:"5 秒",ms:5e3},{label:"10 秒",ms:1e4},{label:"30 秒",ms:3e4},{label:"1 分钟",ms:6e4}],V=Q(()=>{var l,t,s,M,P,N;return[{key:"user",label:"当前用户",value:`${((l=u.user)==null?void 0:l.displayName)||"—"} (${((t=u.user)==null?void 0:t.username)||"—"})`},{key:"screenTitle",label:"大屏标题",value:((s=n.value)==null?void 0:s.screenTitle)||w,editable:!0,edit:"title"},{key:"viewport",label:"三维视口模式",value:F},{key:"ue",label:"云渲染 / UE 地址",value:B},{key:"dataMode",label:"数据采集模式",value:((M=n.value)==null?void 0:M.dataMode)==="modbus"?"Modbus 实采":((P=n.value)==null?void 0:P.dataMode)==="gateway"?"网关实采":"Mock 模拟"},{key:"retention",label:"采集数据保留",value:`${((N=n.value)==null?void 0:N.collectRetentionDays)??"—"} 天`},{key:"poll",label:"数据采集频率",value:n.value?`${n.value.collectPollMs/1e3} 秒`:"—",editable:!0,edit:"poll"},{key:"access",label:"门禁桥接",value:"ACCESS_BRIDGE_URL 未配置时使用 Mock"}]});function y(l){b.value=l,_.value=+(l/1e3).toFixed(l%1e3===0?0:1)}function R(l){const t=Math.max(.5,Math.min(600,l||.5));_.value=t,b.value=Math.round(t*1e3)}function A(){u.isAdmin&&(n.value&&y(n.value.collectPollMs),a.value="",h.value=!0)}function g(){h.value=!1,a.value=""}function S(){var l;u.isAdmin&&(p.value=((l=n.value)==null?void 0:l.screenTitle)||w,a.value="",k.value=!0)}function C(){k.value=!1,a.value=""}function I(l){l==="title"?S():A()}async function K(){m.value="";try{const l=await E("/api/settings",{token:u.token});n.value=l,y(l.collectPollMs),p.value=l.screenTitle||w}catch(l){a.value=l instanceof Error?l.message:"加载失败"}}async function z(){if(u.isAdmin){v.value=!0,a.value="";try{const l=await E("/api/settings/collect-poll",{method:"PUT",token:u.token,body:JSON.stringify({collectPollMs:b.value})});n.value=l,y(l.collectPollMs),m.value=`采集频率已更新为 ${_.value} 秒`,g()}catch(l){a.value=l instanceof Error?l.message:"保存失败"}finally{v.value=!1}}}async function x(){if(!u.isAdmin)return;const l=p.value.trim();if(!l){a.value="大屏标题不能为空";return}if(l.length>64){a.value="大屏标题最多 64 个字符";return}v.value=!0,a.value="";try{const t=await E("/api/settings/screen-title",{method:"PUT",token:u.token,body:JSON.stringify({screenTitle:l})});n.value=t,p.value=t.screenTitle,X(t.screenTitle),m.value="大屏标题已更新",C()}catch(t){a.value=t instanceof Error?t.message:"保存失败"}finally{v.value=!1}}return j(K),(l,t)=>(i(),o("div",Y,[e("section",Z,[e("div",ee,[t[3]||(t[3]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"系统设置")],-1)),e("div",te,[e("div",{class:D(["badge",f(u).isAdmin?"":"amber"])},d(f(u).isAdmin?"管理员":"只读"),3),f(u).isAdmin?(i(),o("button",{key:0,class:"btn ghost",type:"button",onClick:S}," 编辑大屏标题 ")):c("",!0),f(u).isAdmin?(i(),o("button",{key:1,class:"btn",type:"button",onClick:A}," 编辑采集频率 ")):c("",!0)])]),m.value?(i(),o("p",le,d(m.value),1)):c("",!0),a.value&&!h.value&&!k.value?(i(),o("p",se,d(a.value),1)):c("",!0),e("div",ae,[e("table",ne,[t[4]||(t[4]=e("thead",null,[e("tr",null,[e("th",null,"配置项"),e("th",null,"当前值"),e("th",null,"操作")])],-1)),e("tbody",null,[(i(!0),o(U,null,$(V.value,s=>(i(),o("tr",{key:s.key},[e("td",null,d(s.label),1),e("td",null,d(s.value),1),e("td",null,[s.editable&&f(u).isAdmin?(i(),o("button",{key:0,class:"btn ghost",type:"button",onClick:M=>I(s.edit)}," 编辑 ",8,oe)):(i(),o("span",ie,"—"))])]))),128))])])]),n.value?(i(),o("p",ue," 最近更新:"+d(n.value.updatedBy||"—")+" · "+d(new Date(n.value.updatedAt).toLocaleString("zh-CN",{hour12:!1})),1)):c("",!0)]),k.value?(i(),o("div",{key:0,class:"modal-mask",onClick:T(C,["self"])},[e("div",de,[e("div",{class:"panel-head"},[t[5]||(t[5]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"编辑大屏标题")],-1)),e("button",{class:"btn ghost",type:"button",onClick:C},"关闭")]),t[7]||(t[7]=e("p",{class:"desc"}," 保存后大屏顶栏标题立即更新(其他终端约数秒内同步)。最多 64 个字符。 ",-1)),e("div",ce,[e("div",re,[t[6]||(t[6]=e("label",null,"标题文案",-1)),G(e("input",{"onUpdate:modelValue":t[0]||(t[0]=s=>p.value=s),type:"text",maxlength:"64",placeholder:"分子实验室三维可视化管理平台",onKeydown:H(T(x,["prevent"]),["enter"])},null,40,ve),[[q,p.value]])])]),e("p",pe,d(p.value.trim().length)+" / 64",1),a.value?(i(),o("p",be,d(a.value),1)):c("",!0),e("div",me,[e("button",{class:"btn",type:"button",disabled:v.value,onClick:x},d(v.value?"保存中…":"保存并生效"),9,ye),e("button",{class:"btn ghost",type:"button",onClick:C},"取消")])])])):c("",!0),h.value?(i(),o("div",{key:1,class:"modal-mask",onClick:T(g,["self"])},[e("div",fe,[e("div",{class:"panel-head"},[t[8]||(t[8]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"编辑采集频率")],-1)),e("button",{class:"btn ghost",type:"button",onClick:g},"关闭")]),t[11]||(t[11]=e("p",{class:"desc"}," 控制服务端轮询周期,保存后立即生效。允许范围 0.5–600 秒。 ",-1)),e("div",_e,[(i(),o(U,null,$(L,s=>e("button",{key:s.ms,type:"button",class:D(["preset",{active:b.value===s.ms}]),onClick:M=>y(s.ms)},d(s.label),11,he)),64))]),e("div",ke,[e("div",ge,[t[9]||(t[9]=e("label",null,"周期(秒)",-1)),e("input",{value:_.value,type:"number",min:"0.5",max:"600",step:"0.5",onChange:t[1]||(t[1]=s=>R(Number(s.target.value)))},null,40,Ce)]),e("div",Me,[t[10]||(t[10]=e("label",null,"周期(毫秒)",-1)),e("input",{value:b.value,type:"number",min:"500",max:"600000",step:"100",onChange:t[2]||(t[2]=s=>y(Number(s.target.value)))},null,40,we)])]),a.value?(i(),o("p",Te,d(a.value),1)):c("",!0),e("div",Ee,[e("button",{class:"btn",type:"button",disabled:v.value,onClick:z},d(v.value?"保存中…":"保存并生效"),9,Ae),e("button",{class:"btn ghost",type:"button",onClick:g},"取消")])])])):c("",!0)]))}}),De=W(Se,[["__scopeId","data-v-64a5b5b8"]]);export{De as default};
.admin-list-page[data-v-ed6d7751]{min-height:0}.list-panel[data-v-ed6d7751]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.head-actions[data-v-ed6d7751]{display:flex;align-items:center;gap:10px}.table-wrap[data-v-ed6d7751]{flex:1;min-height:0;overflow:auto}.muted[data-v-ed6d7751]{color:var(--panel-muted)}.hint[data-v-ed6d7751]{margin-top:12px;font-size:12px;color:var(--panel-muted)}.msg.ok[data-v-ed6d7751]{color:var(--ok);font-size:13px;margin-bottom:8px}.msg.err[data-v-ed6d7751]{color:#ffb0b0;font-size:13px;margin:8px 0}.desc[data-v-ed6d7751]{margin:0 0 12px;font-size:12px;color:var(--panel-muted);line-height:1.6}.presets[data-v-ed6d7751]{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px}.preset[data-v-ed6d7751]{border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;color:var(--panel-muted);padding:6px 12px;font-size:12px;cursor:pointer;font-weight:600}.preset.active[data-v-ed6d7751]{background:#3dbeff38;color:#eaf4ff;border-color:#3dbeff8c}.poll-form[data-v-ed6d7751]{grid-template-columns:1fr 1fr}.modal-mask[data-v-ed6d7751]{position:fixed;top:0;right:0;bottom:0;left:0;background:#04080eb8;display:flex;align-items:center;justify-content:center;z-index:50}.modal[data-v-ed6d7751]{width:min(560px,92vw);max-height:90vh;overflow:auto}.modal-actions[data-v-ed6d7751]{margin-top:14px;display:flex;gap:10px}
import{d as c,j as u,c as l,b as s,t as a,s as o,O as i,o as p}from"./index-BssDqbym.js";const m={class:"page-fill"},_={class:"stub-box"},v=c({__name:"StubView",setup(d){const{t:e}=u(),t=i(),n=o(()=>t.name==="roam"?e("pages.roamTitle"):e("pages.stubTitle")),r=o(()=>t.name==="roam"?e("pages.roamDesc"):e("pages.stubDesc"));return(f,b)=>(p(),l("div",m,[s("div",_,[s("div",null,[s("h2",null,a(n.value),1),s("p",null,a(r.value),1)])])]))}});export{v as default};
import{d as c,c as l,b as e,t as s,B as o,o as i,K as u}from"./index-Bs_x-_cK.js";const r={class:"page-fill"},d={class:"stub-box"},v=c({__name:"StubView",setup(_){const t=u(),a=o(()=>String(t.meta.title||"功能页")),n=o(()=>String(t.meta.desc||"该模块骨架已就绪,待数据接口与交互深化。"));return(p,m)=>(i(),l("div",r,[e("div",d,[e("div",null,[e("h2",null,s(a.value),1),e("p",null,s(n.value),1)])])]))}});export{v as default};
import{d as S,u as $,l as M,c as i,b as e,t as o,f as r,F as U,x,w as L,e as g,v as _,P as A,r as u,R as D,p as k,o as d,_ as T}from"./index-BssDqbym.js";const B={class:"page-fill admin-list-page"},F={class:"panel list-panel"},O={class:"panel-head"},P={class:"panel-title"},J={key:0,class:"msg ok"},z={key:1,class:"msg err"},H={class:"table-wrap"},I={class:"table"},R={class:"ops"},j=["onClick"],q=["onClick"],G={key:0},K={class:"modal panel"},Q={class:"form-grid"},W={class:"field"},X={class:"field"},Y={class:"field"},Z={class:"field"},ee={key:0,class:"msg err"},te={class:"modal-actions"},se=["disabled"],le=S({__name:"UserManageView",setup(ae){const v=$(),c=u([]),a=u(""),p=u(""),m=u(!1),b=u(!1),l=D({username:"",displayName:"",password:"",role:"viewer"});function w(){l.username="",l.displayName="",l.password="",l.role="viewer",a.value=""}function h(){w(),m.value=!0}function f(){m.value=!1,a.value=""}async function y(){const n=await k("/api/users",{token:v.token});c.value=n.users}async function C(){a.value="",b.value=!0;try{await k("/api/users",{method:"POST",token:v.token,body:JSON.stringify(l)}),p.value=`已创建用户 ${l.username}`,f(),w(),await y()}catch(n){a.value=n instanceof Error?n.message:"创建失败"}finally{b.value=!1}}async function N(n){a.value="";try{await k(`/api/users/${n.id}`,{method:"PATCH",token:v.token,body:JSON.stringify({enabled:!n.enabled})}),await y()}catch(t){a.value=t instanceof Error?t.message:"更新失败"}}async function V(n){if(confirm(`确认删除用户 ${n.username}?`)){a.value="";try{await k(`/api/users/${n.id}`,{method:"DELETE",token:v.token}),p.value=`已删除 ${n.username}`,await y()}catch(t){a.value=t instanceof Error?t.message:"删除失败"}}}return M(y),(n,t)=>(d(),i("div",B,[e("section",F,[e("div",O,[e("div",P,[t[4]||(t[4]=e("div",{class:"vbar"},null,-1)),e("h3",null,"用户列表("+o(c.value.length)+")",1)]),e("div",{class:"head-actions"},[t[5]||(t[5]=e("div",{class:"badge"},"仅管理员",-1)),e("button",{class:"btn",type:"button",onClick:h},"新增用户")])]),p.value?(d(),i("p",J,o(p.value),1)):r("",!0),a.value&&!m.value?(d(),i("p",z,o(a.value),1)):r("",!0),e("div",H,[e("table",I,[t[7]||(t[7]=e("thead",null,[e("tr",null,[e("th",null,"用户名"),e("th",null,"显示名"),e("th",null,"角色"),e("th",null,"状态"),e("th",null,"最近登录"),e("th",null,"操作")])],-1)),e("tbody",null,[(d(!0),i(U,null,x(c.value,s=>(d(),i("tr",{key:s.id},[e("td",null,o(s.username),1),e("td",null,o(s.displayName),1),e("td",null,o(s.role==="admin"?"管理员":"只读"),1),e("td",null,o(s.enabled?"启用":"禁用"),1),e("td",null,o(s.lastLoginAt?new Date(s.lastLoginAt).toLocaleString("zh-CN"):"—"),1),e("td",R,[e("button",{class:"btn ghost",type:"button",onClick:E=>N(s)},o(s.enabled?"禁用":"启用"),9,j),e("button",{class:"btn danger",type:"button",onClick:E=>V(s)},"删除",8,q)])]))),128)),c.value.length?r("",!0):(d(),i("tr",G,[...t[6]||(t[6]=[e("td",{colspan:"6",class:"empty"},"暂无用户,点击右上角「新增用户」",-1)])]))])])])]),m.value?(d(),i("div",{key:0,class:"modal-mask",onClick:L(f,["self"])},[e("div",K,[e("div",{class:"panel-head"},[t[8]||(t[8]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增用户")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",Q,[e("div",W,[t[9]||(t[9]=e("label",null,"用户名",-1)),g(e("input",{"onUpdate:modelValue":t[0]||(t[0]=s=>l.username=s),autocomplete:"off"},null,512),[[_,l.username]])]),e("div",X,[t[10]||(t[10]=e("label",null,"显示名",-1)),g(e("input",{"onUpdate:modelValue":t[1]||(t[1]=s=>l.displayName=s)},null,512),[[_,l.displayName]])]),e("div",Y,[t[11]||(t[11]=e("label",null,"密码",-1)),g(e("input",{"onUpdate:modelValue":t[2]||(t[2]=s=>l.password=s),type:"password"},null,512),[[_,l.password]])]),e("div",Z,[t[13]||(t[13]=e("label",null,"角色",-1)),g(e("select",{"onUpdate:modelValue":t[3]||(t[3]=s=>l.role=s)},[...t[12]||(t[12]=[e("option",{value:"viewer"},"只读 (viewer)",-1),e("option",{value:"admin"},"管理员 (admin)",-1)])],512),[[A,l.role]])])]),a.value?(d(),i("p",ee,o(a.value),1)):r("",!0),e("div",te,[e("button",{class:"btn",type:"button",disabled:b.value,onClick:C},o(b.value?"创建中…":"创建"),9,se),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0)]))}}),oe=T(le,[["__scopeId","data-v-b2e28b89"]]);export{oe as default};
import{d as S,u as $,j as L,c as i,b as e,t as o,f as r,F as M,z as U,w as x,e as g,v as _,L as A,r as u,N as D,l as k,o as d,_ as T}from"./index-Bs_x-_cK.js";const B={class:"page-fill admin-list-page"},F={class:"panel list-panel"},O={class:"panel-head"},z={class:"panel-title"},J={key:0,class:"msg ok"},P={key:1,class:"msg err"},j={class:"table-wrap"},H={class:"table"},I={class:"ops"},q=["onClick"],G=["onClick"],K={key:0},Q={class:"modal panel"},R={class:"form-grid"},W={class:"field"},X={class:"field"},Y={class:"field"},Z={class:"field"},ee={key:0,class:"msg err"},te={class:"modal-actions"},se=["disabled"],le=S({__name:"UserManageView",setup(ae){const v=$(),c=u([]),a=u(""),p=u(""),m=u(!1),b=u(!1),l=D({username:"",displayName:"",password:"",role:"viewer"});function w(){l.username="",l.displayName="",l.password="",l.role="viewer",a.value=""}function h(){w(),m.value=!0}function f(){m.value=!1,a.value=""}async function y(){const n=await k("/api/users",{token:v.token});c.value=n.users}async function C(){a.value="",b.value=!0;try{await k("/api/users",{method:"POST",token:v.token,body:JSON.stringify(l)}),p.value=`已创建用户 ${l.username}`,f(),w(),await y()}catch(n){a.value=n instanceof Error?n.message:"创建失败"}finally{b.value=!1}}async function N(n){a.value="";try{await k(`/api/users/${n.id}`,{method:"PATCH",token:v.token,body:JSON.stringify({enabled:!n.enabled})}),await y()}catch(t){a.value=t instanceof Error?t.message:"更新失败"}}async function V(n){if(confirm(`确认删除用户 ${n.username}?`)){a.value="";try{await k(`/api/users/${n.id}`,{method:"DELETE",token:v.token}),p.value=`已删除 ${n.username}`,await y()}catch(t){a.value=t instanceof Error?t.message:"删除失败"}}}return L(y),(n,t)=>(d(),i("div",B,[e("section",F,[e("div",O,[e("div",z,[t[4]||(t[4]=e("div",{class:"vbar"},null,-1)),e("h3",null,"用户列表("+o(c.value.length)+")",1)]),e("div",{class:"head-actions"},[t[5]||(t[5]=e("div",{class:"badge"},"仅管理员",-1)),e("button",{class:"btn",type:"button",onClick:h},"新增用户")])]),p.value?(d(),i("p",J,o(p.value),1)):r("",!0),a.value&&!m.value?(d(),i("p",P,o(a.value),1)):r("",!0),e("div",j,[e("table",H,[t[7]||(t[7]=e("thead",null,[e("tr",null,[e("th",null,"用户名"),e("th",null,"显示名"),e("th",null,"角色"),e("th",null,"状态"),e("th",null,"最近登录"),e("th",null,"操作")])],-1)),e("tbody",null,[(d(!0),i(M,null,U(c.value,s=>(d(),i("tr",{key:s.id},[e("td",null,o(s.username),1),e("td",null,o(s.displayName),1),e("td",null,o(s.role==="admin"?"管理员":"只读"),1),e("td",null,o(s.enabled?"启用":"禁用"),1),e("td",null,o(s.lastLoginAt?new Date(s.lastLoginAt).toLocaleString("zh-CN"):"—"),1),e("td",I,[e("button",{class:"btn ghost",type:"button",onClick:E=>N(s)},o(s.enabled?"禁用":"启用"),9,q),e("button",{class:"btn danger",type:"button",onClick:E=>V(s)},"删除",8,G)])]))),128)),c.value.length?r("",!0):(d(),i("tr",K,[...t[6]||(t[6]=[e("td",{colspan:"6",class:"empty"},"暂无用户,点击右上角「新增用户」",-1)])]))])])])]),m.value?(d(),i("div",{key:0,class:"modal-mask",onClick:x(f,["self"])},[e("div",Q,[e("div",{class:"panel-head"},[t[8]||(t[8]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"新增用户")],-1)),e("button",{class:"btn ghost",type:"button",onClick:f},"关闭")]),e("div",R,[e("div",W,[t[9]||(t[9]=e("label",null,"用户名",-1)),g(e("input",{"onUpdate:modelValue":t[0]||(t[0]=s=>l.username=s),autocomplete:"off"},null,512),[[_,l.username]])]),e("div",X,[t[10]||(t[10]=e("label",null,"显示名",-1)),g(e("input",{"onUpdate:modelValue":t[1]||(t[1]=s=>l.displayName=s)},null,512),[[_,l.displayName]])]),e("div",Y,[t[11]||(t[11]=e("label",null,"密码",-1)),g(e("input",{"onUpdate:modelValue":t[2]||(t[2]=s=>l.password=s),type:"password"},null,512),[[_,l.password]])]),e("div",Z,[t[13]||(t[13]=e("label",null,"角色",-1)),g(e("select",{"onUpdate:modelValue":t[3]||(t[3]=s=>l.role=s)},[...t[12]||(t[12]=[e("option",{value:"viewer"},"只读 (viewer)",-1),e("option",{value:"admin"},"管理员 (admin)",-1)])],512),[[A,l.role]])])]),a.value?(d(),i("p",ee,o(a.value),1)):r("",!0),e("div",te,[e("button",{class:"btn",type:"button",disabled:b.value,onClick:C},o(b.value?"创建中…":"创建"),9,se),e("button",{class:"btn ghost",type:"button",onClick:f},"取消")])])])):r("",!0)]))}}),oe=T(le,[["__scopeId","data-v-b2e28b89"]]);export{oe as default};
.hist[data-v-12002b74]{min-height:200px;margin-bottom:10px;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.hist[data-v-12002b74] .echart-wrap{height:180px}.vav-page[data-v-12002b74]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.table-wrap[data-v-12002b74]{flex:1;min-height:0;overflow:auto}.vav-table[data-v-12002b74]{width:auto;max-width:100%;table-layout:auto;border-collapse:collapse;font-size:12px}.vav-table[data-v-12002b74] th,.vav-table th[data-v-12002b74],.vav-table td[data-v-12002b74]{padding:6px 10px;white-space:nowrap;width:1%}.vav-table .name[data-v-12002b74]{width:auto;max-width:160px;overflow:hidden;text-overflow:ellipsis}.vav-table .ops[data-v-12002b74]{display:flex;gap:6px;width:1%}.vav-table[data-v-12002b74] .btn.sm,.vav-table .btn.sm[data-v-12002b74]{padding:4px 10px;font-size:11px;line-height:1.2}.foot[data-v-12002b74]{margin-top:12px;flex:0 0 auto;font-size:12px;color:var(--label);line-height:1.7}
.hist[data-v-07c9907f]{min-height:200px;margin-bottom:10px;border:1px solid rgba(0,247,255,.16);border-radius:6px;padding:8px;background:#04102059}.hist[data-v-07c9907f] .echart-wrap{height:180px}.vav-page[data-v-07c9907f]{flex:1;min-height:0;display:flex;flex-direction:column;overflow:hidden}.table-wrap[data-v-07c9907f]{flex:1;min-height:0;overflow:auto}.vav-table[data-v-07c9907f]{width:auto;max-width:100%;table-layout:auto;border-collapse:collapse;font-size:12px}.vav-table[data-v-07c9907f] th,.vav-table th[data-v-07c9907f],.vav-table td[data-v-07c9907f]{padding:6px 10px;white-space:nowrap;width:1%}.vav-table .name[data-v-07c9907f]{width:auto;max-width:160px;overflow:hidden;text-overflow:ellipsis}.vav-table .ops[data-v-07c9907f]{display:flex;gap:6px;width:1%}.vav-table[data-v-07c9907f] .btn.sm,.vav-table .btn.sm[data-v-07c9907f]{padding:4px 10px;font-size:11px;line-height:1.2}.foot[data-v-07c9907f]{margin-top:12px;flex:0 0 auto;font-size:12px;color:var(--label);line-height:1.7}
import{d as w,j as A,u as V,c,b as e,t as s,h as a,H as k,F as C,x as E,s as d,p as F,o as m,_ as O}from"./index-BssDqbym.js";import{u as S}from"./realtime-lmP-Cubp.js";import{E as H,m as M}from"./historyChart-DJ1B6lTP.js";import{u}from"./useMetricHistory-CLFOMuUx.js";const N={class:"page-fill"},B={class:"panel vav-page"},L={class:"panel-head"},T={class:"panel-title"},D={class:"badge"},I={class:"hist"},R={class:"table-wrap"},$={class:"table vav-table"},j={class:"name"},J={class:"ops"},P=["disabled","onClick"],q=["disabled","onClick"],z={class:"foot"},G=w({__name:"VavView",setup(K){const{t}=A(),l=V(),p=S(),{series:v,loading:h}=u(()=>({source:"vav",metric:"airflow"})),{series:_,loading:g}=u(()=>({source:"vav",metric:"face_velocity"})),f=d(()=>M([...v.value.map(o=>({...o,name:t("pages.seriesAirflow",{name:o.name||o.id})})),..._.value.map(o=>({...o,name:t("pages.seriesFaceVel",{name:o.name||o.id})}))],{maxSeries:8})),b=d(()=>h.value||g.value);async function r(o,i){l.isAdmin&&(await F("/api/realtime/write",{method:"POST",token:l.token,body:JSON.stringify({target:o,action:i?"start":"stop"})}),alert(t(i?"pages.vavCmdOn":"pages.vavCmdOff")))}function x(o){return o.maxExhaust?t("metrics.maxExhaust"):o.minAirflow?t("metrics.minAirflow"):t("pages.vavModeNormal")}return(o,i)=>(m(),c("div",N,[e("section",B,[e("div",L,[e("div",T,[i[0]||(i[0]=e("div",{class:"vbar"},null,-1)),e("h3",null,s(a(t)("pages.vavTitle")),1)]),e("div",D,s(a(l).isAdmin?a(t)("common.controllable"):a(t)("common.readonly"))+" · "+s(a(t)("common.last24h")),1)]),e("div",I,[k(H,{option:f.value,loading:b.value,"empty-text":a(t)("pages.vavEmpty")},null,8,["option","loading","empty-text"])]),e("div",R,[e("table",$,[e("thead",null,[e("tr",null,[e("th",null,s(a(t)("common.device")),1),e("th",null,s(a(t)("pages.vavRunState")),1),e("th",null,s(a(t)("pages.vavFaceVel")),1),e("th",null,s(a(t)("pages.vavDoorH")),1),e("th",null,s(a(t)("pages.vavAirflow")),1),e("th",null,s(a(t)("pages.vavValve")),1),e("th",null,s(a(t)("pages.vavMaxEx")),1),e("th",null,s(a(t)("pages.vavMinAf")),1),e("th",null,s(a(t)("pages.vavExMode")),1),e("th",null,s(a(t)("pages.vavAlarm")),1),e("th",null,s(a(t)("common.action")),1)])]),e("tbody",null,[(m(!0),c(C,null,E(a(p).snapshot.vav,n=>(m(),c("tr",{key:n.id},[e("td",j,s(n.name),1),e("td",null,s(n.running?a(t)("screen.running"):a(t)("screen.stopped")),1),e("td",null,s(n.faceVelocity.toFixed(3))+" m/s",1),e("td",null,s(n.sashHeight)+" mm",1),e("td",null,s(n.airflow)+" m³/h",1),e("td",null,s(n.valveOpen)+" %",1),e("td",null,s(n.maxExhaust?a(t)("common.yes"):a(t)("common.no")),1),e("td",null,s(n.minAirflow?a(t)("common.yes"):a(t)("common.no")),1),e("td",null,s(x(n)),1),e("td",null,s(n.alarmCode||a(t)("common.none")),1),e("td",J,[e("button",{class:"btn sm",disabled:!a(l).isAdmin,onClick:y=>r(n.id,!0)},s(a(t)("common.start")),9,P),e("button",{class:"btn ghost sm",disabled:!a(l).isAdmin,onClick:y=>r(n.id,!1)},s(a(t)("common.stop")),9,q)])]))),128))])])]),e("p",z,s(a(t)("pages.vavFoot")),1)])]))}}),Y=O(G,[["__scopeId","data-v-12002b74"]]);export{Y as default};
import{d as V,u as k,c as i,b as t,t as l,h as o,D as y,F as w,z as A,B as u,o as d,l as C,_ as S}from"./index-Bs_x-_cK.js";import{u as E}from"./realtime-CI_KLy_N.js";import{E as O,m as B}from"./historyChart-DTdcyadg.js";import{u as c}from"./useMetricHistory-Ck1zYYEr.js";const F={class:"page-fill"},$={class:"panel vav-page"},H={class:"panel-head"},L={class:"badge"},M={class:"hist"},N={class:"table-wrap"},D={class:"table vav-table"},T={class:"name"},z={class:"ops"},I=["disabled","onClick"],J=["disabled","onClick"],P=V({__name:"VavView",setup(R){const n=k(),m=E(),{series:h,loading:p}=c(()=>({source:"vav",metric:"airflow"})),{series:_,loading:f}=c(()=>({source:"vav",metric:"face_velocity"})),v=u(()=>B([...h.value.map(e=>({...e,name:`${e.name||e.id}·风量`})),..._.value.map(e=>({...e,name:`${e.name||e.id}·面风速`}))],{maxSeries:8})),b=u(()=>p.value||f.value);async function r(e,a){n.isAdmin&&(await C("/api/realtime/write",{method:"POST",token:n.token,body:JSON.stringify({target:e,action:a?"start":"stop"})}),alert(a?"开机指令已下发(Mock)":"关机指令已下发(Mock)"))}function g(e){return e.maxExhaust?"最大排风":e.minAirflow?"最小风量":"常态"}return(e,a)=>(d(),i("div",F,[t("section",$,[t("div",H,[a[0]||(a[0]=t("div",{class:"panel-title"},[t("div",{class:"vbar"}),t("h3",null,"通风柜 VAV 集中监控")],-1)),t("div",L,l(o(n).isAdmin?"可控制":"只读")+" · 近24h曲线",1)]),t("div",M,[y(O,{option:v.value,loading:b.value,"empty-text":"VAV 历史积累中"},null,8,["option","loading"])]),t("div",N,[t("table",D,[a[1]||(a[1]=t("thead",null,[t("tr",null,[t("th",null,"设备"),t("th",null,"开停状态"),t("th",null,"实际面风速"),t("th",null,"实际门高"),t("th",null,"实际风量"),t("th",null,"阀开度"),t("th",null,"最大排风"),t("th",null,"最小风量"),t("th",null,"排风模式"),t("th",null,"报警代码"),t("th",null,"操作")])],-1)),t("tbody",null,[(d(!0),i(w,null,A(o(m).snapshot.vav,s=>(d(),i("tr",{key:s.id},[t("td",T,l(s.name),1),t("td",null,l(s.running?"运行":"停止"),1),t("td",null,l(s.faceVelocity.toFixed(3))+" m/s",1),t("td",null,l(s.sashHeight)+" mm",1),t("td",null,l(s.airflow)+" m³/h",1),t("td",null,l(s.valveOpen)+" %",1),t("td",null,l(s.maxExhaust?"是":"否"),1),t("td",null,l(s.minAirflow?"是":"否"),1),t("td",null,l(g(s)),1),t("td",null,l(s.alarmCode||"无"),1),t("td",z,[t("button",{class:"btn sm",disabled:!o(n).isAdmin,onClick:x=>r(s.id,!0)},"开机",8,I),t("button",{class:"btn ghost sm",disabled:!o(n).isAdmin,onClick:x=>r(s.id,!1)},"关机",8,J)])]))),128))])])]),a[2]||(a[2]=t("p",{class:"foot"}," 点位来源:文库制备1/2通风柜(开停、面风速×0.001、门高、风量、最大/最小风量、报警代码)。阀开度按报价清单监控项展示。 ",-1))])]))}}),Q=S(P,[["__scopeId","data-v-07c9907f"]]);export{Q as default};
import{d as J,u as j,j as q,c as d,b as e,n as y,t as o,f as b,F as S,h as p,e as m,v as c,L as U,z as D,M as G,x as Q,g as R,r as k,N as I,B as E,l as w,o as a,_ as X}from"./index-Bs_x-_cK.js";import{W as Y}from"./WebRtcPlayer-AsPwoXXX.js";const Z={class:"page-fill video-page"},ee={class:"video-tabs"},se={class:"badge"},te=["disabled"],le={key:0,class:"msg"},ne={key:0,class:"panel"},oe={class:"form-grid three"},ie={class:"field"},ae={class:"field"},de={class:"field"},ue={class:"field"},re={class:"field"},ve={class:"field"},pe={class:"panel list-panel"},me={class:"table-wrap"},be={class:"table"},ce={class:"ops"},fe=["onClick"],ye=["onClick"],ke=["onClick"],ge={key:0},we={key:1,class:"panel config-panel"},he={class:"panel-head"},_e={class:"head-right"},Ce={class:"form-grid three"},Te={class:"field"},Ae=["disabled"],Ve={class:"field"},Pe=["disabled"],Se={class:"field"},Ne=["disabled"],Me={class:"field"},Ue=["disabled"],Re={class:"field"},Ee=["disabled"],$e={class:"field"},xe=["disabled"],De={class:"field"},Ie=["disabled"],He={class:"field"},Le=["disabled"],Be={class:"field switch-field"},Oe={class:"switch"},We=["disabled"],Ke={class:"row-actions"},ze=["disabled"],Fe={key:2,class:"msg"},Je={key:3,class:"hint"},je={key:2,class:"preview-layout"},qe={class:"panel preview-main"},Ge={class:"panel-head"},Qe={class:"panel-title"},Xe={key:1,class:"stage-body"},Ye={key:2,class:"cam-meta bar"},Ze={class:"panel preview-side"},es={class:"thumb-grid"},ss=["onClick"],ts={class:"thumb-top"},ls={class:"ch"},ns={class:"thumb-name"},os={class:"thumb-loc"},is=J({__name:"VideoView",setup(as){const i=j(),f=k("devices"),N=k(!1),v=k(""),h=k([]),C=k(null),g=k(""),P=k(!1),_=k(""),u=I({name:"",channel:7,location:"",deviceType:"nvr-ch",ip:"",remark:""}),l=I({host:"",port:8e3,rtspPort:554,username:"",password:"",protocol:"sdk",streamType:"sub",previewTimeoutMs:8e3,enabled:!0}),M={online:"在线",offline:"离线",alarm:"报警"},H={ipc:"海康网络摄像机","nvr-ch":"海康 NVR 通道"},L=E(()=>h.value.filter(n=>n.enabled&&n.status==="online").length),T=E(()=>h.value.filter(n=>n.enabled)),r=E(()=>T.value.find(n=>n.id===g.value)||T.value[0]||null);async function A(){N.value=!0,v.value="";try{const[n,s]=await Promise.all([w("/api/video/devices",{token:i.token}),w("/api/video/config",{token:i.token})]);h.value=n.devices,C.value=s,l.host=s.host,l.port=s.port,l.rtspPort=s.rtspPort??554,l.username=s.username,l.password=s.passwordMasked||"",l.protocol=s.protocol==="tcp"?"isapi":s.protocol,l.streamType=s.streamType,l.previewTimeoutMs=s.previewTimeoutMs,l.enabled=s.enabled,!g.value&&T.value[0]&&(g.value=T.value[0].id)}catch(n){v.value=n instanceof Error?n.message:"加载失败"}finally{N.value=!1}}async function B(){if(i.isAdmin){v.value="";try{await w("/api/video/devices",{method:"POST",token:i.token,body:JSON.stringify(u)}),u.name="",u.location="",u.ip="",u.remark="",u.channel+=1,v.value="设备已添加",await A()}catch(n){v.value=n instanceof Error?n.message:"添加失败"}}}async function O(n){if(i.isAdmin){v.value="";try{await w(`/api/video/devices/${n.id}`,{method:"PATCH",token:i.token,body:JSON.stringify({enabled:!n.enabled})}),await A()}catch(s){v.value=s instanceof Error?s.message:"更新失败"}}}async function W(n){if(i.isAdmin&&confirm(`确认删除设备「${n.name}」?`)){v.value="";try{await w(`/api/video/devices/${n.id}`,{method:"DELETE",token:i.token}),g.value===n.id&&(g.value=""),v.value="已删除",await A()}catch(s){v.value=s instanceof Error?s.message:"删除失败"}}}async function K(){if(i.isAdmin){v.value="",_.value="";try{const n={host:l.host,port:l.port,rtspPort:l.rtspPort,username:l.username,protocol:l.protocol,streamType:l.streamType,previewTimeoutMs:l.previewTimeoutMs,enabled:l.enabled};l.password&&l.password!=="********"&&(n.password=l.password);const s=await w("/api/video/config",{method:"PUT",token:i.token,body:JSON.stringify(n)});C.value=s,l.password=s.passwordMasked||"",v.value="通信配置已保存"}catch(n){v.value=n instanceof Error?n.message:"保存失败"}}}async function z(){if(i.isAdmin){P.value=!0,_.value="";try{const n=await w("/api/video/config/test",{method:"POST",token:i.token});_.value=`${n.message} · ${n.latencyMs} ms`,v.value=n.ok?"连通性测试通过":n.message}catch(n){_.value=n instanceof Error?n.message:"测试失败"}finally{P.value=!1}}}function F(n){g.value=n.id,f.value="preview"}function $(n){return new Date(n).toLocaleString("zh-CN",{hour12:!1})}return q(A),(n,s)=>{var x;return a(),d("div",Z,[e("div",ee,[e("button",{type:"button",class:y(["tab",{active:f.value==="devices"}]),onClick:s[0]||(s[0]=t=>f.value="devices")}," 设备管理 ",2),e("button",{type:"button",class:y(["tab",{active:f.value==="config"}]),onClick:s[1]||(s[1]=t=>f.value="config")}," 通信配置 ",2),e("button",{type:"button",class:y(["tab",{active:f.value==="preview"}]),onClick:s[2]||(s[2]=t=>f.value="preview")}," 查看监控 ",2),s[18]||(s[18]=e("div",{class:"tab-spacer"},null,-1)),s[19]||(s[19]=e("div",{class:"badge"},"海康威视",-1)),e("div",se,"在线 "+o(L.value)+" / "+o(h.value.length),1),e("button",{type:"button",class:"btn ghost",disabled:N.value,onClick:A},"刷新",8,te),v.value?(a(),d("span",le,o(v.value),1)):b("",!0)]),f.value==="devices"?(a(),d(S,{key:0},[p(i).isAdmin?(a(),d("section",ne,[s[27]||(s[27]=e("div",{class:"panel-head"},[e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"添加海康监控设备")]),e("div",{class:"badge"},"管理员")],-1)),e("div",oe,[e("div",ie,[s[20]||(s[20]=e("label",null,"名称",-1)),m(e("input",{"onUpdate:modelValue":s[3]||(s[3]=t=>u.name=t),placeholder:"如:走廊东"},null,512),[[c,u.name]])]),e("div",ae,[s[21]||(s[21]=e("label",null,"NVR 通道号",-1)),m(e("input",{"onUpdate:modelValue":s[4]||(s[4]=t=>u.channel=t),type:"number",min:"1",max:"256"},null,512),[[c,u.channel,void 0,{number:!0}]])]),e("div",de,[s[22]||(s[22]=e("label",null,"安装位置",-1)),m(e("input",{"onUpdate:modelValue":s[5]||(s[5]=t=>u.location=t),placeholder:"楼层/区域"},null,512),[[c,u.location]])]),e("div",ue,[s[24]||(s[24]=e("label",null,"类型",-1)),m(e("select",{"onUpdate:modelValue":s[6]||(s[6]=t=>u.deviceType=t)},[...s[23]||(s[23]=[e("option",{value:"nvr-ch"},"海康 NVR 通道",-1),e("option",{value:"ipc"},"海康网络摄像机",-1)])],512),[[U,u.deviceType]])]),e("div",re,[s[25]||(s[25]=e("label",null,"摄像机 IP(可选)",-1)),m(e("input",{"onUpdate:modelValue":s[7]||(s[7]=t=>u.ip=t),placeholder:"IPC 直连时填写"},null,512),[[c,u.ip]])]),e("div",ve,[s[26]||(s[26]=e("label",null,"备注",-1)),m(e("input",{"onUpdate:modelValue":s[8]||(s[8]=t=>u.remark=t)},null,512),[[c,u.remark]])])]),e("div",{class:"row-actions"},[e("button",{type:"button",class:"btn",onClick:B},"添加")])])):b("",!0),e("section",pe,[s[30]||(s[30]=e("div",{class:"panel-head"},[e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"海康监控设备列表")]),e("div",{class:"badge amber"},"Hikvision NVR")],-1)),e("div",me,[e("table",be,[s[29]||(s[29]=e("thead",null,[e("tr",null,[e("th",null,"通道"),e("th",null,"名称"),e("th",null,"位置"),e("th",null,"类型"),e("th",null,"IP"),e("th",null,"状态"),e("th",null,"启用"),e("th",null,"更新时间"),e("th",null,"操作")])],-1)),e("tbody",null,[(a(!0),d(S,null,D(h.value,t=>(a(),d("tr",{key:t.id},[e("td",null,o(t.channel),1),e("td",null,o(t.name),1),e("td",null,o(t.location),1),e("td",null,o(H[t.deviceType]),1),e("td",null,o(t.ip||"—"),1),e("td",null,[e("span",{class:y(["st",t.status])},o(M[t.status]),3)]),e("td",null,o(t.enabled?"是":"否"),1),e("td",null,o($(t.updatedAt)),1),e("td",ce,[e("button",{type:"button",class:"btn ghost",onClick:V=>F(t)},"查看",8,fe),p(i).isAdmin?(a(),d("button",{key:0,type:"button",class:"btn ghost",onClick:V=>O(t)},o(t.enabled?"禁用":"启用"),9,ye)):b("",!0),p(i).isAdmin?(a(),d("button",{key:1,type:"button",class:"btn danger",onClick:V=>W(t)}," 删除 ",8,ke)):b("",!0)])]))),128)),h.value.length?b("",!0):(a(),d("tr",ge,[...s[28]||(s[28]=[e("td",{colspan:"9",class:"empty"},"暂无设备,请先添加或检查通信配置",-1)])]))])])])])],64)):f.value==="config"?(a(),d("section",we,[e("div",he,[s[32]||(s[32]=e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"海康通信配置")],-1)),e("div",_e,[s[31]||(s[31]=e("div",{class:"badge"},"厂商:海康威视",-1)),e("div",{class:y(["badge",p(i).isAdmin?"":"amber"])},o(p(i).isAdmin?"可编辑":"只读"),3)])]),s[44]||(s[44]=e("p",{class:"hint"}," 对接海康威视 NVR / 摄像机。推荐 HCNetSDK(设备端口 8000)预览;RTSP(554)或 ISAPI 作备选。 一期保存配置并 Mock 登录测试;二期经 Windows HCNetSDK 桥接拉取实况(与门禁桥接同类)。 ",-1)),e("div",Ce,[e("div",Te,[s[33]||(s[33]=e("label",null,"海康 NVR IP",-1)),m(e("input",{"onUpdate:modelValue":s[9]||(s[9]=t=>l.host=t),disabled:!p(i).isAdmin,placeholder:"192.168.x.x"},null,8,Ae),[[c,l.host]])]),e("div",Ve,[s[34]||(s[34]=e("label",null,"设备端口(SDK)",-1)),m(e("input",{"onUpdate:modelValue":s[10]||(s[10]=t=>l.port=t),type:"number",disabled:!p(i).isAdmin},null,8,Pe),[[c,l.port,void 0,{number:!0}]])]),e("div",Se,[s[35]||(s[35]=e("label",null,"RTSP 端口",-1)),m(e("input",{"onUpdate:modelValue":s[11]||(s[11]=t=>l.rtspPort=t),type:"number",disabled:!p(i).isAdmin},null,8,Ne),[[c,l.rtspPort,void 0,{number:!0}]])]),e("div",Me,[s[37]||(s[37]=e("label",null,"接入方式",-1)),m(e("select",{"onUpdate:modelValue":s[12]||(s[12]=t=>l.protocol=t),disabled:!p(i).isAdmin},[...s[36]||(s[36]=[e("option",{value:"sdk"},"HCNetSDK(推荐)",-1),e("option",{value:"rtsp"},"RTSP",-1),e("option",{value:"isapi"},"ISAPI",-1)])],8,Ue),[[U,l.protocol]])]),e("div",Re,[s[38]||(s[38]=e("label",null,"设备用户名",-1)),m(e("input",{"onUpdate:modelValue":s[13]||(s[13]=t=>l.username=t),disabled:!p(i).isAdmin},null,8,Ee),[[c,l.username]])]),e("div",$e,[s[39]||(s[39]=e("label",null,"设备密码",-1)),m(e("input",{"onUpdate:modelValue":s[14]||(s[14]=t=>l.password=t),type:"password",disabled:!p(i).isAdmin,placeholder:"********",autocomplete:"new-password"},null,8,xe),[[c,l.password]])]),e("div",De,[s[41]||(s[41]=e("label",null,"预览码流",-1)),m(e("select",{"onUpdate:modelValue":s[15]||(s[15]=t=>l.streamType=t),disabled:!p(i).isAdmin},[...s[40]||(s[40]=[e("option",{value:"sub"},"子码流(推荐)",-1),e("option",{value:"main"},"主码流",-1)])],8,Ie),[[U,l.streamType]])]),e("div",He,[s[42]||(s[42]=e("label",null,"预览超时 (ms)",-1)),m(e("input",{"onUpdate:modelValue":s[16]||(s[16]=t=>l.previewTimeoutMs=t),type:"number",disabled:!p(i).isAdmin},null,8,Le),[[c,l.previewTimeoutMs,void 0,{number:!0}]])]),e("div",Be,[s[43]||(s[43]=e("label",null,"启用海康通信",-1)),e("label",Oe,[m(e("input",{"onUpdate:modelValue":s[17]||(s[17]=t=>l.enabled=t),type:"checkbox",disabled:!p(i).isAdmin},null,8,We),[[G,l.enabled]]),e("span",null,o(l.enabled?"已启用":"已关闭"),1)])])]),e("div",Ke,[p(i).isAdmin?(a(),d("button",{key:0,type:"button",class:"btn",onClick:K},"保存配置")):b("",!0),p(i).isAdmin?(a(),d("button",{key:1,type:"button",class:"btn ghost",disabled:P.value,onClick:z},o(P.value?"测试中…":"测试连通性"),9,ze)):b("",!0),_.value?(a(),d("span",Fe,o(_.value),1)):b("",!0),C.value?(a(),d("span",Je," 最近更新:"+o($(C.value.updatedAt))+" · "+o(C.value.updatedBy),1)):b("",!0)])])):(a(),d("div",je,[e("section",qe,[e("div",Ge,[e("div",Qe,[s[45]||(s[45]=e("div",{class:"vbar"},null,-1)),e("h3",null,o(r.value?r.value.name:"未选择通道"),1)]),r.value?(a(),d("div",{key:0,class:y(["badge",r.value.status==="online"?"":"amber"])}," CH"+o(r.value.channel)+" · "+o(M[r.value.status]),3)):b("",!0)]),e("div",{class:y(["stage webrtc-stage",((x=r.value)==null?void 0:x.status)||"offline"])},[r.value?(a(),Q(Y,{key:r.value.id,"device-id":r.value.id},null,8,["device-id"])):(a(),d("div",Xe,[...s[46]||(s[46]=[e("div",{class:"cam-title"},"无可用通道",-1),e("p",{class:"cam-note"},"请先在设备管理中启用海康监控通道。",-1)])])),r.value?(a(),d("div",Ye,[R(o(r.value.name)+" · "+o(r.value.location)+" · CH"+o(r.value.channel)+" ",1),r.value.ip?(a(),d(S,{key:0},[R(" · "+o(r.value.ip),1)],64)):b("",!0),s[47]||(s[47]=R(" · WebRTC / WHEP ",-1))])):b("",!0)],2)]),e("section",Ze,[s[48]||(s[48]=e("div",{class:"panel-head"},[e("div",{class:"panel-title"},[e("div",{class:"vbar"}),e("h3",null,"通道列表")])],-1)),e("div",es,[(a(!0),d(S,null,D(T.value,t=>{var V;return a(),d("button",{key:t.id,type:"button",class:y(["thumb",[{active:((V=r.value)==null?void 0:V.id)===t.id},t.status]]),onClick:ds=>g.value=t.id},[e("div",ts,[e("span",ls,"CH"+o(t.channel),1),e("span",{class:y(["st",t.status])},o(M[t.status]),3)]),e("div",ns,o(t.name),1),e("div",os,o(t.location),1)],10,ss)}),128))])])]))])}}}),vs=X(is,[["__scopeId","data-v-36429526"]]);export{vs as default};
import{d as B,u as j,k as X,C as Y,c as v,n as A,b as e,F as U,g as x,t as i,r as w,o as u,_ as J,j as Z,l as ee,h as s,f as y,e as h,v as k,P as L,x as H,Q as te,D as se,R as F,s as R,p as S}from"./index-BssDqbym.js";import{f as oe}from"./t-ChxyHC3f.js";const ie={key:0,class:"overlay"},le={class:"sub"},ne={key:1,class:"live-tag"},ae=B({__name:"WebRtcPlayer",props:{deviceId:{},whepPath:{}},setup(N,{expose:t}){const d=N,_=j(),T=w(null),c=w("idle"),g=w("");let r=null,f=null;async function V(){try{f&&_.token&&await fetch(f,{method:"DELETE",headers:{Authorization:`Bearer ${_.token}`}}).catch(()=>{})}finally{f=null,r==null||r.close(),r=null,T.value&&(T.value.srcObject=null),c.value="idle"}}async function C(){var n;if(await V(),!!d.deviceId){c.value="connecting",g.value="",r=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]}),r.addTransceiver("video",{direction:"recvonly"}),r.addTransceiver("audio",{direction:"recvonly"}),r.ontrack=b=>{T.value&&(T.value.srcObject=b.streams[0]||new MediaStream([b.track]),T.value.play().catch(()=>{}),c.value="playing")},r.onconnectionstatechange=()=>{r&&(r.connectionState==="failed"||r.connectionState==="disconnected")&&(c.value="error",g.value="WebRTC 连接中断")};try{const b=await r.createOffer();await r.setLocalDescription(b),await m(r);const I=d.whepPath||`/api/video/devices/${encodeURIComponent(d.deviceId)}/whep`,$=await fetch(I,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp",Authorization:`Bearer ${_.token}`},body:((n=r.localDescription)==null?void 0:n.sdp)||b.sdp||""}),P=$.headers.get("Location");P&&(f=(P.startsWith("http"),P));const p=await $.text();if(!$.ok){let E=p||`WHEP HTTP ${$.status}`;try{const D=JSON.parse(p);D.message&&(E=D.message)}catch{}throw new Error(E)}await r.setRemoteDescription({type:"answer",sdp:p})}catch(b){c.value="error",g.value=b instanceof Error?b.message:"WebRTC 启动失败",await V(),c.value="error"}}}function m(n){return n.iceGatheringState==="complete"?Promise.resolve():new Promise(b=>{const I=window.setTimeout(()=>b(),2e3);n.onicegatheringstatechange=()=>{n.iceGatheringState==="complete"&&(window.clearTimeout(I),b())}})}return X(()=>d.deviceId,()=>{C()},{immediate:!0}),Y(()=>{V()}),t({restart:C,stop:V}),(n,b)=>(u(),v("div",{class:A(["webrtc-player",c.value])},[e("video",{ref_key:"videoEl",ref:T,class:"video",autoplay:"",playsinline:"",muted:""},null,512),c.value!=="playing"?(u(),v("div",ie,[c.value==="connecting"?(u(),v(U,{key:0},[x("正在建立 WebRTC…")],64)):c.value==="error"?(u(),v(U,{key:1},[b[0]||(b[0]=e("div",null,"WebRTC 未就绪",-1)),e("div",le,i(g.value),1),e("button",{type:"button",class:"btn",onClick:C},"重试")],64)):(u(),v(U,{key:2},[x("空闲")],64))])):(u(),v("div",ne,[...b[1]||(b[1]=[e("i",null,null,-1),e("span",null,"WebRTC · LIVE",-1)])]))],2))}}),de=J(ae,[["__scopeId","data-v-a83be64f"]]),ue={class:"page-fill video-page"},ce={class:"video-tabs"},ve={class:"badge"},re={class:"badge"},pe=["disabled"],me={key:0,class:"msg"},be={key:0,class:"panel"},he={class:"panel-head"},_e={class:"panel-title"},fe={class:"badge"},ye={class:"form-grid three"},ge={class:"field"},ke=["placeholder"],we={class:"field"},Te={class:"field"},Ce=["placeholder"],Pe={class:"field"},Ae={value:"nvr-ch"},Ve={value:"ipc"},Ee={class:"field"},Se=["placeholder"],Ue={class:"field"},$e={class:"row-actions"},Ie={class:"panel list-panel"},Me={class:"panel-head"},Re={class:"panel-title"},xe={class:"table-wrap"},De={class:"table"},Le={class:"ops"},Ne=["onClick"],Oe=["onClick"],We=["onClick"],He={key:0},Fe={colspan:"9",class:"empty"},Be={key:1,class:"panel config-panel"},je={class:"panel-head"},Je={class:"panel-title"},ze={class:"head-right"},Ge={class:"badge"},Qe={class:"hint"},qe={class:"form-grid three"},Ke={class:"field"},Xe=["disabled"],Ye={class:"field"},Ze=["disabled"],et={class:"field"},tt=["disabled"],st={class:"field"},ot=["disabled"],it={value:"sdk"},lt={class:"field"},nt=["disabled"],at={class:"field"},dt=["disabled"],ut={class:"field"},ct=["disabled"],vt={value:"sub"},rt={value:"main"},pt={class:"field"},mt=["disabled"],bt={class:"field switch-field"},ht={class:"switch"},_t=["disabled"],ft={class:"row-actions"},yt=["disabled"],gt={key:2,class:"msg"},kt={key:3,class:"hint"},wt={key:2,class:"preview-layout"},Tt={class:"panel preview-main"},Ct={class:"panel-head"},Pt={class:"panel-title"},At={key:1,class:"stage-body"},Vt={class:"cam-title"},Et={class:"cam-note"},St={key:2,class:"cam-meta bar"},Ut={class:"panel preview-side"},$t={class:"panel-head"},It={class:"panel-title"},Mt={class:"thumb-grid"},Rt=["onClick"],xt={class:"thumb-top"},Dt={class:"ch"},Lt={class:"thumb-name"},Nt={class:"thumb-loc"},Ot=B({__name:"VideoView",setup(N){const{t}=Z(),d=j(),_=w("devices"),T=w(!1),c=w(""),g=w([]),r=w(null),f=w(""),V=w(!1),C=w(""),m=F({name:"",channel:7,location:"",deviceType:"nvr-ch",ip:"",remark:""}),n=F({host:"",port:8e3,rtspPort:554,username:"",password:"",protocol:"sdk",streamType:"sub",previewTimeoutMs:8e3,enabled:!0}),b=R(()=>({online:t("status.online"),offline:t("status.offline"),alarm:t("status.alarm")})),I=R(()=>({ipc:t("video.typeIpc"),"nvr-ch":t("video.typeNvr")})),$=R(()=>g.value.filter(a=>a.enabled&&a.status==="online").length),P=R(()=>g.value.filter(a=>a.enabled)),p=R(()=>P.value.find(a=>a.id===f.value)||P.value[0]||null);async function E(){T.value=!0,c.value="";try{const[a,o]=await Promise.all([S("/api/video/devices",{token:d.token}),S("/api/video/config",{token:d.token})]);g.value=a.devices,r.value=o,n.host=o.host,n.port=o.port,n.rtspPort=o.rtspPort??554,n.username=o.username,n.password=o.passwordMasked||"",n.protocol=o.protocol==="tcp"?"isapi":o.protocol,n.streamType=o.streamType,n.previewTimeoutMs=o.previewTimeoutMs,n.enabled=o.enabled,!f.value&&P.value[0]&&(f.value=P.value[0].id)}catch(a){c.value=a instanceof Error?a.message:t("video.loadFail")}finally{T.value=!1}}async function D(){if(d.isAdmin){c.value="";try{await S("/api/video/devices",{method:"POST",token:d.token,body:JSON.stringify(m)}),m.name="",m.location="",m.ip="",m.remark="",m.channel+=1,c.value=t("video.added"),await E()}catch(a){c.value=a instanceof Error?a.message:t("video.addFail")}}}async function z(a){if(d.isAdmin){c.value="";try{await S(`/api/video/devices/${a.id}`,{method:"PATCH",token:d.token,body:JSON.stringify({enabled:!a.enabled})}),await E()}catch(o){c.value=o instanceof Error?o.message:t("video.updateFail")}}}async function G(a){if(d.isAdmin&&confirm(t("video.confirmDelete",{name:a.name}))){c.value="";try{await S(`/api/video/devices/${a.id}`,{method:"DELETE",token:d.token}),f.value===a.id&&(f.value=""),c.value=t("video.deleted"),await E()}catch(o){c.value=o instanceof Error?o.message:t("video.deleteFail")}}}async function Q(){if(d.isAdmin){c.value="",C.value="";try{const a={host:n.host,port:n.port,rtspPort:n.rtspPort,username:n.username,protocol:n.protocol,streamType:n.streamType,previewTimeoutMs:n.previewTimeoutMs,enabled:n.enabled};n.password&&n.password!=="********"&&(a.password=n.password);const o=await S("/api/video/config",{method:"PUT",token:d.token,body:JSON.stringify(a)});r.value=o,n.password=o.passwordMasked||"",c.value=t("video.saved")}catch(a){c.value=a instanceof Error?a.message:t("video.saveFail")}}}async function q(){if(d.isAdmin){V.value=!0,C.value="";try{const a=await S("/api/video/config/test",{method:"POST",token:d.token});C.value=`${a.message} · ${a.latencyMs} ms`,c.value=a.ok?t("video.testOk"):a.message}catch(a){C.value=a instanceof Error?a.message:t("video.testFail")}finally{V.value=!1}}}function K(a){f.value=a.id,_.value="preview"}function O(a){return oe(a)}return ee(E),(a,o)=>{var W;return u(),v("div",ue,[e("div",ce,[e("button",{type:"button",class:A(["tab",{active:_.value==="devices"}]),onClick:o[0]||(o[0]=l=>_.value="devices")},i(s(t)("video.tabDevices")),3),e("button",{type:"button",class:A(["tab",{active:_.value==="config"}]),onClick:o[1]||(o[1]=l=>_.value="config")},i(s(t)("video.tabConfig")),3),e("button",{type:"button",class:A(["tab",{active:_.value==="preview"}]),onClick:o[2]||(o[2]=l=>_.value="preview")},i(s(t)("video.tabPreview")),3),o[18]||(o[18]=e("div",{class:"tab-spacer"},null,-1)),e("div",ve,i(s(t)("video.brand")),1),e("div",re,i(s(t)("video.onlineCount",{n:$.value,total:g.value.length})),1),e("button",{type:"button",class:"btn ghost",disabled:T.value,onClick:E},i(s(t)("common.refresh")),9,pe),c.value?(u(),v("span",me,i(c.value),1)):y("",!0)]),_.value==="devices"?(u(),v(U,{key:0},[s(d).isAdmin?(u(),v("section",be,[e("div",he,[e("div",_e,[o[19]||(o[19]=e("div",{class:"vbar"},null,-1)),e("h3",null,i(s(t)("video.addTitle")),1)]),e("div",fe,i(s(t)("video.admin")),1)]),e("div",ye,[e("div",ge,[e("label",null,i(s(t)("video.name")),1),h(e("input",{"onUpdate:modelValue":o[3]||(o[3]=l=>m.name=l),placeholder:s(t)("video.namePh")},null,8,ke),[[k,m.name]])]),e("div",we,[e("label",null,i(s(t)("video.channel")),1),h(e("input",{"onUpdate:modelValue":o[4]||(o[4]=l=>m.channel=l),type:"number",min:"1",max:"256"},null,512),[[k,m.channel,void 0,{number:!0}]])]),e("div",Te,[e("label",null,i(s(t)("video.location")),1),h(e("input",{"onUpdate:modelValue":o[5]||(o[5]=l=>m.location=l),placeholder:s(t)("video.locationPh")},null,8,Ce),[[k,m.location]])]),e("div",Pe,[e("label",null,i(s(t)("video.type")),1),h(e("select",{"onUpdate:modelValue":o[6]||(o[6]=l=>m.deviceType=l)},[e("option",Ae,i(s(t)("video.typeNvr")),1),e("option",Ve,i(s(t)("video.typeIpc")),1)],512),[[L,m.deviceType]])]),e("div",Ee,[e("label",null,i(s(t)("video.ip")),1),h(e("input",{"onUpdate:modelValue":o[7]||(o[7]=l=>m.ip=l),placeholder:s(t)("video.ipPh")},null,8,Se),[[k,m.ip]])]),e("div",Ue,[e("label",null,i(s(t)("video.remark")),1),h(e("input",{"onUpdate:modelValue":o[8]||(o[8]=l=>m.remark=l)},null,512),[[k,m.remark]])])]),e("div",$e,[e("button",{type:"button",class:"btn",onClick:D},i(s(t)("video.add")),1)])])):y("",!0),e("section",Ie,[e("div",Me,[e("div",Re,[o[20]||(o[20]=e("div",{class:"vbar"},null,-1)),e("h3",null,i(s(t)("video.listTitle")),1)]),o[21]||(o[21]=e("div",{class:"badge amber"},"Hikvision NVR",-1))]),e("div",xe,[e("table",De,[e("thead",null,[e("tr",null,[e("th",null,i(s(t)("video.colChannel")),1),e("th",null,i(s(t)("video.colName")),1),e("th",null,i(s(t)("video.colLocation")),1),e("th",null,i(s(t)("video.colType")),1),e("th",null,i(s(t)("video.colIp")),1),e("th",null,i(s(t)("video.colStatus")),1),e("th",null,i(s(t)("video.colEnabled")),1),e("th",null,i(s(t)("video.colUpdated")),1),e("th",null,i(s(t)("video.colAction")),1)])]),e("tbody",null,[(u(!0),v(U,null,H(g.value,l=>(u(),v("tr",{key:l.id},[e("td",null,i(l.channel),1),e("td",null,i(l.name),1),e("td",null,i(l.location),1),e("td",null,i(I.value[l.deviceType]),1),e("td",null,i(l.ip||"—"),1),e("td",null,[e("span",{class:A(["st",l.status])},i(b.value[l.status]),3)]),e("td",null,i(l.enabled?s(t)("common.yes"):s(t)("common.no")),1),e("td",null,i(O(l.updatedAt)),1),e("td",Le,[e("button",{type:"button",class:"btn ghost",onClick:M=>K(l)},i(s(t)("video.view")),9,Ne),s(d).isAdmin?(u(),v("button",{key:0,type:"button",class:"btn ghost",onClick:M=>z(l)},i(l.enabled?s(t)("video.disable"):s(t)("video.enable")),9,Oe)):y("",!0),s(d).isAdmin?(u(),v("button",{key:1,type:"button",class:"btn danger",onClick:M=>G(l)},i(s(t)("video.remove")),9,We)):y("",!0)])]))),128)),g.value.length?y("",!0):(u(),v("tr",He,[e("td",Fe,i(s(t)("video.empty")),1)]))])])])])],64)):_.value==="config"?(u(),v("section",Be,[e("div",je,[e("div",Je,[o[22]||(o[22]=e("div",{class:"vbar"},null,-1)),e("h3",null,i(s(t)("video.configTitle")),1)]),e("div",ze,[e("div",Ge,i(s(t)("video.vendor")),1),e("div",{class:A(["badge",s(d).isAdmin?"":"amber"])},i(s(d).isAdmin?s(t)("video.editable"):s(t)("video.readonly")),3)])]),e("p",Qe,i(s(t)("video.configHint")),1),e("div",qe,[e("div",Ke,[e("label",null,i(s(t)("video.nvrIp")),1),h(e("input",{"onUpdate:modelValue":o[9]||(o[9]=l=>n.host=l),disabled:!s(d).isAdmin,placeholder:"192.168.x.x"},null,8,Xe),[[k,n.host]])]),e("div",Ye,[e("label",null,i(s(t)("video.sdkPort")),1),h(e("input",{"onUpdate:modelValue":o[10]||(o[10]=l=>n.port=l),type:"number",disabled:!s(d).isAdmin},null,8,Ze),[[k,n.port,void 0,{number:!0}]])]),e("div",et,[e("label",null,i(s(t)("video.rtspPort")),1),h(e("input",{"onUpdate:modelValue":o[11]||(o[11]=l=>n.rtspPort=l),type:"number",disabled:!s(d).isAdmin},null,8,tt),[[k,n.rtspPort,void 0,{number:!0}]])]),e("div",st,[e("label",null,i(s(t)("video.protocol")),1),h(e("select",{"onUpdate:modelValue":o[12]||(o[12]=l=>n.protocol=l),disabled:!s(d).isAdmin},[e("option",it,i(s(t)("video.protocolSdk")),1),o[23]||(o[23]=e("option",{value:"rtsp"},"RTSP",-1)),o[24]||(o[24]=e("option",{value:"isapi"},"ISAPI",-1))],8,ot),[[L,n.protocol]])]),e("div",lt,[e("label",null,i(s(t)("video.username")),1),h(e("input",{"onUpdate:modelValue":o[13]||(o[13]=l=>n.username=l),disabled:!s(d).isAdmin},null,8,nt),[[k,n.username]])]),e("div",at,[e("label",null,i(s(t)("video.password")),1),h(e("input",{"onUpdate:modelValue":o[14]||(o[14]=l=>n.password=l),type:"password",disabled:!s(d).isAdmin,placeholder:"********",autocomplete:"new-password"},null,8,dt),[[k,n.password]])]),e("div",ut,[e("label",null,i(s(t)("video.stream")),1),h(e("select",{"onUpdate:modelValue":o[15]||(o[15]=l=>n.streamType=l),disabled:!s(d).isAdmin},[e("option",vt,i(s(t)("video.streamSub")),1),e("option",rt,i(s(t)("video.streamMain")),1)],8,ct),[[L,n.streamType]])]),e("div",pt,[e("label",null,i(s(t)("video.timeout")),1),h(e("input",{"onUpdate:modelValue":o[16]||(o[16]=l=>n.previewTimeoutMs=l),type:"number",disabled:!s(d).isAdmin},null,8,mt),[[k,n.previewTimeoutMs,void 0,{number:!0}]])]),e("div",bt,[e("label",null,i(s(t)("video.enableComm")),1),e("label",ht,[h(e("input",{"onUpdate:modelValue":o[17]||(o[17]=l=>n.enabled=l),type:"checkbox",disabled:!s(d).isAdmin},null,8,_t),[[te,n.enabled]]),e("span",null,i(n.enabled?s(t)("video.enabled"):s(t)("video.disabled")),1)])])]),e("div",ft,[s(d).isAdmin?(u(),v("button",{key:0,type:"button",class:"btn",onClick:Q},i(s(t)("video.save")),1)):y("",!0),s(d).isAdmin?(u(),v("button",{key:1,type:"button",class:"btn ghost",disabled:V.value,onClick:q},i(V.value?s(t)("video.testing"):s(t)("video.test")),9,yt)):y("",!0),C.value?(u(),v("span",gt,i(C.value),1)):y("",!0),r.value?(u(),v("span",kt,i(s(t)("video.lastUpdate",{time:O(r.value.updatedAt),by:r.value.updatedBy})),1)):y("",!0)])])):(u(),v("div",wt,[e("section",Tt,[e("div",Ct,[e("div",Pt,[o[25]||(o[25]=e("div",{class:"vbar"},null,-1)),e("h3",null,i(p.value?p.value.name:s(t)("video.noChannel")),1)]),p.value?(u(),v("div",{key:0,class:A(["badge",p.value.status==="online"?"":"amber"])}," CH"+i(p.value.channel)+" · "+i(b.value[p.value.status]),3)):y("",!0)]),e("div",{class:A(["stage webrtc-stage",((W=p.value)==null?void 0:W.status)||"offline"])},[p.value?(u(),se(de,{key:p.value.id,"device-id":p.value.id},null,8,["device-id"])):(u(),v("div",At,[e("div",Vt,i(s(t)("video.noChannelTitle")),1),e("p",Et,i(s(t)("video.noChannelHint")),1)])),p.value?(u(),v("div",St,[x(i(p.value.name)+" · "+i(p.value.location)+" · CH"+i(p.value.channel)+" ",1),p.value.ip?(u(),v(U,{key:0},[x(" · "+i(p.value.ip),1)],64)):y("",!0),o[26]||(o[26]=x(" · WebRTC / WHEP ",-1))])):y("",!0)],2)]),e("section",Ut,[e("div",$t,[e("div",It,[o[27]||(o[27]=e("div",{class:"vbar"},null,-1)),e("h3",null,i(s(t)("video.channelList")),1)])]),e("div",Mt,[(u(!0),v(U,null,H(P.value,l=>{var M;return u(),v("button",{key:l.id,type:"button",class:A(["thumb",[{active:((M=p.value)==null?void 0:M.id)===l.id},l.status]]),onClick:Wt=>f.value=l.id},[e("div",xt,[e("span",Dt,"CH"+i(l.channel),1),e("span",{class:A(["st",l.status])},i(b.value[l.status]),3)]),e("div",Lt,i(l.name),1),e("div",Nt,i(l.location),1)],10,Rt)}),128))])])]))])}}}),Bt=J(Ot,[["__scopeId","data-v-b1a1fb2b"]]);export{Bt as default};
.video-page[data-v-36429526]{gap:12px}.head-right[data-v-36429526]{display:flex;align-items:center;gap:8px}.video-tabs[data-v-36429526]{display:flex;align-items:center;gap:8px;flex:0 0 auto}.tab[data-v-36429526]{border-radius:6px;border:1px solid rgba(62,200,255,.22);background:#122a4e66;color:var(--muted);padding:6px 14px;font-size:12px;cursor:pointer}.tab.active[data-v-36429526]{background:linear-gradient(90deg,#1a6fff,#0aa6e5);color:#fff;border-color:transparent;font-weight:600}.tab-spacer[data-v-36429526]{flex:1}.msg[data-v-36429526]{font-size:12px;color:var(--cyan-lt)}.hint[data-v-36429526]{font-size:12px;color:var(--label);line-height:1.6;margin-bottom:12px}.form-grid.three[data-v-36429526]{grid-template-columns:repeat(3,1fr);max-width:1100px}.row-actions[data-v-36429526]{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:14px}.switch-field .switch[data-v-36429526]{display:flex;align-items:center;gap:8px;height:36px;color:var(--body);font-size:13px;cursor:pointer}.list-panel[data-v-36429526],.config-panel[data-v-36429526]{flex:1;min-height:0;display:flex;flex-direction:column}.table-wrap[data-v-36429526]{flex:1;min-height:0;overflow:auto}.ops[data-v-36429526]{display:flex;flex-wrap:wrap;gap:6px}.empty[data-v-36429526]{text-align:center;color:var(--label);padding:24px!important}.st[data-v-36429526]{display:inline-block;padding:1px 8px;border-radius:4px;font-size:11px}.st.online[data-v-36429526]{background:#2fd6a126;color:var(--green)}.st.offline[data-v-36429526]{background:#8eb4d41f;color:var(--muted)}.st.alarm[data-v-36429526]{background:#f0b4292e;color:var(--amber)}.preview-layout[data-v-36429526]{flex:1;min-height:0;display:grid;grid-template-columns:1.6fr 1fr;gap:12px}.webrtc-stage[data-v-36429526]{display:flex;flex-direction:column;min-height:360px;padding:0;overflow:hidden}.webrtc-stage[data-v-36429526] .webrtc-player{flex:1;min-height:320px;border-radius:0}.cam-meta.bar[data-v-36429526]{flex:0 0 auto;padding:8px 12px;font-size:12px;color:var(--muted);border-top:1px solid rgba(62,200,255,.15);background:#00000040}.preview-main[data-v-36429526],.preview-side[data-v-36429526]{min-height:0;display:flex;flex-direction:column}.stage[data-v-36429526]{position:relative;flex:1;min-height:280px;border-radius:8px;overflow:hidden;border:1px solid rgba(62,200,255,.28);background:radial-gradient(ellipse at 30% 20%,rgba(58,140,220,.22),transparent 55%),linear-gradient(160deg,#0a1a30,#07111f 55%,#040a14)}.stage.alarm[data-v-36429526]{background:radial-gradient(ellipse at 40% 30%,rgba(240,180,41,.18),transparent 50%),linear-gradient(160deg,#1a1520,#0c1018)}.stage.offline[data-v-36429526]{filter:saturate(.55)}.scan[data-v-36429526]{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(122,216,255,.03) 2px,rgba(122,216,255,.03) 4px)}.live-tag[data-v-36429526]{position:absolute;left:12px;top:12px;z-index:2;display:flex;align-items:center;gap:6px;font-size:11px;color:#fff;background:#04101fa6;padding:3px 8px;border-radius:4px}.live-tag i[data-v-36429526]{width:7px;height:7px;border-radius:50%;background:#ff5a5a;box-shadow:0 0 #ff5a5a99;animation:pulse-36429526 1.4s ease infinite}@keyframes pulse-36429526{70%{box-shadow:0 0 0 6px #ff5a5a00}to{box-shadow:0 0 #ff5a5a00}}.stage-body[data-v-36429526]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:24px;z-index:1}.cam-title[data-v-36429526]{font-size:22px;font-weight:600;color:var(--title)}.cam-sub[data-v-36429526]{margin-top:8px;font-size:13px;color:var(--cyan-lt)}.cam-meta[data-v-36429526]{margin-top:10px;font-size:12px;color:var(--label);font-family:var(--font-num)}.cam-note[data-v-36429526]{margin-top:16px;max-width:420px;font-size:12px;color:var(--muted);line-height:1.7}.thumb-grid[data-v-36429526]{flex:1;min-height:0;overflow:auto;display:grid;grid-template-columns:1fr 1fr;gap:8px;align-content:start}.thumb[data-v-36429526]{text-align:left;cursor:pointer;border-radius:8px;padding:10px 12px;border:1px solid rgba(62,200,255,.2);background:#0e244459;color:inherit}.thumb[data-v-36429526]:hover{border-color:#3ec8ff73}.thumb.active[data-v-36429526]{border-color:#3ac8ffb3;background:#1a6fff38;box-shadow:inset 0 0 0 1px #7ad8ff26}.thumb-top[data-v-36429526]{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.ch[data-v-36429526]{font-size:11px;color:var(--cyan-lt);font-family:var(--font-num)}.thumb-name[data-v-36429526]{font-size:13px;font-weight:600;color:#fff}.thumb-loc[data-v-36429526]{margin-top:4px;font-size:11px;color:var(--label)}
.webrtc-player[data-v-a83be64f]{position:relative;width:100%;height:100%;min-height:280px;background:#050a14;border-radius:8px;overflow:hidden}.video[data-v-a83be64f]{width:100%;height:100%;object-fit:contain;background:#000}.overlay[data-v-a83be64f]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:#c9d7f0;font-size:14px;background:#050a14b8;text-align:center;padding:16px}.sub[data-v-a83be64f]{font-size:12px;color:#8fa3c4;max-width:80%;line-height:1.5;word-break:break-all}.btn[data-v-a83be64f]{border:1px solid rgba(61,139,253,.45);background:#3d8bfd33;color:#fff;border-radius:6px;padding:6px 14px;cursor:pointer}.live-tag[data-v-a83be64f]{position:absolute;top:12px;left:12px;display:flex;align-items:center;gap:6px;font-size:11px;padding:4px 8px;border-radius:4px;background:#0000008c;color:#9dffc0}.live-tag i[data-v-a83be64f]{width:7px;height:7px;border-radius:50%;background:#3dd68c;box-shadow:0 0 8px #3dd68c}.video-page[data-v-b1a1fb2b]{gap:12px}.head-right[data-v-b1a1fb2b]{display:flex;align-items:center;gap:8px}.video-tabs[data-v-b1a1fb2b]{display:flex;align-items:center;gap:8px;flex:0 0 auto}.tab[data-v-b1a1fb2b]{border-radius:6px;border:1px solid rgba(62,200,255,.22);background:#122a4e66;color:var(--muted);padding:6px 14px;font-size:12px;cursor:pointer}.tab.active[data-v-b1a1fb2b]{background:linear-gradient(90deg,#1a6fff,#0aa6e5);color:#fff;border-color:transparent;font-weight:600}.tab-spacer[data-v-b1a1fb2b]{flex:1}.msg[data-v-b1a1fb2b]{font-size:12px;color:var(--cyan-lt)}.hint[data-v-b1a1fb2b]{font-size:12px;color:var(--label);line-height:1.6;margin-bottom:12px}.form-grid.three[data-v-b1a1fb2b]{grid-template-columns:repeat(3,1fr);max-width:1100px}.row-actions[data-v-b1a1fb2b]{display:flex;align-items:center;flex-wrap:wrap;gap:12px;margin-top:14px}.switch-field .switch[data-v-b1a1fb2b]{display:flex;align-items:center;gap:8px;height:36px;color:var(--body);font-size:13px;cursor:pointer}.list-panel[data-v-b1a1fb2b],.config-panel[data-v-b1a1fb2b]{flex:1;min-height:0;display:flex;flex-direction:column}.table-wrap[data-v-b1a1fb2b]{flex:1;min-height:0;overflow:auto}.ops[data-v-b1a1fb2b]{display:flex;flex-wrap:wrap;gap:6px}.empty[data-v-b1a1fb2b]{text-align:center;color:var(--label);padding:24px!important}.st[data-v-b1a1fb2b]{display:inline-block;padding:1px 8px;border-radius:4px;font-size:11px}.st.online[data-v-b1a1fb2b]{background:#2fd6a126;color:var(--green)}.st.offline[data-v-b1a1fb2b]{background:#8eb4d41f;color:var(--muted)}.st.alarm[data-v-b1a1fb2b]{background:#f0b4292e;color:var(--amber)}.preview-layout[data-v-b1a1fb2b]{flex:1;min-height:0;display:grid;grid-template-columns:1.6fr 1fr;gap:12px}.webrtc-stage[data-v-b1a1fb2b]{display:flex;flex-direction:column;min-height:360px;padding:0;overflow:hidden}.webrtc-stage[data-v-b1a1fb2b] .webrtc-player{flex:1;min-height:320px;border-radius:0}.cam-meta.bar[data-v-b1a1fb2b]{flex:0 0 auto;padding:8px 12px;font-size:12px;color:var(--muted);border-top:1px solid rgba(62,200,255,.15);background:#00000040}.preview-main[data-v-b1a1fb2b],.preview-side[data-v-b1a1fb2b]{min-height:0;display:flex;flex-direction:column}.stage[data-v-b1a1fb2b]{position:relative;flex:1;min-height:280px;border-radius:8px;overflow:hidden;border:1px solid rgba(62,200,255,.28);background:radial-gradient(ellipse at 30% 20%,rgba(58,140,220,.22),transparent 55%),linear-gradient(160deg,#0a1a30,#07111f 55%,#040a14)}.stage.alarm[data-v-b1a1fb2b]{background:radial-gradient(ellipse at 40% 30%,rgba(240,180,41,.18),transparent 50%),linear-gradient(160deg,#1a1520,#0c1018)}.stage.offline[data-v-b1a1fb2b]{filter:saturate(.55)}.scan[data-v-b1a1fb2b]{pointer-events:none;position:absolute;top:0;right:0;bottom:0;left:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(122,216,255,.03) 2px,rgba(122,216,255,.03) 4px)}.live-tag[data-v-b1a1fb2b]{position:absolute;left:12px;top:12px;z-index:2;display:flex;align-items:center;gap:6px;font-size:11px;color:#fff;background:#04101fa6;padding:3px 8px;border-radius:4px}.live-tag i[data-v-b1a1fb2b]{width:7px;height:7px;border-radius:50%;background:#ff5a5a;box-shadow:0 0 #ff5a5a99;animation:pulse-b1a1fb2b 1.4s ease infinite}@keyframes pulse-b1a1fb2b{70%{box-shadow:0 0 0 6px #ff5a5a00}to{box-shadow:0 0 #ff5a5a00}}.stage-body[data-v-b1a1fb2b]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;padding:24px;z-index:1}.cam-title[data-v-b1a1fb2b]{font-size:22px;font-weight:600;color:var(--title)}.cam-sub[data-v-b1a1fb2b]{margin-top:8px;font-size:13px;color:var(--cyan-lt)}.cam-meta[data-v-b1a1fb2b]{margin-top:10px;font-size:12px;color:var(--label);font-family:var(--font-num)}.cam-note[data-v-b1a1fb2b]{margin-top:16px;max-width:420px;font-size:12px;color:var(--muted);line-height:1.7}.thumb-grid[data-v-b1a1fb2b]{flex:1;min-height:0;overflow:auto;display:grid;grid-template-columns:1fr 1fr;gap:8px;align-content:start}.thumb[data-v-b1a1fb2b]{text-align:left;cursor:pointer;border-radius:8px;padding:10px 12px;border:1px solid rgba(62,200,255,.2);background:#0e244459;color:inherit}.thumb[data-v-b1a1fb2b]:hover{border-color:#3ec8ff73}.thumb.active[data-v-b1a1fb2b]{border-color:#3ac8ffb3;background:#1a6fff38;box-shadow:inset 0 0 0 1px #7ad8ff26}.thumb-top[data-v-b1a1fb2b]{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px}.ch[data-v-b1a1fb2b]{font-size:11px;color:var(--cyan-lt);font-family:var(--font-num)}.thumb-name[data-v-b1a1fb2b]{font-size:13px;font-weight:600;color:#fff}.thumb-loc[data-v-b1a1fb2b]{margin-top:4px;font-size:11px;color:var(--label)}
import{d as S,u as E,q as P,s as W,c as s,n as I,b as i,F as w,g as k,t as x,r as g,o as r,_ as B}from"./index-Bs_x-_cK.js";const D={key:0,class:"overlay"},O={class:"sub"},A={key:1,class:"live-tag"},L=S({__name:"WebRtcPlayer",props:{deviceId:{},whepPath:{}},setup(_,{expose:C}){const c=_,f=E(),n=g(null),a=g("idle"),l=g("");let e=null,d=null;async function u(){try{d&&f.token&&await fetch(d,{method:"DELETE",headers:{Authorization:`Bearer ${f.token}`}}).catch(()=>{})}finally{d=null,e==null||e.close(),e=null,n.value&&(n.value.srcObject=null),a.value="idle"}}async function h(){var o;if(await u(),!!c.deviceId){a.value="connecting",l.value="",e=new RTCPeerConnection({iceServers:[{urls:"stun:stun.l.google.com:19302"}]}),e.addTransceiver("video",{direction:"recvonly"}),e.addTransceiver("audio",{direction:"recvonly"}),e.ontrack=t=>{n.value&&(n.value.srcObject=t.streams[0]||new MediaStream([t.track]),n.value.play().catch(()=>{}),a.value="playing")},e.onconnectionstatechange=()=>{e&&(e.connectionState==="failed"||e.connectionState==="disconnected")&&(a.value="error",l.value="WebRTC 连接中断")};try{const t=await e.createOffer();await e.setLocalDescription(t),await R(e);const m=c.whepPath||`/api/video/devices/${encodeURIComponent(c.deviceId)}/whep`,p=await fetch(m,{method:"POST",headers:{"Content-Type":"application/sdp",Accept:"application/sdp",Authorization:`Bearer ${f.token}`},body:((o=e.localDescription)==null?void 0:o.sdp)||t.sdp||""}),v=p.headers.get("Location");v&&(d=(v.startsWith("http"),v));const y=await p.text();if(!p.ok){let b=y||`WHEP HTTP ${p.status}`;try{const T=JSON.parse(y);T.message&&(b=T.message)}catch{}throw new Error(b)}await e.setRemoteDescription({type:"answer",sdp:y})}catch(t){a.value="error",l.value=t instanceof Error?t.message:"WebRTC 启动失败",await u(),a.value="error"}}}function R(o){return o.iceGatheringState==="complete"?Promise.resolve():new Promise(t=>{const m=window.setTimeout(()=>t(),2e3);o.onicegatheringstatechange=()=>{o.iceGatheringState==="complete"&&(window.clearTimeout(m),t())}})}return P(()=>c.deviceId,()=>{h()},{immediate:!0}),W(()=>{u()}),C({restart:h,stop:u}),(o,t)=>(r(),s("div",{class:I(["webrtc-player",a.value])},[i("video",{ref_key:"videoEl",ref:n,class:"video",autoplay:"",playsinline:"",muted:""},null,512),a.value!=="playing"?(r(),s("div",D,[a.value==="connecting"?(r(),s(w,{key:0},[k("正在建立 WebRTC…")],64)):a.value==="error"?(r(),s(w,{key:1},[t[0]||(t[0]=i("div",null,"WebRTC 未就绪",-1)),i("div",O,x(l.value),1),i("button",{type:"button",class:"btn",onClick:h},"重试")],64)):(r(),s(w,{key:2},[k("空闲")],64))])):(r(),s("div",A,[...t[1]||(t[1]=[i("i",null,null,-1),i("span",null,"WebRTC · LIVE",-1)])]))],2))}}),j=B(L,[["__scopeId","data-v-a83be64f"]]);export{j as W};
.webrtc-player[data-v-a83be64f]{position:relative;width:100%;height:100%;min-height:280px;background:#050a14;border-radius:8px;overflow:hidden}.video[data-v-a83be64f]{width:100%;height:100%;object-fit:contain;background:#000}.overlay[data-v-a83be64f]{position:absolute;top:0;right:0;bottom:0;left:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:#c9d7f0;font-size:14px;background:#050a14b8;text-align:center;padding:16px}.sub[data-v-a83be64f]{font-size:12px;color:#8fa3c4;max-width:80%;line-height:1.5;word-break:break-all}.btn[data-v-a83be64f]{border:1px solid rgba(61,139,253,.45);background:#3d8bfd33;color:#fff;border-radius:6px;padding:6px 14px;cursor:pointer}.live-tag[data-v-a83be64f]{position:absolute;top:12px;left:12px;display:flex;align-items:center;gap:6px;font-size:11px;padding:4px 8px;border-radius:4px;background:#0000008c;color:#9dffc0}.live-tag i[data-v-a83be64f]{width:7px;height:7px;border-radius:50%;background:#3dd68c;box-shadow:0 0 8px #3dd68c}
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
@font-face{font-family:AlibabaPuHuiTi-3-115-Black;src:url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.woff2) format("woff2"),url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.woff) format("woff"),url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.ttf) format("truetype");font-weight:900;font-style:normal;font-display:swap}:root{--screen-bg: #000b1d;--panel-bg: rgba(0, 18, 42, .55);--panel-border: rgba(0, 247, 255, .22);--panel-title: #f4feff;--panel-muted: #7eb6d6;--text: #d7f4ff;--accent: #00f7ff;--cyan: #00f7ff;--alert: #ff4d4f;--ok: #52c41a;--warn: #faad14;--title-font: "AlibabaPuHuiTi-3-115-Black", "PingFang SC", "Noto Sans SC", "Microsoft YaHei", sans-serif;--body-font: "PingFang SC", "Noto Sans SC", "Microsoft YaHei", "Helvetica Neue", sans-serif;--digital-font: "Share Tech Mono", ui-monospace, monospace;--cjk-tracking: .02em;--bg: var(--screen-bg);--bg-deep: #04080f;--cyan-lt: #7ad8ff;--green: var(--ok);--amber: var(--warn);--red: var(--alert);--title: var(--panel-title);--body: var(--text);--label: var(--panel-muted);--muted: var(--panel-muted);--panel-bd: var(--panel-border);--card-bg: rgba(6, 12, 20, .55);--card-bd: rgba(61, 190, 255, .18);--track: rgba(61, 190, 255, .16);--bar-grad: linear-gradient(90deg, rgba(61, 190, 255, .55), #3dbeff);--font-cn: var(--body-font);--font-num: var(--digital-font);--shadow: 0 6px 20px rgba(0, 0, 0, .22)}*{margin:0;padding:0;box-sizing:border-box}html,body,#app{width:100%;height:100%;overflow:hidden;background:var(--bg-deep)}body{font-family:var(--body-font);font-weight:600;letter-spacing:var(--cjk-tracking);color:var(--text);-webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums;font-synthesis:none}html[lang=zh-TW]{--title-font: "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", "Heiti TC", "PingFang SC", sans-serif;--body-font: "PingFang TC", "Noto Sans TC", "Microsoft JhengHei", "Heiti TC", "PingFang SC", sans-serif;--cjk-tracking: 0}html[lang=zh-TW] body{font-weight:500}html[lang=en],html[lang=pt]{--title-font: "AlibabaPuHuiTi-3-115-Black", "Helvetica Neue", Arial, sans-serif;--body-font: "Helvetica Neue", Arial, "PingFang SC", sans-serif;--cjk-tracking: .01em}button,input,select,textarea{font:inherit}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:#3dbeff59;border-radius:2px}::-webkit-scrollbar-track{background:transparent}.stage{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;max-width:100vw;max-height:100vh;transform:none;display:flex;flex-direction:column;overflow:hidden;background:#00060f;color:var(--text);font-family:var(--body-font);--screen-side-w: clamp(280px, 24vw, 480px)}.stage:before{content:none}.screen-header{position:relative;height:84px;flex:0 0 84px;display:flex;align-items:center;justify-content:space-between;padding:0 24px;border-bottom:1px solid var(--panel-border);background:linear-gradient(90deg,#3dbeff29,#0810188c 42%,#060c1459)}.screen-header:after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:linear-gradient(90deg,var(--accent),transparent 62%);opacity:.85;pointer-events:none}.brand{display:flex;align-items:center;gap:12px}.brand-mark{width:34px;height:34px;border-radius:3px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff8c,#3dbeff0f);box-shadow:0 0 1.1em #3dbeff52;display:grid;place-items:center;color:#eaf4ff;font-weight:700;font-family:var(--digital-font)}.brand-txt .sys{font-size:14px;font-weight:600;color:var(--panel-title);letter-spacing:.04em}.brand-txt .en{font-size:9px;color:var(--accent);letter-spacing:.16em;text-transform:uppercase;font-family:var(--body-font)}.title-group{position:absolute;left:50%;top:18px;transform:translate(-50%);display:flex;align-items:center;gap:18px}.title-group h1{font-size:28px;font-weight:700;letter-spacing:.12em;white-space:nowrap;font-family:var(--title-font);background:linear-gradient(180deg,#fff 20%,#b7d7ff);-webkit-background-clip:text;background-clip:text;color:transparent}.wing{display:flex;align-items:center;gap:8px;height:28px}.wing-line{width:96px;height:3px;border-radius:1px;background:linear-gradient(90deg,transparent 0%,rgba(61,190,255,.15) 20%,#3dbeff 100%);box-shadow:0 0 10px #3dbeff8c;position:relative}.wing-line:before{content:"";position:absolute;left:18%;right:0;top:50%;transform:translateY(-50%);height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.75))}.wing-chevron{width:0;height:0;border-style:solid;border-width:8px 0 8px 12px;border-color:transparent transparent transparent #3dbeff;filter:drop-shadow(0 0 6px rgba(61,190,255,.85));flex:0 0 auto}.wing-dot{width:8px;height:8px;border-radius:50%;background:#7ad8ff;box-shadow:0 0 0 3px #3dbeff38,0 0 12px #3dbeffe6;flex:0 0 auto}.wing.right .wing-line{background:linear-gradient(90deg,#3dbeff 0%,rgba(61,190,255,.15) 80%,transparent 100%)}.wing.right .wing-line:before{left:0;right:18%;background:linear-gradient(90deg,rgba(255,255,255,.75),transparent)}.wing.right .wing-chevron{border-width:8px 12px 8px 0;border-color:transparent #3dbeff transparent transparent}.hdr-status{display:flex;align-items:center;gap:12px}.alarm-badge,.user-chip,.server-chip{display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;font-size:12px;letter-spacing:.04em}.alarm-badge{border-color:#e25b5b80;color:#ffb0b0;cursor:pointer}.user-chip{color:var(--text)}.user-chip button{border:none;background:transparent;color:var(--cyan-lt);cursor:pointer;margin-left:4px}.weather-wrap,.clock-wrap{position:absolute;top:50%;transform:translate(-50%,-50%);display:flex;align-items:baseline;gap:10px;white-space:nowrap}.weather-wrap{left:26%}.clock-wrap{left:74%}.weather-wrap .place,.weather-wrap .temp{font-size:18px;font-weight:600;font-family:var(--digital-font);color:var(--ok);line-height:1}.weather-wrap .w-text,.weather-wrap .humid{font-size:12px;color:#7cf0c4;letter-spacing:.04em}.clock-wrap .time{font-size:18px;font-weight:600;font-family:var(--digital-font);color:var(--accent);line-height:1;text-shadow:0 0 .55em rgba(61,190,255,.5)}.clock-wrap .date{font-size:12px;color:var(--panel-muted);letter-spacing:.08em}.dot{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 #3cba7a99;animation:pulse 2s infinite}.dot.red{background:var(--alert)}@keyframes pulse{0%{box-shadow:0 0 #3cba7a8c}70%{box-shadow:0 0 0 8px #3cba7a00}to{box-shadow:0 0 #3cba7a00}}.screen-nav{height:48px;flex:0 0 48px;display:flex;align-items:center;gap:8px;padding:0 20px}.nav-chip{border-radius:3px;border:1px solid var(--panel-border);background:#060c148c;cursor:pointer;color:var(--panel-muted);padding:6px 12px;font-size:12px;font-weight:600;letter-spacing:.04em;text-decoration:none;transition:.2s}.nav-chip.active,.nav-chip.router-link-active{background:linear-gradient(90deg,#3dbeff59,#3dbeff1f);color:#eaf4ff;border-color:#3dbeff8c}.nav-chip:hover{color:var(--cyan-lt);border-color:#3dbeff73}.nav-spacer{flex:1}.server-chip{color:#7cf0c4;border-color:#3cba7a59}.screen-main{flex:1;min-height:0;display:flex;gap:14px;padding:0 20px 14px}.panel{background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:4px;padding:14px;box-shadow:var(--shadow)}.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;flex:0 0 auto}.panel-title{display:flex;align-items:center;gap:8px}.panel-title .vbar{width:2px;height:14px;border-radius:1px;background:var(--accent);box-shadow:0 0 .5em var(--accent)}.panel-title h3{font-size:14px;font-weight:700;color:var(--panel-title);letter-spacing:.08em;text-transform:uppercase;font-family:var(--title-font)}.badge{padding:2px 8px;border-radius:2px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;background:#3cba7a1f;color:var(--ok)}.badge.amber{background:#e0a04a26;color:var(--warn)}.badge.red{background:#e25b5b26;color:#ffb0b0}.metric-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}.metric{display:flex;align-items:center;gap:8px;padding:10px;min-height:64px;border-radius:4px;background:var(--card-bg);border:1px solid var(--card-bd)}.metric .m-label{font-size:11px;color:var(--panel-muted);letter-spacing:.06em;text-transform:uppercase}.metric .m-value{font-size:20px;font-weight:600;font-family:var(--digital-font);color:#fff}.metric .m-value.green{color:var(--ok)}.kpi-bar{height:108px;flex:0 0 108px;display:flex;gap:14px;padding:0 20px 16px}.kpi{flex:1;padding:12px;border-radius:4px;background:var(--panel-bg);border:1px solid var(--panel-border);display:flex;flex-direction:column;justify-content:center;gap:6px}.kpi .k-label{font-size:11px;color:var(--panel-muted);letter-spacing:.06em;text-transform:uppercase}.kpi .digital{align-self:flex-start;padding:3px 10px;border-radius:2px;background:#060c14e6;border:1px solid rgba(61,190,255,.45);font-size:20px;font-weight:600;font-family:var(--digital-font);color:var(--accent)}.kpi .k-trend{font-size:10px;color:var(--warn)}.kpi .k-trend.green{color:var(--ok)}.kpi .k-trend.cyan{color:var(--cyan-lt)}.btn{border:1px solid rgba(61,190,255,.45);background:#3dbeff24;color:#e8f4ff;border-radius:2px;padding:8px 14px;cursor:pointer;font-weight:600;letter-spacing:.04em}.btn:hover{background:#3dbeff47;border-color:var(--accent)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn.danger{border-color:#e25b5b80;background:#e25b5b33;color:#ffe8e8}.btn.ghost{background:transparent}.table{width:100%;border-collapse:collapse;font-size:12px}.table th,.table td{padding:8px 10px;border-bottom:1px solid rgba(61,190,255,.16);text-align:left}.table th{color:var(--panel-muted);font-weight:600;letter-spacing:.05em;text-transform:uppercase;font-size:11px;background:#060c1459}.table td{color:var(--text)}.table tbody tr:hover td{background:#3dbeff14}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.field{display:flex;flex-direction:column;gap:6px}.field label{font-size:12px;color:var(--panel-muted);letter-spacing:.04em;font-weight:600}.field input,.field select,.field textarea{height:36px;border-radius:2px;padding:0 10px;border:none;box-shadow:0 0 0 1px #3dbeff47 inset;background:#060c14a6;color:var(--panel-title);outline:none}.field textarea{height:auto;padding:8px 10px}.field input:focus,.field select:focus,.field textarea:focus{box-shadow:0 0 0 1px #3dbeffa6 inset}.page-fill{flex:1;min-height:0;display:flex;flex-direction:column;gap:14px;width:100%;height:100%;pointer-events:auto}.page-fill>.panel{min-height:0}.stub-box{flex:1;display:grid;place-items:center;border-radius:4px;border:1px solid var(--panel-border);background:#081018b8;text-align:center;padding:40px}.stub-box h2{font-size:24px;color:var(--panel-title);margin-bottom:10px;letter-spacing:.08em;font-family:var(--title-font)}.stub-box p{font-size:13px;color:var(--panel-muted);line-height:1.8;max-width:560px}.mono{font-family:var(--digital-font);font-variant-numeric:tabular-nums}.tops-root{box-sizing:border-box;width:100%;height:100%;min-height:0;display:flex;flex-direction:column;gap:.6em;padding:.6em .75em .75em;overflow:hidden;background:radial-gradient(ellipse at 18% -8%,rgba(61,190,255,.14),transparent 48%),radial-gradient(ellipse at 92% 108%,rgba(226,91,91,.08),transparent 42%),linear-gradient(rgba(61,190,255,.035) 1px,transparent 1px),linear-gradient(90deg,rgba(61,190,255,.035) 1px,transparent 1px),var(--screen-bg);background-size:100% 100%,100% 100%,2.8em 2.8em,2.8em 2.8em,auto;color:var(--text);font-family:var(--body-font)}.tops-tone--ok{--tone: var(--ok)}.tops-tone--accent{--tone: var(--accent)}.tops-tone--warn{--tone: var(--warn)}.tops-tone--alert{--tone: var(--alert)}.tops-tone--muted{--tone: var(--panel-muted)}.tops-header{position:relative;flex:none;display:flex;align-items:center;gap:.9em;padding:.5em .85em;border:1px solid var(--panel-border);border-radius:4px;overflow:hidden;background:linear-gradient(90deg,#3dbeff2e,#081018db 42%,#060c14eb)}.tops-header:after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:linear-gradient(90deg,var(--accent),transparent 62%);opacity:.85}.tops-brand{display:flex;align-items:center;gap:.55em;min-width:0;cursor:pointer}.tops-brand__mark{flex:none;width:2.1em;height:2.1em;display:grid;place-items:center;border-radius:3px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff8c,#3dbeff0f);box-shadow:0 0 1.1em #3dbeff52,inset 0 0 .8em #3dbeff38;color:#eaf4ff}.tops-brand__mark :deep(svg),.tops-brand__mark svg{width:1.3em;height:1.3em}.tops-brand__copy{display:flex;flex-direction:column;gap:.1em;min-width:0}.tops-brand__copy strong{font-size:1.04em;font-weight:600;letter-spacing:.02em;color:var(--panel-title);white-space:nowrap}.tops-brand__copy small{font-size:.62em;letter-spacing:.16em;text-transform:uppercase;color:var(--panel-muted);white-space:nowrap}.tops-header__chips{display:flex;flex-wrap:wrap;align-items:center;gap:.4em;min-width:0}.tops-chip{display:inline-flex;align-items:center;gap:.42em;padding:.24em .48em;border:1px solid var(--panel-border);border-radius:2px;background:#060c148c;white-space:nowrap}.tops-chip small{font-size:.6em;letter-spacing:.06em;text-transform:uppercase;color:var(--panel-muted)}.tops-chip b{font-size:.76em;font-weight:600;color:var(--panel-title);font-family:var(--digital-font)}.tops-dot{width:.42em;height:.42em;border-radius:50%;background:var(--tone, var(--ok));box-shadow:0 0 .45em var(--tone, var(--ok))}.tops-header__end{margin-left:auto;display:flex;align-items:center;gap:.7em}.tops-clock{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.tops-clock small{font-size:.6em;letter-spacing:.12em;color:var(--panel-muted)}.tops-clock b{font-family:var(--digital-font);font-size:1.18em;font-weight:600;color:var(--accent);text-shadow:0 0 .55em rgba(61,190,255,.5)}.tops-logout{font:inherit;font-size:.68em;font-weight:600;letter-spacing:.06em;padding:.38em .75em;border:1px solid var(--panel-border);border-radius:3px;background:#060c148c;color:var(--panel-muted);cursor:pointer;transition:color .18s ease,border-color .18s ease,background .18s ease;text-decoration:none}.tops-logout:hover:not(:disabled){color:var(--panel-title);border-color:#3dbeff8c;background:#3dbeff24}.tops-body{flex:1;min-height:0;display:flex;gap:.6em}.tops-main{flex:1;min-width:0;min-height:0;overflow:auto;display:flex;flex-direction:column}.tops-side{flex:none;width:13.4em;display:flex;flex-direction:column;gap:.45em;padding:.6em .55em;border:1px solid var(--panel-border);border-radius:4px;background:linear-gradient(180deg,#081018f0,#060c14f0)}.tops-side__head{display:flex;align-items:baseline;justify-content:space-between;gap:.4em;padding:0 .2em .45em;border-bottom:1px solid var(--panel-border)}.tops-side__head strong{font-size:.82em;font-weight:600;letter-spacing:.06em;color:var(--panel-title)}.tops-side__head small{font-size:.64em;letter-spacing:.12em;color:var(--panel-muted)}.tops-menu{flex:1;min-height:0;display:flex;flex-direction:column;gap:.42em;padding-top:.1em;overflow-y:auto}.tops-menu__item{position:relative;display:flex;align-items:center;gap:.6em;width:100%;padding:.55em .6em .55em .75em;font:inherit;text-align:left;text-decoration:none;color:var(--text);border:1px solid var(--panel-border);border-radius:3px;background:linear-gradient(180deg,#081018e0,#060c14e0);cursor:pointer;transition:border-color .2s ease,background .2s ease,transform .2s ease;box-sizing:border-box}.tops-menu__item:before{content:"";position:absolute;left:0;top:.35em;bottom:.35em;width:2px;border-radius:1px;background:transparent;transition:background .2s ease,box-shadow .2s ease}.tops-menu__item:hover{transform:translate(2px);border-color:#3dbeff73;background:linear-gradient(180deg,#3dbeff29,#060c14e6)}.tops-menu__item.router-link-active,.tops-menu__item.is-on{border-color:#3dbeff99;background:linear-gradient(90deg,#3dbeff47,#081018b8 72%)}.tops-menu__item.router-link-active:before,.tops-menu__item.is-on:before{background:var(--accent);box-shadow:0 0 .6em var(--accent)}.tops-menu__icon{flex:none;width:1.7em;height:1.7em;display:grid;place-items:center;border-radius:3px;border:1px solid rgba(61,190,255,.28);color:var(--panel-muted);background:#060c148c}.tops-menu__item.router-link-active .tops-menu__icon{color:var(--accent);border-color:#3dbeff80}.tops-menu__icon svg{width:1em;height:1em}.tops-menu__copy{display:flex;flex-direction:column;gap:.12em;min-width:0}.tops-menu__label{font-size:.82em;font-weight:600;color:var(--panel-title)}.tops-menu__hint{font-size:.58em;letter-spacing:.04em;color:var(--panel-muted)}.tops-side__foot{display:flex;align-items:center;gap:.45em;padding:.35em .2em 0;border-top:1px solid var(--panel-border);font-size:.62em;letter-spacing:.08em;color:var(--panel-muted)}.tops-login{position:relative;isolation:isolate;width:100%;height:100%;min-height:100vh;overflow:hidden;display:grid;place-items:center;background:radial-gradient(120% 90% at 50% -10%,#123048,#081018 52%,#04080f);color:var(--text);font-family:var(--body-font);font-weight:600;letter-spacing:.02em}.tops-login__atmosphere{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none}.tops-login__grid{position:absolute;top:18%;right:-10%;bottom:-28%;left:-10%;background-image:linear-gradient(rgba(61,190,255,.16) 1px,transparent 1px),linear-gradient(90deg,rgba(61,190,255,.16) 1px,transparent 1px);background-size:48px 48px;transform:perspective(720px) rotateX(58deg);transform-origin:50% 0%;-webkit-mask-image:linear-gradient(180deg,transparent 0%,#000 28%,#000 72%,transparent 100%);mask-image:linear-gradient(180deg,transparent 0%,#000 28%,#000 72%,transparent 100%);animation:tops-login-grid 18s linear infinite;opacity:.55}.tops-login__glow{position:absolute;border-radius:50%;filter:blur(48px)}.tops-login__glow--a{width:min(48vw,520px);height:min(48vw,520px);left:50%;top:12%;transform:translate(-50%);background:radial-gradient(circle,rgba(61,190,255,.28),transparent 68%);animation:tops-login-breathe 5.5s ease-in-out infinite}.tops-login__glow--b{width:min(36vw,380px);height:min(36vw,380px);left:50%;top:42%;transform:translate(-50%);background:radial-gradient(circle,rgba(242,230,168,.12),transparent 70%)}.tops-login__horizon{position:absolute;left:10%;right:10%;top:58%;height:1px;background:linear-gradient(90deg,transparent,rgba(61,190,255,.55),transparent);opacity:.7}.tops-login__stage{position:relative;z-index:1;width:min(28rem,calc(100vw - 2.5rem));display:flex;flex-direction:column;align-items:center;text-align:center;padding:1.25rem 0 2rem}.tops-login__mark{width:4.2rem;height:4.2rem;display:grid;place-items:center;border-radius:8px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff80,#3dbeff0f);box-shadow:0 0 1.4em #3dbeff59;color:#eaf4ff;font-size:1.4rem;font-weight:700;letter-spacing:.08em;margin-bottom:1rem;animation:tops-login-rise .9s cubic-bezier(.22,1,.36,1) both}.tops-login__title{margin:0;font-size:clamp(1.15rem,2.4vw,1.45rem);font-weight:700;letter-spacing:.08em;color:var(--panel-title);animation:tops-login-rise .9s .06s cubic-bezier(.22,1,.36,1) both}.tops-login__tagline{margin:.45rem 0 0;font-size:.78rem;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);animation:tops-login-rise .9s .1s cubic-bezier(.22,1,.36,1) both}.tops-login__support{margin:.35rem 0 1.25rem;font-size:.78rem;color:var(--panel-muted);line-height:1.5;max-width:22rem;animation:tops-login-rise .9s .14s cubic-bezier(.22,1,.36,1) both}.tops-login__form{width:100%;display:flex;flex-direction:column;gap:.75rem;padding:1.15rem 1.2rem 1.25rem;border:1px solid var(--panel-border);border-radius:4px;background:#081018e0;box-shadow:0 12px 40px #00000059;text-align:left;animation:tops-login-rise .9s .18s cubic-bezier(.22,1,.36,1) both}.tops-login__form.is-shake{animation:tops-login-shake .45s ease}.tops-login__field{display:flex;flex-direction:column;gap:.35rem}.tops-login__field span{font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;color:var(--panel-muted)}.tops-login__field input{height:2.4rem;padding:0 .75rem;border-radius:2px;border:none;background:#060c14a6;box-shadow:0 0 0 1px #3dbeff47 inset;color:var(--panel-title);outline:none}.tops-login__field input:focus{box-shadow:0 0 0 1px #3dbeffa6 inset,0 0 .6em #3dbeff40}.tops-login__error{margin:0;font-size:.78rem;color:#ffb0b0}.tops-login__submit{margin-top:.25rem;height:2.55rem;border:1px solid rgba(61,190,255,.55);border-radius:2px;background:#3dbeff38;color:#f4fbff;font-weight:700;letter-spacing:.12em;cursor:pointer;transition:background .18s ease,border-color .18s ease}.tops-login__submit:hover:not(:disabled){background:#3dbeff57;border-color:var(--accent)}.tops-login__submit:disabled{opacity:.55;cursor:wait}.tops-login__hint{margin:.15rem 0 0;font-size:.68rem;color:var(--panel-muted);line-height:1.55;text-align:center}.tops-login__hint code{font-family:var(--digital-font);color:var(--accent)}.tops-login__dash{margin-top:.35rem;background:transparent;border:none;color:var(--accent);font-size:.78rem;letter-spacing:.06em;cursor:pointer;text-decoration:underline;opacity:.9}@keyframes tops-login-grid{0%{background-position:0 0,0 0}to{background-position:0 48px,48px 0}}@keyframes tops-login-breathe{0%,to{opacity:.75;transform:translate(-50%) scale(1)}50%{opacity:1;transform:translate(-50%) scale(1.06)}}@keyframes tops-login-rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes tops-login-shake{0%,to{transform:translate(0)}25%{transform:translate(-6px)}75%{transform:translate(6px)}}
@font-face{font-family:AlibabaPuHuiTi-3-115-Black;src:url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.woff2) format("woff2"),url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.woff) format("woff"),url(/fonts/AlibabaPuHuiTi-3-115-Black/AlibabaPuHuiTi-3-115-Black.ttf) format("truetype");font-weight:900;font-style:normal;font-display:swap}:root{--screen-bg: #000b1d;--panel-bg: rgba(0, 18, 42, .55);--panel-border: rgba(0, 247, 255, .22);--panel-title: #f4feff;--panel-muted: #7eb6d6;--text: #d7f4ff;--accent: #00f7ff;--cyan: #00f7ff;--alert: #ff4d4f;--ok: #52c41a;--warn: #faad14;--title-font: "AlibabaPuHuiTi-3-115-Black", "Noto Sans SC", "PingFang SC", sans-serif;--body-font: "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;--digital-font: "Share Tech Mono", ui-monospace, monospace;--bg: var(--screen-bg);--bg-deep: #04080f;--cyan-lt: #7ad8ff;--green: var(--ok);--amber: var(--warn);--red: var(--alert);--title: var(--panel-title);--body: var(--text);--label: var(--panel-muted);--muted: var(--panel-muted);--panel-bd: var(--panel-border);--card-bg: rgba(6, 12, 20, .55);--card-bd: rgba(61, 190, 255, .18);--track: rgba(61, 190, 255, .16);--bar-grad: linear-gradient(90deg, rgba(61, 190, 255, .55), #3dbeff);--font-cn: var(--body-font);--font-num: var(--digital-font);--shadow: 0 6px 20px rgba(0, 0, 0, .22)}*{margin:0;padding:0;box-sizing:border-box}html,body,#app{width:100%;height:100%;overflow:hidden;background:var(--bg-deep)}body{font-family:var(--body-font);font-weight:600;letter-spacing:.02em;color:var(--text);-webkit-font-smoothing:antialiased;font-variant-numeric:tabular-nums}button,input,select,textarea{font:inherit}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-thumb{background:#3dbeff59;border-radius:2px}::-webkit-scrollbar-track{background:transparent}.stage{position:fixed;top:0;right:0;bottom:0;left:0;width:100%;height:100%;max-width:100vw;max-height:100vh;transform:none;display:flex;flex-direction:column;overflow:hidden;background:#00060f;color:var(--text);font-family:var(--body-font);--screen-side-w: clamp(280px, 24vw, 480px)}.stage:before{content:none}.screen-header{position:relative;height:84px;flex:0 0 84px;display:flex;align-items:center;justify-content:space-between;padding:0 24px;border-bottom:1px solid var(--panel-border);background:linear-gradient(90deg,#3dbeff29,#0810188c 42%,#060c1459)}.screen-header:after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:linear-gradient(90deg,var(--accent),transparent 62%);opacity:.85;pointer-events:none}.brand{display:flex;align-items:center;gap:12px}.brand-mark{width:34px;height:34px;border-radius:3px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff8c,#3dbeff0f);box-shadow:0 0 1.1em #3dbeff52;display:grid;place-items:center;color:#eaf4ff;font-weight:700;font-family:var(--digital-font)}.brand-txt .sys{font-size:14px;font-weight:600;color:var(--panel-title);letter-spacing:.04em}.brand-txt .en{font-size:9px;color:var(--accent);letter-spacing:.16em;text-transform:uppercase;font-family:var(--body-font)}.title-group{position:absolute;left:50%;top:18px;transform:translate(-50%);display:flex;align-items:center;gap:18px}.title-group h1{font-size:28px;font-weight:700;letter-spacing:.12em;white-space:nowrap;font-family:var(--title-font);background:linear-gradient(180deg,#fff 20%,#b7d7ff);-webkit-background-clip:text;background-clip:text;color:transparent}.wing{display:flex;align-items:center;gap:8px;height:28px}.wing-line{width:96px;height:3px;border-radius:1px;background:linear-gradient(90deg,transparent 0%,rgba(61,190,255,.15) 20%,#3dbeff 100%);box-shadow:0 0 10px #3dbeff8c;position:relative}.wing-line:before{content:"";position:absolute;left:18%;right:0;top:50%;transform:translateY(-50%);height:1px;background:linear-gradient(90deg,transparent,rgba(255,255,255,.75))}.wing-chevron{width:0;height:0;border-style:solid;border-width:8px 0 8px 12px;border-color:transparent transparent transparent #3dbeff;filter:drop-shadow(0 0 6px rgba(61,190,255,.85));flex:0 0 auto}.wing-dot{width:8px;height:8px;border-radius:50%;background:#7ad8ff;box-shadow:0 0 0 3px #3dbeff38,0 0 12px #3dbeffe6;flex:0 0 auto}.wing.right .wing-line{background:linear-gradient(90deg,#3dbeff 0%,rgba(61,190,255,.15) 80%,transparent 100%)}.wing.right .wing-line:before{left:0;right:18%;background:linear-gradient(90deg,rgba(255,255,255,.75),transparent)}.wing.right .wing-chevron{border-width:8px 12px 8px 0;border-color:transparent #3dbeff transparent transparent}.hdr-status{display:flex;align-items:center;gap:12px}.alarm-badge,.user-chip,.server-chip{display:flex;align-items:center;gap:6px;padding:6px 12px;border-radius:2px;border:1px solid var(--panel-border);background:#060c148c;font-size:12px;letter-spacing:.04em}.alarm-badge{border-color:#e25b5b80;color:#ffb0b0;cursor:pointer}.user-chip{color:var(--text)}.user-chip button{border:none;background:transparent;color:var(--cyan-lt);cursor:pointer;margin-left:4px}.weather-wrap,.clock-wrap{position:absolute;top:50%;transform:translate(-50%,-50%);display:flex;align-items:baseline;gap:10px;white-space:nowrap}.weather-wrap{left:26%}.clock-wrap{left:74%}.weather-wrap .place,.weather-wrap .temp{font-size:18px;font-weight:600;font-family:var(--digital-font);color:var(--ok);line-height:1}.weather-wrap .w-text,.weather-wrap .humid{font-size:12px;color:#7cf0c4;letter-spacing:.04em}.clock-wrap .time{font-size:18px;font-weight:600;font-family:var(--digital-font);color:var(--accent);line-height:1;text-shadow:0 0 .55em rgba(61,190,255,.5)}.clock-wrap .date{font-size:12px;color:var(--panel-muted);letter-spacing:.08em}.dot{width:7px;height:7px;border-radius:50%;background:var(--ok);box-shadow:0 0 #3cba7a99;animation:pulse 2s infinite}.dot.red{background:var(--alert)}@keyframes pulse{0%{box-shadow:0 0 #3cba7a8c}70%{box-shadow:0 0 0 8px #3cba7a00}to{box-shadow:0 0 #3cba7a00}}.screen-nav{height:48px;flex:0 0 48px;display:flex;align-items:center;gap:8px;padding:0 20px}.nav-chip{border-radius:3px;border:1px solid var(--panel-border);background:#060c148c;cursor:pointer;color:var(--panel-muted);padding:6px 12px;font-size:12px;font-weight:600;letter-spacing:.04em;text-decoration:none;transition:.2s}.nav-chip.active,.nav-chip.router-link-active{background:linear-gradient(90deg,#3dbeff59,#3dbeff1f);color:#eaf4ff;border-color:#3dbeff8c}.nav-chip:hover{color:var(--cyan-lt);border-color:#3dbeff73}.nav-spacer{flex:1}.server-chip{color:#7cf0c4;border-color:#3cba7a59}.screen-main{flex:1;min-height:0;display:flex;gap:14px;padding:0 20px 14px}.panel{background:var(--panel-bg);border:1px solid var(--panel-border);border-radius:4px;padding:14px;box-shadow:var(--shadow)}.panel-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px;flex:0 0 auto}.panel-title{display:flex;align-items:center;gap:8px}.panel-title .vbar{width:2px;height:14px;border-radius:1px;background:var(--accent);box-shadow:0 0 .5em var(--accent)}.panel-title h3{font-size:14px;font-weight:700;color:var(--panel-title);letter-spacing:.08em;text-transform:uppercase;font-family:var(--title-font)}.badge{padding:2px 8px;border-radius:2px;font-size:10px;letter-spacing:.06em;text-transform:uppercase;background:#3cba7a1f;color:var(--ok)}.badge.amber{background:#e0a04a26;color:var(--warn)}.badge.red{background:#e25b5b26;color:#ffb0b0}.metric-grid{display:grid;grid-template-columns:1fr 1fr;gap:8px}.metric{display:flex;align-items:center;gap:8px;padding:10px;min-height:64px;border-radius:4px;background:var(--card-bg);border:1px solid var(--card-bd)}.metric .m-label{font-size:11px;color:var(--panel-muted);letter-spacing:.06em;text-transform:uppercase}.metric .m-value{font-size:20px;font-weight:600;font-family:var(--digital-font);color:#fff}.metric .m-value.green{color:var(--ok)}.kpi-bar{height:108px;flex:0 0 108px;display:flex;gap:14px;padding:0 20px 16px}.kpi{flex:1;padding:12px;border-radius:4px;background:var(--panel-bg);border:1px solid var(--panel-border);display:flex;flex-direction:column;justify-content:center;gap:6px}.kpi .k-label{font-size:11px;color:var(--panel-muted);letter-spacing:.06em;text-transform:uppercase}.kpi .digital{align-self:flex-start;padding:3px 10px;border-radius:2px;background:#060c14e6;border:1px solid rgba(61,190,255,.45);font-size:20px;font-weight:600;font-family:var(--digital-font);color:var(--accent)}.kpi .k-trend{font-size:10px;color:var(--warn)}.kpi .k-trend.green{color:var(--ok)}.kpi .k-trend.cyan{color:var(--cyan-lt)}.btn{border:1px solid rgba(61,190,255,.45);background:#3dbeff24;color:#e8f4ff;border-radius:2px;padding:8px 14px;cursor:pointer;font-weight:600;letter-spacing:.04em}.btn:hover{background:#3dbeff47;border-color:var(--accent)}.btn:disabled{opacity:.45;cursor:not-allowed}.btn.danger{border-color:#e25b5b80;background:#e25b5b33;color:#ffe8e8}.btn.ghost{background:transparent}.table{width:100%;border-collapse:collapse;font-size:12px}.table th,.table td{padding:8px 10px;border-bottom:1px solid rgba(61,190,255,.16);text-align:left}.table th{color:var(--panel-muted);font-weight:600;letter-spacing:.05em;text-transform:uppercase;font-size:11px;background:#060c1459}.table td{color:var(--text)}.table tbody tr:hover td{background:#3dbeff14}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:12px}.field{display:flex;flex-direction:column;gap:6px}.field label{font-size:12px;color:var(--panel-muted);letter-spacing:.04em;font-weight:600}.field input,.field select,.field textarea{height:36px;border-radius:2px;padding:0 10px;border:none;box-shadow:0 0 0 1px #3dbeff47 inset;background:#060c14a6;color:var(--panel-title);outline:none}.field textarea{height:auto;padding:8px 10px}.field input:focus,.field select:focus,.field textarea:focus{box-shadow:0 0 0 1px #3dbeffa6 inset}.page-fill{flex:1;min-height:0;display:flex;flex-direction:column;gap:14px;width:100%;height:100%;pointer-events:auto}.page-fill>.panel{min-height:0}.stub-box{flex:1;display:grid;place-items:center;border-radius:4px;border:1px solid var(--panel-border);background:#081018b8;text-align:center;padding:40px}.stub-box h2{font-size:24px;color:var(--panel-title);margin-bottom:10px;letter-spacing:.08em;font-family:var(--title-font)}.stub-box p{font-size:13px;color:var(--panel-muted);line-height:1.8;max-width:560px}.mono{font-family:var(--digital-font);font-variant-numeric:tabular-nums}.tops-root{box-sizing:border-box;width:100%;height:100%;min-height:0;display:flex;flex-direction:column;gap:.6em;padding:.6em .75em .75em;overflow:hidden;background:radial-gradient(ellipse at 18% -8%,rgba(61,190,255,.14),transparent 48%),radial-gradient(ellipse at 92% 108%,rgba(226,91,91,.08),transparent 42%),linear-gradient(rgba(61,190,255,.035) 1px,transparent 1px),linear-gradient(90deg,rgba(61,190,255,.035) 1px,transparent 1px),var(--screen-bg);background-size:100% 100%,100% 100%,2.8em 2.8em,2.8em 2.8em,auto;color:var(--text);font-family:var(--body-font)}.tops-tone--ok{--tone: var(--ok)}.tops-tone--accent{--tone: var(--accent)}.tops-tone--warn{--tone: var(--warn)}.tops-tone--alert{--tone: var(--alert)}.tops-tone--muted{--tone: var(--panel-muted)}.tops-header{position:relative;flex:none;display:flex;align-items:center;gap:.9em;padding:.5em .85em;border:1px solid var(--panel-border);border-radius:4px;overflow:hidden;background:linear-gradient(90deg,#3dbeff2e,#081018db 42%,#060c14eb)}.tops-header:after{content:"";position:absolute;left:0;right:0;bottom:0;height:1px;background:linear-gradient(90deg,var(--accent),transparent 62%);opacity:.85}.tops-brand{display:flex;align-items:center;gap:.55em;min-width:0;cursor:pointer}.tops-brand__mark{flex:none;width:2.1em;height:2.1em;display:grid;place-items:center;border-radius:3px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff8c,#3dbeff0f);box-shadow:0 0 1.1em #3dbeff52,inset 0 0 .8em #3dbeff38;color:#eaf4ff}.tops-brand__mark :deep(svg),.tops-brand__mark svg{width:1.3em;height:1.3em}.tops-brand__copy{display:flex;flex-direction:column;gap:.1em;min-width:0}.tops-brand__copy strong{font-size:1.04em;font-weight:600;letter-spacing:.02em;color:var(--panel-title);white-space:nowrap}.tops-brand__copy small{font-size:.62em;letter-spacing:.16em;text-transform:uppercase;color:var(--panel-muted);white-space:nowrap}.tops-header__chips{display:flex;flex-wrap:wrap;align-items:center;gap:.4em;min-width:0}.tops-chip{display:inline-flex;align-items:center;gap:.42em;padding:.24em .48em;border:1px solid var(--panel-border);border-radius:2px;background:#060c148c;white-space:nowrap}.tops-chip small{font-size:.6em;letter-spacing:.06em;text-transform:uppercase;color:var(--panel-muted)}.tops-chip b{font-size:.76em;font-weight:600;color:var(--panel-title);font-family:var(--digital-font)}.tops-dot{width:.42em;height:.42em;border-radius:50%;background:var(--tone, var(--ok));box-shadow:0 0 .45em var(--tone, var(--ok))}.tops-header__end{margin-left:auto;display:flex;align-items:center;gap:.7em}.tops-clock{display:flex;flex-direction:column;align-items:flex-end;line-height:1.1}.tops-clock small{font-size:.6em;letter-spacing:.12em;color:var(--panel-muted)}.tops-clock b{font-family:var(--digital-font);font-size:1.18em;font-weight:600;color:var(--accent);text-shadow:0 0 .55em rgba(61,190,255,.5)}.tops-logout{font:inherit;font-size:.68em;font-weight:600;letter-spacing:.06em;padding:.38em .75em;border:1px solid var(--panel-border);border-radius:3px;background:#060c148c;color:var(--panel-muted);cursor:pointer;transition:color .18s ease,border-color .18s ease,background .18s ease;text-decoration:none}.tops-logout:hover:not(:disabled){color:var(--panel-title);border-color:#3dbeff8c;background:#3dbeff24}.tops-body{flex:1;min-height:0;display:flex;gap:.6em}.tops-main{flex:1;min-width:0;min-height:0;overflow:auto;display:flex;flex-direction:column}.tops-side{flex:none;width:13.4em;display:flex;flex-direction:column;gap:.45em;padding:.6em .55em;border:1px solid var(--panel-border);border-radius:4px;background:linear-gradient(180deg,#081018f0,#060c14f0)}.tops-side__head{display:flex;align-items:baseline;justify-content:space-between;gap:.4em;padding:0 .2em .45em;border-bottom:1px solid var(--panel-border)}.tops-side__head strong{font-size:.82em;font-weight:600;letter-spacing:.06em;color:var(--panel-title)}.tops-side__head small{font-size:.64em;letter-spacing:.12em;color:var(--panel-muted)}.tops-menu{flex:1;min-height:0;display:flex;flex-direction:column;gap:.42em;padding-top:.1em;overflow-y:auto}.tops-menu__item{position:relative;display:flex;align-items:center;gap:.6em;width:100%;padding:.55em .6em .55em .75em;font:inherit;text-align:left;text-decoration:none;color:var(--text);border:1px solid var(--panel-border);border-radius:3px;background:linear-gradient(180deg,#081018e0,#060c14e0);cursor:pointer;transition:border-color .2s ease,background .2s ease,transform .2s ease;box-sizing:border-box}.tops-menu__item:before{content:"";position:absolute;left:0;top:.35em;bottom:.35em;width:2px;border-radius:1px;background:transparent;transition:background .2s ease,box-shadow .2s ease}.tops-menu__item:hover{transform:translate(2px);border-color:#3dbeff73;background:linear-gradient(180deg,#3dbeff29,#060c14e6)}.tops-menu__item.router-link-active,.tops-menu__item.is-on{border-color:#3dbeff99;background:linear-gradient(90deg,#3dbeff47,#081018b8 72%)}.tops-menu__item.router-link-active:before,.tops-menu__item.is-on:before{background:var(--accent);box-shadow:0 0 .6em var(--accent)}.tops-menu__icon{flex:none;width:1.7em;height:1.7em;display:grid;place-items:center;border-radius:3px;border:1px solid rgba(61,190,255,.28);color:var(--panel-muted);background:#060c148c}.tops-menu__item.router-link-active .tops-menu__icon{color:var(--accent);border-color:#3dbeff80}.tops-menu__icon svg{width:1em;height:1em}.tops-menu__copy{display:flex;flex-direction:column;gap:.12em;min-width:0}.tops-menu__label{font-size:.82em;font-weight:600;color:var(--panel-title)}.tops-menu__hint{font-size:.58em;letter-spacing:.04em;color:var(--panel-muted)}.tops-side__foot{display:flex;align-items:center;gap:.45em;padding:.35em .2em 0;border-top:1px solid var(--panel-border);font-size:.62em;letter-spacing:.08em;color:var(--panel-muted)}.tops-login{position:relative;isolation:isolate;width:100%;height:100%;min-height:100vh;overflow:hidden;display:grid;place-items:center;background:radial-gradient(120% 90% at 50% -10%,#123048,#081018 52%,#04080f);color:var(--text);font-family:var(--body-font);font-weight:600;letter-spacing:.02em}.tops-login__atmosphere{position:absolute;top:0;right:0;bottom:0;left:0;z-index:0;pointer-events:none}.tops-login__grid{position:absolute;top:18%;right:-10%;bottom:-28%;left:-10%;background-image:linear-gradient(rgba(61,190,255,.16) 1px,transparent 1px),linear-gradient(90deg,rgba(61,190,255,.16) 1px,transparent 1px);background-size:48px 48px;transform:perspective(720px) rotateX(58deg);transform-origin:50% 0%;-webkit-mask-image:linear-gradient(180deg,transparent 0%,#000 28%,#000 72%,transparent 100%);mask-image:linear-gradient(180deg,transparent 0%,#000 28%,#000 72%,transparent 100%);animation:tops-login-grid 18s linear infinite;opacity:.55}.tops-login__glow{position:absolute;border-radius:50%;filter:blur(48px)}.tops-login__glow--a{width:min(48vw,520px);height:min(48vw,520px);left:50%;top:12%;transform:translate(-50%);background:radial-gradient(circle,rgba(61,190,255,.28),transparent 68%);animation:tops-login-breathe 5.5s ease-in-out infinite}.tops-login__glow--b{width:min(36vw,380px);height:min(36vw,380px);left:50%;top:42%;transform:translate(-50%);background:radial-gradient(circle,rgba(242,230,168,.12),transparent 70%)}.tops-login__horizon{position:absolute;left:10%;right:10%;top:58%;height:1px;background:linear-gradient(90deg,transparent,rgba(61,190,255,.55),transparent);opacity:.7}.tops-login__stage{position:relative;z-index:1;width:min(28rem,calc(100vw - 2.5rem));display:flex;flex-direction:column;align-items:center;text-align:center;padding:1.25rem 0 2rem}.tops-login__mark{width:4.2rem;height:4.2rem;display:grid;place-items:center;border-radius:8px;border:1px solid rgba(61,190,255,.55);background:radial-gradient(circle at 30% 25%,#3dbeff80,#3dbeff0f);box-shadow:0 0 1.4em #3dbeff59;color:#eaf4ff;font-size:1.4rem;font-weight:700;letter-spacing:.08em;margin-bottom:1rem;animation:tops-login-rise .9s cubic-bezier(.22,1,.36,1) both}.tops-login__title{margin:0;font-size:clamp(1.15rem,2.4vw,1.45rem);font-weight:700;letter-spacing:.08em;color:var(--panel-title);animation:tops-login-rise .9s .06s cubic-bezier(.22,1,.36,1) both}.tops-login__tagline{margin:.45rem 0 0;font-size:.78rem;letter-spacing:.18em;text-transform:uppercase;color:var(--accent);animation:tops-login-rise .9s .1s cubic-bezier(.22,1,.36,1) both}.tops-login__support{margin:.35rem 0 1.25rem;font-size:.78rem;color:var(--panel-muted);line-height:1.5;max-width:22rem;animation:tops-login-rise .9s .14s cubic-bezier(.22,1,.36,1) both}.tops-login__form{width:100%;display:flex;flex-direction:column;gap:.75rem;padding:1.15rem 1.2rem 1.25rem;border:1px solid var(--panel-border);border-radius:4px;background:#081018e0;box-shadow:0 12px 40px #00000059;text-align:left;animation:tops-login-rise .9s .18s cubic-bezier(.22,1,.36,1) both}.tops-login__form.is-shake{animation:tops-login-shake .45s ease}.tops-login__field{display:flex;flex-direction:column;gap:.35rem}.tops-login__field span{font-size:.68rem;letter-spacing:.1em;text-transform:uppercase;color:var(--panel-muted)}.tops-login__field input{height:2.4rem;padding:0 .75rem;border-radius:2px;border:none;background:#060c14a6;box-shadow:0 0 0 1px #3dbeff47 inset;color:var(--panel-title);outline:none}.tops-login__field input:focus{box-shadow:0 0 0 1px #3dbeffa6 inset,0 0 .6em #3dbeff40}.tops-login__error{margin:0;font-size:.78rem;color:#ffb0b0}.tops-login__submit{margin-top:.25rem;height:2.55rem;border:1px solid rgba(61,190,255,.55);border-radius:2px;background:#3dbeff38;color:#f4fbff;font-weight:700;letter-spacing:.12em;cursor:pointer;transition:background .18s ease,border-color .18s ease}.tops-login__submit:hover:not(:disabled){background:#3dbeff57;border-color:var(--accent)}.tops-login__submit:disabled{opacity:.55;cursor:wait}.tops-login__hint{margin:.15rem 0 0;font-size:.68rem;color:var(--panel-muted);line-height:1.55;text-align:center}.tops-login__hint code{font-family:var(--digital-font);color:var(--accent)}.tops-login__dash{margin-top:.35rem;background:transparent;border:none;color:var(--accent);font-size:.78rem;letter-spacing:.06em;cursor:pointer;text-decoration:underline;opacity:.9}@keyframes tops-login-grid{0%{background-position:0 0,0 0}to{background-position:0 48px,48px 0}}@keyframes tops-login-breathe{0%,to{opacity:.75;transform:translate(-50%) scale(1)}50%{opacity:1;transform:translate(-50%) scale(1.06)}}@keyframes tops-login-rise{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@keyframes tops-login-shake{0%,to{transform:translate(0)}25%{transform:translate(-6px)}75%{transform:translate(6px)}}
import{p as y,r as c,B as u}from"./index-Bs_x-_cK.js";const g={ts:0,rooms:[],hvac:{systemRunning:!1,supplyFanHz:0,exhaustPressure:0,filterRemainPct:0,mode:"auto",supplyTemp:0,supplyHumidity:0,supplyPressure:0,freshAirTemp:0,alarms:[]},vav:[],fridges:[],neLights:[],metering:{powerKwh:0,waterM3:0,coolingKwh:0,powerTrendPct:0,waterTrendPct:0,coolingTrendPct:0},access:{doors:[],todayPassCount:0,recentEvents:[]},online:{devicesOnline:0,devicesTotal:0,gatewayOk:!1},pointAlarms:[]},T=y("realtime",()=>{const t=c(g),n=c(!1),r=c("sample-1");let e=null,a;const m=u(()=>{if(Array.isArray(t.value.pointAlarms))return t.value.pointAlarms.length;const o=t.value.rooms.reduce((s,h)=>s+h.alarms.length,0),l=t.value.fridges.filter(s=>s.temp>-19).length;return o+l+t.value.hvac.alarms.length}),p=u(()=>t.value.rooms.find(o=>o.id===r.value)||t.value.rooms[0]||{id:"-",name:"-",temp:0,humidity:0,pressure:0,alarms:[]});function d(o){r.value=o}function f(o){t.value=o}function i(){const o=`${location.protocol==="https:"?"wss":"ws"}://${location.host}/ws`;e==null||e.close(),e=new WebSocket(o),e.onopen=()=>{n.value=!0},e.onmessage=l=>{try{const s=JSON.parse(l.data);s.type==="snapshot"&&(t.value=s.data)}catch{}},e.onclose=()=>{n.value=!1,window.clearTimeout(a),a=window.setTimeout(i,2e3)},e.onerror=()=>e==null?void 0:e.close()}function v(){window.clearTimeout(a),e==null||e.close(),e=null}return{snapshot:t,connected:n,selectedRoomId:r,alarmCount:m,primaryRoom:p,selectRoom:d,setSnapshot:f,connect:i,disconnect:v}});export{T as u};
import{B as y,r as c,s as u}from"./index-BssDqbym.js";const g={ts:0,rooms:[],hvac:{systemRunning:!1,supplyFanHz:0,exhaustPressure:0,filterRemainPct:0,mode:"auto",supplyTemp:0,supplyHumidity:0,supplyPressure:0,freshAirTemp:0,alarms:[]},vav:[],fridges:[],neLights:[],metering:{powerKwh:0,waterM3:0,coolingKwh:0,powerTrendPct:0,waterTrendPct:0,coolingTrendPct:0},access:{doors:[],todayPassCount:0,recentEvents:[]},online:{devicesOnline:0,devicesTotal:0,gatewayOk:!1},pointAlarms:[]},T=y("realtime",()=>{const t=c(g),n=c(!1),r=c("sample-1");let e=null,a;const m=u(()=>{if(Array.isArray(t.value.pointAlarms))return t.value.pointAlarms.length;const o=t.value.rooms.reduce((s,h)=>s+h.alarms.length,0),l=t.value.fridges.filter(s=>s.temp>-19).length;return o+l+t.value.hvac.alarms.length}),p=u(()=>t.value.rooms.find(o=>o.id===r.value)||t.value.rooms[0]||{id:"-",name:"-",temp:0,humidity:0,pressure:0,alarms:[]});function d(o){r.value=o}function f(o){t.value=o}function i(){const o=`${location.protocol==="https:"?"wss":"ws"}://${location.host}/ws`;e==null||e.close(),e=new WebSocket(o),e.onopen=()=>{n.value=!0},e.onmessage=l=>{try{const s=JSON.parse(l.data);s.type==="snapshot"&&(t.value=s.data)}catch{}},e.onclose=()=>{n.value=!1,window.clearTimeout(a),a=window.setTimeout(i,2e3)},e.onerror=()=>e==null?void 0:e.close()}function v(){window.clearTimeout(a),e==null||e.close(),e=null}return{snapshot:t,connected:n,selectedRoomId:r,alarmCount:m,primaryRoom:p,selectRoom:d,setSnapshot:f,connect:i,disconnect:v}});export{T as u};
import{y as o}from"./index-BssDqbym.js";function e(t,n){return String(o.global.t(t,n))}function l(t){if(t==null||t==="")return"—";const n=String(o.global.locale.value),r=n==="zh-CN"?"zh-CN":n==="zh-TW"?"zh-TW":n==="pt"?"pt-PT":"en-US";return new Date(t).toLocaleString(r,{hour12:!1})}export{l as f,e as t};
import{j as w,k as $,l as d,m as g,r as u}from"./index-BssDqbym.js";function n(t){return t<10?`0${t}`:`${t}`}function k(){const{tm:t,locale:l}=w(),a=u("--:--:--"),s=u("");let r;function o(){const e=new Date;a.value=`${n(e.getHours())}:${n(e.getMinutes())}:${n(e.getSeconds())}`;const c=t("weekdays"),i=Array.isArray(c)&&c[e.getDay()]||"";s.value=`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${i}`}return $(l,()=>o()),d(()=>{o(),r=window.setInterval(o,1e3)}),g(()=>window.clearInterval(r)),{time:a,date:s}}export{k as u};
import{j as s,k as c,r as u}from"./index-Bs_x-_cK.js";const i=["星期日","星期一","星期二","星期三","星期四","星期五","星期六"];function n(t){return t<10?`0${t}`:`${t}`}function $(){const t=u("--:--:--"),o=u("");let a;function r(){const e=new Date;t.value=`${n(e.getHours())}:${n(e.getMinutes())}:${n(e.getSeconds())}`,o.value=`${e.getFullYear()}-${n(e.getMonth()+1)}-${n(e.getDate())} ${i[e.getDay()]}`}return s(()=>{r(),a=window.setInterval(r,1e3)}),c(()=>window.clearInterval(a)),{time:t,date:o}}export{$ as u};
import{l as f,C as m,k as v,p as d,r as n}from"./index-BssDqbym.js";function p(i,u=6e4){const c=n([]),s=n(!1),a=n("");let o;async function r(){const e=i();if(!(!e.source||!e.metric)){s.value=!0,a.value="";try{const t=new URLSearchParams({source:e.source,metric:e.metric,hours:String(e.hours??24),bucketMinutes:String(e.bucketMinutes??60)}),l=await d(`/api/realtime/history?${t}`);c.value=l.series||[]}catch(t){a.value=t instanceof Error?t.message:"历史加载失败"}finally{s.value=!1}}}return f(()=>{r(),o=window.setInterval(()=>void r(),u)}),m(()=>{o&&window.clearInterval(o)}),v(i,()=>void r(),{deep:!0}),{series:c,loading:s,error:a,refresh:r}}export{p as u};
import{j as f,s as m,q as v,l as d,r as n}from"./index-Bs_x-_cK.js";function w(i,u=6e4){const c=n([]),t=n(!1),a=n("");let o;async function r(){const e=i();if(!(!e.source||!e.metric)){t.value=!0,a.value="";try{const s=new URLSearchParams({source:e.source,metric:e.metric,hours:String(e.hours??24),bucketMinutes:String(e.bucketMinutes??15)}),l=await d(`/api/realtime/history?${s}`);c.value=l.series||[]}catch(s){a.value=s instanceof Error?s.message:"历史加载失败"}finally{t.value=!1}}}return f(()=>{r(),o=window.setInterval(()=>void r(),u)}),m(()=>{o&&window.clearInterval(o)}),v(i,()=>void r(),{deep:!0}),{series:c,loading:t,error:a,refresh:r}}export{w as u};
import{t as l}from"./t-ChxyHC3f.js";import{C as ye,r as ke}from"./index-BssDqbym.js";const Ve={pressure:"Speedometer.png",lightN:"electricity-meter-blue.png",lightE:"electricity-meter-orange.png",fridge:"temperature-sensor-orange.png",vav:"motor-green.png"},ze={pressure:"pressure",lightN:"lightN",lightE:"lightE",fridge:"fridge",vav:"vav",camera:"camera",access:"access"},Ue=.5,ve=[{id:"home",label:"全景总览"},{id:"camera",label:"监控"},{id:"access",label:"门禁"},{id:"pressure",label:"压差"},{id:"lightN",label:"普通照明"},{id:"lightE",label:"应急照明"},{id:"fridge",label:"冰箱"},{id:"vav",label:"通风柜"},{id:"e066",label:"E栋1F066冰箱"}],qe=ve.filter(o=>o.id!=="e066"&&o.id!=="home"),L={lon:133.54299724844427,lat:22.19728530602825,h:51},z={lon:133.54308017687475,lat:22.19712618090024,h:51};function Ie(o,a){return{x:L.lon+o*(z.lon-L.lon),y:L.lat+a*(z.lat-L.lat),z:L.h+a*(z.h-L.h)}}function m(o,a,s){return{...o,...Ie(a,s)}}const we=[m({id:"p-seq",mode:"pressure",label:"测序区",roomHint:"测序区",bind:{kind:"room",roomId:"seq"}},.1,.58),m({id:"p-seq-buf",mode:"pressure",label:"测序区缓冲",roomHint:"测序区缓冲",bind:{kind:"room",roomId:"seq-buf"}},.1,.3),m({id:"p-lib-2",mode:"pressure",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"room",roomId:"lib-2"}},.25,.58),m({id:"p-lib-2-buf",mode:"pressure",label:"文库制备区2缓冲",roomHint:"文库制备区2缓冲",bind:{kind:"room",roomId:"lib-2-buf"}},.25,.3),m({id:"p-lib-1",mode:"pressure",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"room",roomId:"lib-1"}},.4,.58),m({id:"p-lib-1-buf",mode:"pressure",label:"文库制备区1缓冲",roomHint:"文库制备区1缓冲",bind:{kind:"room",roomId:"lib-1-buf"}},.4,.3),m({id:"p-sample-2",mode:"pressure",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"room",roomId:"sample-2"}},.55,.58),m({id:"p-sample-1",mode:"pressure",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"room",roomId:"sample-1"}},.68,.58),m({id:"p-sample-buf",mode:"pressure",label:"样本制备区缓冲",roomHint:"样本制备区缓冲",bind:{kind:"room",roomId:"sample-buf"}},.66,.3),m({id:"p-recv",mode:"pressure",label:"收样咨询室",roomHint:"咨询室",bind:{kind:"room",roomId:"recv"}},.88,.88),m({id:"p-reagent",mode:"pressure",label:"试剂准备间",roomHint:"准备区",bind:{kind:"room",roomId:"reagent"}},.85,.58),m({id:"p-report",mode:"pressure",label:"生信分析报告室",roomHint:"报告室",bind:{kind:"room",roomId:"report"}},.88,.38),m({id:"p-pcr",mode:"pressure",label:"PCR走廊",roomHint:"PCR走廊",bind:{kind:"room",roomId:"pcr-corridor"}},.42,.12)],Ee=[m({id:"ln-seq",mode:"lightN",label:"测序区",roomHint:"测序区",bind:{kind:"neLight",lightId:"n-seq"}},.1,.52),m({id:"ln-lib-2",mode:"lightN",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"neLight",lightId:"n-lib-2"}},.27,.42),m({id:"ln-lib-1",mode:"lightN",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"neLight",lightId:"n-lib-1"}},.38,.52),m({id:"ln-sample-2",mode:"lightN",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"neLight",lightId:"n-sample-2"}},.55,.52),m({id:"ln-sample-1",mode:"lightN",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"neLight",lightId:"n-sample-1"}},.7,.52),m({id:"ln-report",mode:"lightN",label:"报告室",roomHint:"报告室",bind:{kind:"neLight",lightId:"n-report"}},.88,.4),m({id:"ln-corridor",mode:"lightN",label:"NGS走廊",roomHint:"PCR走廊",bind:{kind:"neLight",lightId:"n-corridor"}},.5,.12)],Ne=[m({id:"le-seq-buf",mode:"lightE",label:"测序区缓冲",roomHint:"测序区缓冲",bind:{kind:"neLight",lightId:"e-seq-buf"}},.1,.3),m({id:"le-seq",mode:"lightE",label:"测序区",roomHint:"测序区",bind:{kind:"neLight",lightId:"e-seq"}},.1,.55),m({id:"le-lib-2-buf",mode:"lightE",label:"文库制备区2缓冲",roomHint:"文库制备区2缓冲",bind:{kind:"neLight",lightId:"e-lib-2-buf"}},.25,.3),m({id:"le-lib-2",mode:"lightE",label:"文库制备区2",roomHint:"文库制备区2",bind:{kind:"neLight",lightId:"e-lib-2"}},.25,.55),m({id:"le-lib-1-buf",mode:"lightE",label:"文库制备区1缓冲",roomHint:"文库制备区1缓冲",bind:{kind:"neLight",lightId:"e-lib-1-buf"}},.4,.3),m({id:"le-lib-1",mode:"lightE",label:"文库制备区1",roomHint:"文库制备区1",bind:{kind:"neLight",lightId:"e-lib-1"}},.4,.55),m({id:"le-sample-1-buf",mode:"lightE",label:"样本制备区1缓冲",roomHint:"样本制备区缓冲",bind:{kind:"neLight",lightId:"e-sample-1-buf"}},.66,.3),m({id:"le-sample-2",mode:"lightE",label:"样本制备区2",roomHint:"样本制备区2",bind:{kind:"neLight",lightId:"e-sample-2"}},.55,.55),m({id:"le-sample-1",mode:"lightE",label:"样本制备区1",roomHint:"样本制备区1",bind:{kind:"neLight",lightId:"e-sample-1"}},.68,.55),m({id:"le-report",mode:"lightE",label:"报告室",roomHint:"报告室",bind:{kind:"neLight",lightId:"e-report"}},.88,.38),m({id:"le-prep",mode:"lightE",label:"准备间",roomHint:"准备区",bind:{kind:"neLight",lightId:"e-prep"}},.85,.58),m({id:"le-recv",mode:"lightE",label:"咨询室",roomHint:"咨询室",bind:{kind:"neLight",lightId:"e-recv"}},.88,.88),m({id:"le-corridor",mode:"lightE",label:"走廊",roomHint:"PCR走廊",bind:{kind:"neLight",lightId:"e-corridor"}},.35,.12)],He=[m({id:"f-recv-1",mode:"fridge",label:"收样咨询室冰箱1",roomHint:"咨询室",bind:{kind:"fridge",deviceId:"mb-104-rtu-3-收样咨询室冰箱1"}},.86,.82),m({id:"f-recv-2",mode:"fridge",label:"收样咨询室冰箱2",roomHint:"咨询室",bind:{kind:"fridge",deviceId:"mb-104-rtu-4-收样咨询室冰箱2"}},.9,.82),m({id:"f-lib-1",mode:"fridge",label:"文库制备区1冰箱",roomHint:"文库制备区1",bind:{kind:"fridge",deviceId:"mb-104-rtu-6-文库制备区1冰箱"}},.42,.4),m({id:"f-lib-2",mode:"fridge",label:"文库制备区2冰箱",roomHint:"文库制备区2",bind:{kind:"fridge",deviceId:"mb-104-rtu-7-文库制备区2冰箱"}},.27,.4),m({id:"f-sample-1",mode:"fridge",label:"样本制备区1冰箱",roomHint:"样本制备区1",bind:{kind:"fridge",deviceId:"mb-104-rtu-5-样本制备区1冰箱"}},.7,.42),m({id:"f-seq",mode:"fridge",label:"测序区冰箱1",roomHint:"测序区",bind:{kind:"fridge",deviceId:"mb-104-rtu-8-测序区冰箱1"}},.12,.4),m({id:"f-reagent-1",mode:"fridge",label:"试剂准备间冰箱1",roomHint:"准备区",bind:{kind:"fridge",deviceId:"mb-104-rtu-1-试剂准备间冰箱1"}},.83,.55),m({id:"f-reagent-2",mode:"fridge",label:"试剂准备间冰箱2",roomHint:"准备区",bind:{kind:"fridge",deviceId:"mb-104-rtu-2-试剂准备间冰箱2"}},.87,.55)],Ce=[m({id:"v-lib-1",mode:"vav",label:"文库制备1通风柜",roomHint:"文库制备区1",bind:{kind:"vav",deviceId:"mb-103-文库制备1通风柜"}},.4,.78),m({id:"v-lib-2",mode:"vav",label:"文库制备2通风柜",roomHint:"文库制备区2",bind:{kind:"vav",deviceId:"mb-103-文库制备2通风柜"}},.25,.78)],A=[...we,...Ee,...Ne,...He,...Ce];function Ge(o){return o==="e066"||o==="camera"||o==="access"?[]:o==="home"?A:A.filter(a=>a.mode===o)}const Le=[{prefix:"监控-",mode:"camera"},{prefix:"门禁-",mode:"access"},{prefix:"压差-",mode:"pressure"},{prefix:"普通照明-",mode:"lightN"},{prefix:"应急照明-",mode:"lightE"},{prefix:"冰箱-",mode:"fridge"},{prefix:"通风柜-",mode:"vav"}],Pe=[{test:/cctv/i,mode:"camera"},{test:/access-control/i,mode:"access"},{test:/speedometer/i,mode:"pressure"},{test:/electricity-meter-blue/i,mode:"lightN"},{test:/electricity-meter-orange/i,mode:"lightE"},{test:/temperature-sensor/i,mode:"fridge"},{test:/motor-green|moter-green/i,mode:"vav"}];function Se(o){const a=(o.name||"").trim();for(const n of Le)if(a.startsWith(n.prefix))return n.mode;const s=(o.tag0||"").trim();if(s==="screen-mode"&&o.tag1){const n=A.find(f=>f.id===o.tag1);if(n)return n.mode}const i=s.toLowerCase();if(i==="camera")return"camera";if(i==="access")return"access";if(s==="pressure"||s==="lightN"||s==="lightE"||s==="fridge"||s==="vav")return s;const c=o.icon||"";for(const n of Pe)if(n.test.test(c))return n.mode;return null}function Me(o,a){const s=o.replace(/^(压差|普通照明|应急照明|冰箱|通风柜)-/,"").trim(),i=A.filter(b=>b.mode===a),c=i.find(b=>b.label===s||b.label===o||b.roomHint===s);if(c)return c;let n,f=0;for(const b of i)for(const v of[b.label,b.roomHint]){if(!v)continue;let I=0;s===v?I=100+v.length:s.includes(v)?I=v.length:v.includes(s)&&s.length>=2&&(I=s.length),I>f&&(f=I,n=b)}return n}function ee(o){const a=`doorStatus.${o}`,s=l(a);return s===a?o:s}function Re(o,a){var c;const s=o.bind;if(s.kind==="room"){const n=a.rooms.find(b=>b.id===s.roomId),f=[{label:l("metrics.temp"),value:`${p(n==null?void 0:n.temp)} ℃`},{label:l("metrics.humidity"),value:`${p(n==null?void 0:n.humidity,0)} %`},{label:l("metrics.pressure"),value:`${p(n==null?void 0:n.pressure)} Pa`}];return(c=n==null?void 0:n.alarms)!=null&&c.length&&f.push({label:l("metrics.alarm"),value:n.alarms.join("、")}),f}if(s.kind==="fridge"){const n=a.fridges.find(f=>f.id===s.deviceId);return[{label:l("metrics.temp"),value:`${p(n==null?void 0:n.temp)} ℃`},{label:l("metrics.humidity"),value:`${p(n==null?void 0:n.humidity,0)} %`}]}if(s.kind==="vav"){const n=a.vav.find(f=>f.id===s.deviceId);return[{label:l("metrics.status"),value:n?n.running?l("screen.running"):l("screen.stopped"):"--"},{label:l("metrics.faceVelocity"),value:`${p(n==null?void 0:n.faceVelocity)} m/s`},{label:l("metrics.sashHeight"),value:`${p(n==null?void 0:n.sashHeight)} mm`},{label:l("metrics.airflow"),value:`${p(n==null?void 0:n.airflow,0)} m³/h`},{label:l("metrics.valveOpen"),value:`${p(n==null?void 0:n.valveOpen,0)} %`},{label:l("metrics.maxExhaust"),value:n?n.maxExhaust?l("metrics.yes"):l("metrics.no"):"--"},{label:l("metrics.minAirflow"),value:n?n.minAirflow?l("metrics.yes"):l("metrics.no"):"--"},{label:l("metrics.alarmCode"),value:n?n.alarmCode?String(n.alarmCode):l("metrics.none"):"--"}]}const i=(a.neLights||[]).find(n=>n.id===s.lightId);return[{label:l("metrics.area"),value:o.roomHint||o.label},{label:l("metrics.status"),value:i?i.on?l("screen.switchOn"):l("screen.switchOff"):"--"}]}function We(o,a){var I,H,E,P,S,$,M,R,_;const s=(o.tag1||"").trim(),i=s&&((I=a.sensors)!=null&&I.length)?a.sensors.find(h=>h.id===s||h.code===s):void 0;if(i){if(i.category==="lightN"||i.category==="lightE")return{title:i.name,lines:[{label:l("metrics.type"),value:l(i.category==="lightN"?"modes.lightN":"modes.lightE")},{label:l("metrics.status"),value:i.on==null?"--":i.on?l("screen.switchOn"):l("screen.switchOff")}]};if(i.category==="fridge"){const g=[{label:l("metrics.temp"),value:`${p(i.values.temp)} ℃`},{label:l("metrics.humidity"),value:`${p(i.values.humidity,0)} %`}];return(H=i.alarms)!=null&&H.length&&g.push({label:l("metrics.alarm"),value:i.alarms.join("、")}),{title:i.name,lines:g}}if(i.category==="access"){const g=a.access.doors.find(N=>N.id===i.doorDeviceId||N.name===i.name||N.id===i.code);return{title:i.name,lines:[{label:l("metrics.door"),value:(g==null?void 0:g.name)||i.name},{label:l("metrics.status"),value:g?ee(g.status):"--"},{label:l("metrics.todayPass"),value:String(a.access.todayPassCount??"--")}]}}if(i.category==="camera")return{title:i.name,lines:[{label:l("metrics.type"),value:l("metrics.camera")}]};if(i.category==="vav")return{title:i.name,lines:[{label:l("metrics.status"),value:i.on==null?"--":i.on?l("screen.running"):l("screen.stopped")},{label:l("metrics.faceVelocity"),value:`${p((E=i.vav)==null?void 0:E.faceVelocity)} m/s`},{label:l("metrics.sashHeight"),value:`${p((P=i.vav)==null?void 0:P.sashHeight)} mm`},{label:l("metrics.airflow"),value:`${p((S=i.vav)==null?void 0:S.airflow,0)} m³/h`},{label:l("metrics.alarmCode"),value:(($=i.vav)==null?void 0:$.alarmCode)==null||i.vav.alarmCode===0?l("metrics.none"):String(i.vav.alarmCode)}]};const h=[{label:l("metrics.temp"),value:`${p(i.values.temp)} ℃`},{label:l("metrics.humidity"),value:`${p(i.values.humidity,0)} %`},{label:l("metrics.pressure"),value:`${p(i.values.pressure)} Pa`}];return(M=i.alarms)!=null&&M.length&&h.push({label:l("metrics.alarm"),value:i.alarms.join("、")}),{title:i.name,lines:h}}const c=o.tag1?A.find(h=>h.id===o.tag1):void 0,n=(c==null?void 0:c.mode)||Se(o);if(!n||n==="camera")return null;const f=(o.name||(c==null?void 0:c.label)||"").trim(),b=f||l("screen.deviceCategory");if(n==="access"){const h=f.replace(/^门禁-/,"").replace(/门禁$/,"").trim(),g=a.access.doors.find(N=>{const j=N.name.replace(/门禁$/,"");return N.name.includes(h)||h.includes(j)||j.includes(h)});return{title:b,lines:[{label:l("metrics.door"),value:(g==null?void 0:g.name)||f||"--"},{label:l("metrics.status"),value:g?ee(g.status):"--"},{label:l("metrics.todayPass"),value:String(a.access.todayPassCount??"--")}]}}if(n==="pressure"){const h=(R=a.sensors)==null?void 0:R.find(g=>g.category==="pressure"&&(g.name===f||g.name.includes(f)||f.includes(g.name)));if(h){const g=[{label:l("metrics.temp"),value:`${p(h.values.temp)} ℃`},{label:l("metrics.humidity"),value:`${p(h.values.humidity,0)} %`},{label:l("metrics.pressure"),value:`${p(h.values.pressure)} Pa`}];return(_=h.alarms)!=null&&_.length&&g.push({label:l("metrics.alarm"),value:h.alarms.join("、")}),{title:h.name,lines:g}}}const v=c||Me(f,n);return v?{title:f||v.label,lines:Re(v,a)}:{title:b,lines:[{label:l("metrics.status"),value:"--"}]}}function p(o,a=1){return o==null||!Number.isFinite(Number(o))?"--":Number(o).toFixed(a)}const Te=2,Ae=12,te=0,xe="scene=mvlpj2yt6379aa29",T="/gis";function x(){return"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||`${T}/gis.html?${xe}`}function ie(o=x()){try{return new URL(o,typeof window<"u"?window.location.href:"http://localhost").origin}catch{return typeof window<"u"?window.location.origin:"http://localhost"}}function ne(o=x()){try{const a=new URL(o,typeof window<"u"?window.location.href:"http://localhost");return a.pathname.startsWith(`${T}/`)||a.pathname===T?T:a.pathname.startsWith("/rtengine/")||a.pathname==="/rtengine"?"/rtengine":""}catch{return T}}function $e(o,a=x()){const s=String(o||"").trim().replace(/\\/g,"/").split("/").pop()||"";if(!s)return"";const i=ne(a);return`${ie(a)}${i}/api/icons/${encodeURIComponent(s)}`}async function _e(o=x()){const a=ne(o),s=await fetch(`${ie(o)}${a}/api/icons`);if(!s.ok)throw new Error(`图标列表加载失败 (${s.status})`);const i=await s.json();return(Array.isArray(i)?i:i.files||[]).filter(n=>typeof n=="string"&&n.toLowerCase().endsWith(".png"))}async function Ye(o,a=x()){const s=o!=null&&o.length?o:await _e(a);return await Promise.all(s.map(i=>new Promise(c=>{const n=new Image;n.onload=()=>c(),n.onerror=()=>c(),n.src=$e(i,a)}))),s}function U(o,a,s){if(!o)return;let i="*";try{i=new URL(a,window.location.href).origin}catch{}try{o.postMessage(s,i)}catch{try{o.postMessage(s,"*")}catch{}}}function je(o){if(!o||typeof o!="object")return null;const a=o,s=[a,a.data,a.location,a.coord,a.coordinates,a.metaData];if(typeof a.metaData=="string")try{s.push(JSON.parse(a.metaData))}catch{}for(const i of s){if(!i||typeof i!="object")continue;const c=i,n=Number(c.x??c.lng??c.longitude??c.lon),f=Number(c.y??c.lat??c.latitude),b=Number(c.z??c.height??c.alt??c.altitude??0);if(Number.isFinite(n)&&Number.isFinite(f))return{x:n,y:f,z:Number.isFinite(b)?b:0}}return null}function Oe(o){if(!o||typeof o!="object")return[];const a=o,s=[a];if(a.data&&typeof a.data=="object"&&s.push(a.data),a.metaData&&typeof a.metaData=="object"&&s.push(a.metaData),typeof a.metaData=="string")try{s.push(JSON.parse(a.metaData))}catch{}return a.params&&typeof a.params=="object"&&s.push(a.params),s}function Fe(o){const a={id:null,name:null,type:null,tag0:null,tag1:null,tag2:null,icon:null,eventId:null},s=Oe(o);if(!s.length)return a;const i=(...v)=>{for(const I of s)for(const H of v){const E=I[H];if(E!=null&&String(E).trim())return String(E).trim()}return null},c=i("id","markerId","objectId"),n=i("name","text","title","label"),f=i("text","title","label","name");return{id:c,name:n&&c&&n===c&&f&&f!==c?f:n,type:i("type","objectType"),tag0:i("tag0","Tag0"),tag1:i("tag1","Tag1"),tag2:i("tag2","Tag2"),icon:i("icon","url","Icon"),eventId:i("eventId")}}function Ke(o){const a=ke(!1);function s(){var e;return((e=o.iframeRef.value)==null?void 0:e.contentWindow)??null}function i(){try{const e=s();return e?(e.location.href,e.$gisObj??null):null}catch{return null}}function c(e,t){const r=i(),d=r==null?void 0:r[e];if(typeof d=="function")try{if(e==="flyToBookmark"||e==="flyToViewpoint"||e==="flyToMarker"||e==="flyToHome"){const u=typeof t=="string"||typeof t=="number"?t:t&&typeof t=="object"?t.id??t.name??t.bookmarkName??t:t;d.call(r,u,t);return}if(e==="setLightVisible"&&t&&typeof t=="object"){const u=t;if(u.id!=null){d.call(r,u.id,!!u.visible);return}}if(e==="setSolarTime"){const u=typeof t=="number"?t:t&&typeof t=="object"?Number(t.time??t.solarTime??t.value):NaN;if(Number.isFinite(u)){d.call(r,u);return}}d.call(r,t??{});return}catch{}U(s(),o.cloudUrl,{type:e,data:t??{},messageId:`web-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}const n=[];let f=!1;const b=new Map,v=2500;function I(e){b.set(e,Date.now());const t=n.indexOf(e);t>=0&&n.splice(t,1)}function H(e){const t=b.get(e);return t!=null&&Date.now()-t<v}async function E(){if(f)return;const e=i();if(!e||typeof e.registerBookmarks!="function")return;let t="";try{t=new URL(o.cloudUrl,window.location.href).searchParams.get("scene")||""}catch{}if(!t)return;const r=[`/gis/designer/data/scenes/${encodeURIComponent(t)}.json`,`/designer/data/scenes/${encodeURIComponent(t)}.json`,`/designer/api/embed/scenes/${encodeURIComponent(t)}`];for(const d of r)try{const u=await fetch(d);if(!u.ok)continue;const y=await u.json();if(!Array.isArray(y.bookmarks)||!y.bookmarks.length)continue;e.registerBookmarks(y.bookmarks),e._bookmarkFlyReady=!0,f=!0;return}catch{}}function P(e,t){const r=String(e||"").trim();if(!r||H(r))return;const d=i();if(d&&typeof d.flyToBookmark=="function")try{const u=t?d.flyToBookmark(r,t):d.flyToBookmark(r),y=!!(u&&typeof u=="object"&&u.queued);return I(r),void 0}catch{}n.includes(r)||n.push(r),E().then(()=>{if(H(r))return;const u=i();if(!(!u||typeof u.flyToBookmark!="function"))try{u.flyToBookmark(r,t),I(r)}catch{}})}function S(){const e=n.splice(0,n.length);for(const t of e)P(t)}function $(e){c("setMapPickMode",{state:e,enable:e})}function M(e){const t=(e.icon||"").trim(),r=e.scale??1,d=e.leader!==!1,u=e.leaderHeight!=null&&Number(e.leaderHeight)>0?Number(e.leaderHeight):Te;return{id:e.id,name:e.name,text:e.text??e.name,showText:e.showText!==!1,type:e.type||"marker",x:e.x,y:e.y,z:e.z,lng:e.x,lat:e.y,height:e.z,longitude:e.x,latitude:e.y,scale:r,scalex:r,scaley:r,scalez:r,tag0:e.tag0||"camera",tag1:e.tag1||e.id,leader:d,leaderHeight:u,leaderThickness:e.leaderThickness??2,leaderColor:e.leaderColor||"#00f7ff",...t?{icon:t,url:t}:{icon:""}}}function R(e){c("addMarker",M(e))}function _(e){for(const t of e)R(t)}function h(e){c("removeMarker",{id:e})}function g(){c("clearMarkers",{})}function N(){const e=i(),t=e==null?void 0:e.markers,r=[];return!t||typeof t.forEach!="function"||t.forEach(d=>{if(!d||typeof d!="object")return;const u=d,y=String(u.id||"");y&&r.push({id:y,name:String(u.name||u.text||""),tag0:String(u.tag0||""),icon:String(u.icon||u.url||"")})}),r}function j(e,t){const r=i();if(r&&typeof r.setPoiVisible=="function")try{r.setPoiVisible(e,!!t);return}catch{}c("setPoiVisible",{id:e,visible:t})}function q(e,t){const r=i(),d=r==null?void 0:r[e];if(typeof d=="function")try{d.call(r,t,void 0,void 0);return}catch{}U(s(),o.cloudUrl,{type:e,data:{tag0:t},messageId:`web-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}function oe(e){q("showPOIs",e)}function re(e){q("hidePOIs",e)}function ae(e,t){const r=i();if(r&&typeof r.updateMarkerText=="function")try{r.updateMarkerText(e,t);return}catch{}c("updateMarkerText",{id:e,text:t}),c("updateMarker",{id:e,text:t,name:t})}function se(e){const t=M(e),r=i();if(r&&typeof r.updateMarker=="function")try{r.updateMarker(t);return}catch{}c("updateMarker",t)}function le(e){const t=e.type||"spot",r=e.pitch??-90,d=e.yaw??0,u=e.roll??0;return{id:e.id,name:e.name||e.id,type:t,lightType:t,kind:t,LightType:t,isGeo:!1,x:e.x,y:e.y,z:e.z,position:[e.x,e.y,e.z],yaw:d,pitch:r,roll:u,heading:d,rotation:{yaw:d,pitch:r,roll:u},intensity:e.intensity??8,attenuationRadius:e.attenuationRadius??10,innerConeAngle:e.innerConeAngle??18,outerConeAngle:e.outerConeAngle??42,innerAngle:e.innerConeAngle??18,outerAngle:e.outerConeAngle??42,sourceWidth:100,sourceHeight:100,useTemperature:e.useTemperature??!1,temperature:e.temperature??6500,castShadows:e.castShadows!==!1,color:e.color||[1,1,1,1],visible:e.visible!==!1,tag0:e.tag0||"facility-light",tag1:e.tag1||"",tag2:e.tag2||""}}function ce(e){c("addLight",le(e))}function de(e){const t={id:e.id};e.type&&(t.type=e.type,t.lightType=e.type,t.kind=e.type),e.intensity!=null&&(t.intensity=e.intensity),e.visible!=null&&(t.visible=e.visible),e.color&&(t.color=e.color),e.attenuationRadius!=null&&(t.attenuationRadius=e.attenuationRadius),e.innerConeAngle!=null&&(t.innerConeAngle=e.innerConeAngle,t.innerAngle=e.innerConeAngle),e.outerConeAngle!=null&&(t.outerConeAngle=e.outerConeAngle,t.outerAngle=e.outerConeAngle),e.yaw!=null&&(t.yaw=e.yaw,t.heading=e.yaw),e.pitch!=null&&(t.pitch=e.pitch),e.roll!=null&&(t.roll=e.roll),e.x!=null&&(t.x=e.x,t.lng=e.x),e.y!=null&&(t.y=e.y,t.lat=e.y),e.z!=null&&(t.z=e.z,t.height=e.z),c("updateLight",t)}function ue(e){c("removeLight",{id:e})}function me(){c("clearLights",{})}function fe(e,t){const r=!!t;c("setLightVisible",{id:e,visible:r});const d=i();if(d&&typeof d.setLightVisible=="function")try{d.setLightVisible(e,r)}catch{}}function O(e){const t=Number(e);Number.isFinite(t)&&(c("setSolarTime",t),c("setSolarTime",{time:t,solarTime:t,value:t,data:t}))}function D(e,t){typeof e=="number"?c("setWeather",t?{weatherId:e,weather:String(e),...t}:{weatherId:e,weather:String(e)}):c("setWeather",e)}function B(e,t=0,r=0,d=0,u=e,y=1){const k=i();if(k&&typeof k.setSunParam=="function")try{k.setSunParam(e,t,r,d,u,y);return}catch{}c("setSunParam",{intensity:e,fogDensity:t,h:r,s:d,v:u,a:y,timeOfDay:e}),U(s(),o.cloudUrl,{type:"setSunParam",data:[e,t,r,d,u,y],messageId:`web-sun-${Date.now()}`})}function G(e){const t=i();if(t&&typeof t.setFog=="function")try{t.setFog(e);return}catch{}c("setFog",{fog:e})}function ge(e){const t=e.intensity??e.sunBrightness??1;B(t,t<.2?.7:0)}function be(e){e?(O(te),D(5,{fog:1,fogDensity:1,fogIntensity:1,cloudCoverage:1,wind:0,transition:.08}),B(0,1,0,0,0,1),G(1),O(te)):(O(Ae),D(1,{fog:0,fogDensity:0,cloudCoverage:.15,transition:.2}),B(1,0),G(0))}let W=!1;function he(){W||(W=!0,c("setMarkerVisible",{visible:!0}),c("showPOIs",{visible:!0}))}let V=!1,Y=!1;function F(){var e;V||(V=!0,a.value=!0,(e=o.onReady)==null||e.call(o),!Y&&(Y=!0,E().then(()=>S())))}function K(e){var y;const t=e.data;if(!t||typeof t!="object")return;const r=String(t.type||""),d=t.data??t,u=d&&typeof d=="object"?d:null;if(!V&&u&&(u.bookmarksReady===!0||Array.isArray(u.bookmarks)&&u.bookmarks.length>0||typeof u.bookmarkCount=="number"&&u.bookmarkCount>0)&&F(),r==="sceneEmbedLoaded"||r==="sceneEmbedProgress"||r==="ueConnected"||r==="peerConnected"||r==="psConnected"||r==="streamPlaying"||r==="bookmarksReady"||r==="sceneBookmarks"){if(r==="sceneEmbedProgress"){const k=Number(u==null?void 0:u.percent);Number.isFinite(k)&&k>=100&&F();return}F();return}if(r==="mouseClick"||r==="mouseClickCallback"||r==="modelClick"||r==="modelClickCallback"||r==="selectMarker"||d&&typeof d=="object"&&d.eventId==="mouseClick"){const k=Fe(d);(y=o.onMouseClick)==null||y.call(o,{point:je(d),markerId:k.id||k.tag1||k.tag0,marker:k,raw:d})}}window.addEventListener("message",K),ye(()=>window.removeEventListener("message",K));function pe(){const e=new Map,t=i();if(!t)return e;const r=[];try{typeof t.getBookmarks=="function"&&r.push(t.getBookmarks())}catch{}for(const d of["bookmarks","_bookmarks","bookmarkList","views"]){const u=t[d];u&&r.push(u)}for(const d of r){const u=Array.isArray(d)?d:d&&typeof d=="object"&&Array.isArray(d.bookmarks)?d.bookmarks:[];for(const y of u){if(!y||typeof y!="object")continue;const k=y,J=String(k.name??k.id??k.title??"").trim();if(!J)continue;const X=[k];for(const w of["camera","position","pos","location","coord","coordinates","view"]){const C=k[w];C&&typeof C=="object"&&X.push(C)}for(const w of X){const C=Number(w.x??w.lng??w.longitude??w.lon),Q=Number(w.y??w.lat??w.latitude),Z=Number(w.z??w.height??w.alt??w.altitude??0);if(Number.isFinite(C)&&Number.isFinite(Q)){e.set(J,{x:C,y:Q,z:Number.isFinite(Z)?Z:0});break}}}}return e}return{ready:a,send:c,flyToBookmark:P,setPickMode:$,addMarker:R,addMarkers:_,removeMarker:h,clearMarkers:g,setMarkerVisible:j,listMarkers:N,showPois:oe,hidePois:re,updateMarker:se,updateMarkerText:ae,addLight:ce,updateLight:de,removeLight:ue,clearLights:me,setLightVisible:fe,setSolarTime:O,setWeather:D,setLighting:ge,applyDayNight:be,showScenePresets:he,markReady:F,flushPendingFlies:S,readBookmarkPositions:pe,ensureBookmarks:E}}export{ze as D,A as M,Te as a,Ue as b,Se as c,Ve as d,qe as e,p as f,Ye as g,x as h,_e as i,We as m,Ge as p,$e as r,Ke as u};
import{s as H,r as J}from"./index-Bs_x-_cK.js";const Y="scene=mvlpj2yt6379aa29",b="/rtengine";function w(){return"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||"/rtengine/gis.html?scene=mvlpj2yt6379aa29".trim()||`${b}/gis.html?${Y}`}function B(r=w()){try{return new URL(r,typeof window<"u"?window.location.href:"http://localhost").origin}catch{return typeof window<"u"?window.location.origin:"http://localhost"}}function E(r=w()){try{const o=new URL(r,typeof window<"u"?window.location.href:"http://localhost");return o.pathname.startsWith(`${b}/`)||o.pathname===b?b:""}catch{return b}}function q(r,o=w()){const u=String(r||"").trim().replace(/\\/g,"/").split("/").pop()||"";if(!u)return"";const s=E(o);return`${B(o)}${s}/api/icons/${encodeURIComponent(u)}`}async function Q(r=w()){const o=E(r),u=await fetch(`${B(r)}${o}/api/icons`);if(!u.ok)throw new Error(`图标列表加载失败 (${u.status})`);const s=await u.json();return(Array.isArray(s)?s:s.files||[]).filter(f=>typeof f=="string"&&f.toLowerCase().endsWith(".png"))}async function te(r,o=w()){const u=r!=null&&r.length?r:await Q(o);return await Promise.all(u.map(s=>new Promise(a=>{const f=new Image;f.onload=()=>a(),f.onerror=()=>a(),f.src=q(s,o)}))),u}function $(r,o,u){if(!r)return;let s="*";try{s=new URL(o,window.location.href).origin}catch{}try{r.postMessage(u,s)}catch{try{r.postMessage(u,"*")}catch{}}}function X(r){if(!r||typeof r!="object")return null;const o=r,u=[o,o.data,o.location,o.coord,o.coordinates,o.metaData];if(typeof o.metaData=="string")try{u.push(JSON.parse(o.metaData))}catch{}for(const s of u){if(!s||typeof s!="object")continue;const a=s,f=Number(a.x??a.lng??a.longitude??a.lon),g=Number(a.y??a.lat??a.latitude),k=Number(a.z??a.height??a.alt??a.altitude??0);if(Number.isFinite(f)&&Number.isFinite(g))return{x:f,y:g,z:Number.isFinite(k)?k:0}}return null}function K(r){if(!r||typeof r!="object")return[];const o=r,u=[o];if(o.data&&typeof o.data=="object"&&u.push(o.data),o.metaData&&typeof o.metaData=="object"&&u.push(o.metaData),typeof o.metaData=="string")try{u.push(JSON.parse(o.metaData))}catch{}return o.params&&typeof o.params=="object"&&u.push(o.params),u}function Z(r){const o={id:null,name:null,type:null,tag0:null,tag1:null,tag2:null,icon:null,eventId:null},u=K(r);if(!u.length)return o;const s=(...M)=>{for(const y of u)for(const I of M){const p=y[I];if(p!=null&&String(p).trim())return String(p).trim()}return null},a=s("id","markerId","objectId"),f=s("name","text","title","label"),g=s("text","title","label","name");return{id:a,name:f&&a&&f===a&&g&&g!==a?g:f,type:s("type","objectType"),tag0:s("tag0","Tag0"),tag1:s("tag1","Tag1"),tag2:s("tag2","Tag2"),icon:s("icon","url","Icon"),eventId:s("eventId")}}function ne(r){const o=J(!1);function u(){var e;return((e=r.iframeRef.value)==null?void 0:e.contentWindow)??null}function s(){try{const e=u();return e?(e.location.href,e.$gisObj??null):null}catch{return null}}function a(e,t){const n=s(),i=n==null?void 0:n[e];if(typeof i=="function")try{if(e==="flyToBookmark"||e==="flyToViewpoint"||e==="flyToMarker"||e==="flyToHome"){const c=typeof t=="string"||typeof t=="number"?t:t&&typeof t=="object"?t.id??t.name??t.bookmarkName??t:t;i.call(n,c,t);return}i.call(n,t??{});return}catch{}$(u(),r.cloudUrl,{type:e,data:t??{},messageId:`web-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}const f=[];let g=!1;async function k(){if(g)return;const e=s();if(!e||typeof e.registerBookmarks!="function")return;let t="";try{t=new URL(r.cloudUrl,window.location.href).searchParams.get("scene")||""}catch{}if(!t)return;const n=[`/rtengine/designer/data/scenes/${encodeURIComponent(t)}.json`,`/designer/data/scenes/${encodeURIComponent(t)}.json`,`/designer/api/embed/scenes/${encodeURIComponent(t)}`];for(const i of n)try{const c=await fetch(i);if(!c.ok)continue;const l=await c.json();if(!Array.isArray(l.bookmarks)||!l.bookmarks.length)continue;e.registerBookmarks(l.bookmarks),e._bookmarkFlyReady=!0,g=!0;return}catch{}}function M(e,t){const n=String(e||"").trim();if(!n)return;const i=()=>{const c=s();if(!c||typeof c.flyToBookmark!="function")return!1;try{const l=t?c.flyToBookmark(n,t):c.flyToBookmark(n);return l&&typeof l=="object"&&l.queued&&(f.includes(n)||f.push(n)),!0}catch{return!1}};i()||(f.includes(n)||f.push(n),a("flyToBookmark",n),k().then(()=>{i()}),window.setTimeout(()=>i(),600),window.setTimeout(()=>i(),2e3))}function y(){const e=f.splice(0,f.length);for(const t of e)M(t)}function I(e){a("setMapPickMode",{state:e,enable:e})}function p(e){const t=(e.icon||"").trim();return{id:e.id,name:e.name,text:e.text??e.name,showText:e.showText!==!1,type:e.type||"marker",x:e.x,y:e.y,z:e.z,scale:e.scale??1,scalex:e.scale??1,scaley:e.scale??1,scalez:e.scale??1,tag0:e.tag0||"camera",tag1:e.tag1||e.id,...t?{icon:t,url:t}:{}}}function F(e){a("addMarker",p(e))}function A(e){a("addMarkers",e.map(t=>p(t)))}function U(e){a("removeMarker",{id:e})}function D(){a("clearMarkers",{})}function L(){const e=s(),t=e==null?void 0:e.markers,n=[];return!t||typeof t.forEach!="function"||t.forEach(i=>{if(!i||typeof i!="object")return;const c=i,l=String(c.id||"");l&&n.push({id:l,name:String(c.name||c.text||""),tag0:String(c.tag0||""),icon:String(c.icon||c.url||"")})}),n}function z(e,t){const n=s();if(n&&typeof n.setPoiVisible=="function")try{n.setPoiVisible(e,!!t);return}catch{}a("setPoiVisible",{id:e,visible:t})}function P(e,t){const n=s(),i=n==null?void 0:n[e];if(typeof i=="function")try{i.call(n,t,void 0,void 0);return}catch{}$(u(),r.cloudUrl,{type:e,data:{tag0:t},messageId:`web-${Date.now()}-${Math.random().toString(36).slice(2,8)}`})}function O(e){P("showPOIs",e)}function V(e){P("hidePOIs",e)}function _(e){const t=p(e);a("updateMarker",t),a("addMarker",t)}let T=!1;function W(){T||(T=!0,a("setMarkerVisible",{visible:!0}),a("showPOIs",{visible:!0}))}let N=!1;function j(){var e;if(N){f.length&&y();return}N=!0,o.value=!0,(e=r.onReady)==null||e.call(r),k().then(()=>y()),window.setTimeout(()=>{k().then(()=>y())},800),window.setTimeout(()=>y(),2500)}function v(e){var l;const t=e.data;if(!t||typeof t!="object")return;const n=String(t.type||""),i=t.data??t,c=i&&typeof i=="object"?i:null;if(!N&&c&&(c.bookmarksReady===!0||Array.isArray(c.bookmarks)&&c.bookmarks.length>0||typeof c.bookmarkCount=="number"&&c.bookmarkCount>0)&&j(),n==="sceneEmbedLoaded"||n==="sceneEmbedProgress"||n==="ueConnected"||n==="peerConnected"||n==="psConnected"||n==="streamPlaying"||n==="bookmarksReady"||n==="sceneBookmarks"){if(n==="sceneEmbedProgress"){const m=Number(c==null?void 0:c.percent);Number.isFinite(m)&&m>=100&&j();return}j();return}if(n==="mouseClick"||n==="mouseClickCallback"||n==="modelClick"||n==="modelClickCallback"||n==="selectMarker"||i&&typeof i=="object"&&i.eventId==="mouseClick"){const m=Z(i);(l=r.onMouseClick)==null||l.call(r,{point:X(i),markerId:m.id||m.tag1||m.tag0,marker:m,raw:i})}}window.addEventListener("message",v),H(()=>window.removeEventListener("message",v));function G(){const e=new Map,t=s();if(!t)return e;const n=[];try{typeof t.getBookmarks=="function"&&n.push(t.getBookmarks())}catch{}for(const i of["bookmarks","_bookmarks","bookmarkList","views"]){const c=t[i];c&&n.push(c)}for(const i of n){const c=Array.isArray(i)?i:i&&typeof i=="object"&&Array.isArray(i.bookmarks)?i.bookmarks:[];for(const l of c){if(!l||typeof l!="object")continue;const m=l,R=String(m.name??m.id??m.title??"").trim();if(!R)continue;const C=[m];for(const d of["camera","position","pos","location","coord","coordinates","view"]){const h=m[d];h&&typeof h=="object"&&C.push(h)}for(const d of C){const h=Number(d.x??d.lng??d.longitude??d.lon),x=Number(d.y??d.lat??d.latitude),S=Number(d.z??d.height??d.alt??d.altitude??0);if(Number.isFinite(h)&&Number.isFinite(x)){e.set(R,{x:h,y:x,z:Number.isFinite(S)?S:0});break}}}}return e}return{ready:o,send:a,flyToBookmark:M,setPickMode:I,addMarker:F,addMarkers:A,removeMarker:U,clearMarkers:D,setMarkerVisible:z,listMarkers:L,showPois:O,hidePois:V,updateMarker:_,showScenePresets:W,markReady:j,flushPendingFlies:y,readBookmarkPositions:G,ensureBookmarks:k}}export{w as d,Q as f,te as p,q as r,ne as u};
import{l as u,m as f,p as d,r as p}from"./index-BssDqbym.js";const l="分子实验室三维可视化管理平台",T="jh-lab-screen-title",a=p(l);let s,n=null,i=0;async function r(){try{const t=await d("/api/settings"),e=String(t.screenTitle||"").trim();e&&(a.value=e)}catch{}}function c(){n||typeof BroadcastChannel>"u"||(n=new BroadcastChannel(T),n.onmessage=t=>{var o;const e=String(((o=t.data)==null?void 0:o.screenTitle)||"").trim();e&&(a.value=e)})}function h(t){const e=String(t||"").trim()||l;a.value=e;try{c(),n==null||n.postMessage({screenTitle:e})}catch{}}function v(t){return u(()=>{i+=1,c(),r(),s||(s=window.setInterval(()=>{r()},5e3))}),f(()=>{i=Math.max(0,i-1),i===0&&s&&(window.clearInterval(s),s=void 0)}),{title:a,refresh:r}}export{l as D,h as p,v as u};
......@@ -11,8 +11,8 @@
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@500;600;700&family=Share+Tech+Mono&display=swap" rel="stylesheet" />
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
<script type="module" crossorigin src="/assets/index-Bs_x-_cK.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Yzi0d50E.css">
<script type="module" crossorigin src="/assets/index-BssDqbym.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-Crx1aGdr.css">
</head>
<body>
<div id="app"></div>
......
......@@ -121,15 +121,14 @@ export async function queryFridgeTempSeries(opts?: {
}): Promise<FridgeTempSeries[]> {
if (!isPgEnabled()) return []
const hours = Math.min(168, Math.max(1, opts?.hours ?? 24))
const bucketMinutes = Math.min(60, Math.max(5, opts?.bucketMinutes ?? 15))
const bucketMinutes = Math.min(60, Math.max(1, opts?.bucketMinutes ?? 60))
try {
const series = await queryTsSeries({
source: 'fridge',
metric: 'temp',
hours,
// 24h 内用 1min 桶,曲线更密
bucketMinutes: hours <= 24 ? Math.min(bucketMinutes, 1) || 1 : bucketMinutes,
bucketMinutes,
})
if (series.length) {
const fridges = await listDevices({ category: 'fridge' })
......
......@@ -362,7 +362,7 @@ export function resolveTsTimeRange(opts: {
}
if (toMs - fromMs > maxMs) {
throw new Error(`查询跨度不能超过 ${maxHistorySpanDays()} 天`)
throw new Error(查询跨度不能超过 天)
}
if (toMs - fromMs < 60_000) {
throw new Error('查询跨度至少 1 分钟')
......@@ -393,7 +393,29 @@ function mapRollupRows(
return [...map.values()]
}
/** 优先读预聚合;无数据时回退原始点桶聚合。支持绝对 from/to 或相对 hours。 */
/** 将更密的点抽成整点小时(UTC 整点 = 中国本地 :00) */
function downsampleToHourly(series: TsSeries[]): TsSeries[] {
const HOUR = 3_600_000
return series.map((s) => {
const byHour = new Map<number, { t: number; sum: number; n: number }>()
for (const p of s.points) {
const key = Math.floor(p.t / HOUR) * HOUR
const hit = byHour.get(key)
if (hit) {
hit.sum += p.v
hit.n += 1
} else {
byHour.set(key, { t: key, sum: p.v, n: 1 })
}
}
const points = [...byHour.values()]
.sort((a, b) => a.t - b.t)
.map((x) => ({ t: x.t, v: x.sum / x.n }))
return { ...s, points }
})
}
/** 优先读预聚合;60min 无桶时从 15/1min 抽整点;支持绝对 from/to 或相对 hours */
export async function queryTsSeries(opts: {
source: string
metric: string
......@@ -406,15 +428,15 @@ export async function queryTsSeries(opts: {
if (!isPgEnabled()) return []
const range = resolveTsTimeRange(opts)
const hours = range.hours
// 短窗口优先 1min 桶(更密);长窗口用请求粒度或 15min
const wantBucket = Math.min(60, Math.max(1, opts.bucketMinutes ?? 15))
const bucket = hours <= 24 && wantBucket <= 5 ? 1 : wantBucket === 1 ? 1 : wantBucket
const wantBucket = Math.min(60, Math.max(1, opts.bucketMinutes ?? 60))
const hourly = wantBucket >= 60
const bucket = hourly ? 60 : hours <= 24 && wantBucket <= 5 ? 1 : wantBucket === 1 ? 1 : wantBucket
const params: unknown[] = [opts.source, opts.metric, range.from, range.to, bucket]
let deviceFilter = ''
if (opts.deviceIds?.length) {
params.push(opts.deviceIds)
deviceFilter = ` AND device_id = ANY($${params.length}::text[])`
deviceFilter = AND device_id = ANY({params.length}::text[])
}
let { rows: rollupRows } = await query<{
......@@ -422,15 +444,43 @@ export async function queryTsSeries(opts: {
bucket: Date
avg_eng: string | number
}>(
`SELECT device_id, bucket, avg_eng
SELECT device_id, bucket, avg_eng
FROM ts_rollups
WHERE source = $1 AND metric = $2 AND bucket_minutes = $5
AND bucket >= $3 AND bucket <= $4
${deviceFilter}
ORDER BY device_id, bucket`,
WHERE source = AND metric = AND bucket_minutes =
AND bucket >= AND bucket <=
ORDER BY device_id, bucket,
params,
)
// 60min 无预聚合:用 15min(再不行 1min)抽整点
if (!rollupRows.length && hourly) {
for (const fb of [15, 1]) {
const fbParams: unknown[] = [opts.source, opts.metric, range.from, range.to, fb]
let fbFilter = ''
if (opts.deviceIds?.length) {
fbParams.push(opts.deviceIds)
fbFilter = AND device_id = ANY({fbParams.length}::text[])
}
const fallback = await query<{
device_id: string
bucket: Date
avg_eng: string | number
}>(
SELECT device_id, bucket, avg_eng
FROM ts_rollups
WHERE source = AND metric = AND bucket_minutes =
AND bucket >= AND bucket <=
ORDER BY device_id, bucket,
fbParams,
)
if (fallback.rows.length) {
return downsampleToHourly(mapRollupRows(fallback.rows))
}
}
}
// 1min 尚无数据时回退 15min
if (!rollupRows.length && bucket === 1) {
const fallback = await query<{
......@@ -438,18 +488,21 @@ export async function queryTsSeries(opts: {
bucket: Date
avg_eng: string | number
}>(
`SELECT device_id, bucket, avg_eng
SELECT device_id, bucket, avg_eng
FROM ts_rollups
WHERE source = $1 AND metric = $2 AND bucket_minutes = 15
AND bucket >= $3 AND bucket <= $4
${deviceFilter}
ORDER BY device_id, bucket`,
WHERE source = AND metric = AND bucket_minutes = 15
AND bucket >= AND bucket <=
ORDER BY device_id, bucket,
params,
)
rollupRows = fallback.rows
}
if (rollupRows.length) return mapRollupRows(rollupRows)
if (rollupRows.length) {
const series = mapRollupRows(rollupRows)
return hourly ? downsampleToHourly(series) : series
}
// 回退:原始点按桶聚合
const { rows } = await query<{
......@@ -457,20 +510,21 @@ export async function queryTsSeries(opts: {
bucket: Date
avg_eng: string | number
}>(
`SELECT
SELECT
device_id,
to_timestamp(floor(extract(epoch FROM ts) / ($5 * 60)) * ($5 * 60)) AS bucket,
to_timestamp(floor(extract(epoch FROM ts) / ( * 60)) * ( * 60)) AS bucket,
AVG(eng) AS avg_eng
FROM ts_samples
WHERE source = $1 AND metric = $2
AND ts >= $3 AND ts <= $4
${deviceFilter}
WHERE source = AND metric =
AND ts >= AND ts <=
GROUP BY device_id, bucket
ORDER BY device_id, bucket`,
ORDER BY device_id, bucket,
params,
)
return mapRollupRows(rows)
const series = mapRollupRows(rows)
return hourly ? downsampleToHourly(series) : series
}
export type TsExportRow = {
......@@ -503,7 +557,7 @@ export async function queryTsExportRows(opts: {
let deviceFilter = ''
if (opts.deviceIds?.length) {
params.push(opts.deviceIds)
deviceFilter = ` AND device_id = ANY($${params.length}::text[])`
deviceFilter = AND device_id = ANY({params.length}::text[])
}
const { rows: raw } = await query<{
......@@ -514,13 +568,13 @@ export async function queryTsExportRows(opts: {
eng: string | number
raw: string | number | null
}>(
`SELECT ts, device_id, source, metric, eng, raw
SELECT ts, device_id, source, metric, eng, raw
FROM ts_samples
WHERE source = $1 AND metric = $2
AND ts >= $3 AND ts <= $4
${deviceFilter}
WHERE source = AND metric =
AND ts >= AND ts <=
ORDER BY device_id, ts
LIMIT $5`,
LIMIT ,
params,
)
......@@ -548,7 +602,7 @@ export async function queryTsExportRows(opts: {
let rollDeviceFilter = ''
if (opts.deviceIds?.length) {
rollParams.push(opts.deviceIds)
rollDeviceFilter = ` AND device_id = ANY($${rollParams.length}::text[])`
rollDeviceFilter = AND device_id = ANY({rollParams.length}::text[])
}
rollParams.push(EXPORT_ROW_LIMIT + 1)
const limitIdx = rollParams.length
......@@ -559,13 +613,13 @@ export async function queryTsExportRows(opts: {
metric: string
avg_eng: string | number
}>(
`SELECT bucket, device_id, source, metric, avg_eng
SELECT bucket, device_id, source, metric, avg_eng
FROM ts_rollups
WHERE source = $1 AND metric = $2 AND bucket_minutes = $5
AND bucket >= $3 AND bucket <= $4
${rollDeviceFilter}
WHERE source = AND metric = AND bucket_minutes =
AND bucket >= AND bucket <=
ORDER BY device_id, bucket
LIMIT $${limitIdx}`,
LIMIT {limitIdx},
rollParams,
)
if (!roll.length) continue
......@@ -684,7 +738,7 @@ export async function queryNamedTsSeries(
opts?: { hours?: number; bucketMinutes?: number },
): Promise<Record<string, TsSeries[]>> {
const hours = opts?.hours ?? 24
const bucketMinutes = opts?.bucketMinutes ?? 15
const bucketMinutes = opts?.bucketMinutes ?? 60
const out: Record<string, TsSeries[]> = {}
await Promise.all(
queries.map(async (q) => {
......
......@@ -13,7 +13,7 @@ import type {
import { NE_LIGHT_DEFS } from './neLights.js'
/** 与前端 PROTOCOL_ROOMS / 场景书签对齐的稳定房间 id */
const ROOM_ID_BY_NAME: Record<string, string> = {
export const ROOM_ID_BY_NAME: Record<string, string> = {
收样咨询室: 'recv',
生信分析报告室: 'report',
试剂准备间: 'reagent',
......@@ -30,6 +30,13 @@ const ROOM_ID_BY_NAME: Record<string, string> = {
测序区缓冲: 'seq-buf',
}
/** 时序 deviceId(如 lib-1-buf)→ 中文房间名,供曲线图例/提示使用 */
export const ROOM_NAME_BY_ID: Record<string, string> = Object.fromEntries(
Object.entries(ROOM_ID_BY_NAME)
.filter(([name]) => name !== 'NGS走廊')
.map(([name, id]) => [id, name]),
)
function stableRoomId(d: Device): string {
if (ROOM_ID_BY_NAME[d.name]) return ROOM_ID_BY_NAME[d.name]
for (const [name, id] of Object.entries(ROOM_ID_BY_NAME)) {
......
......@@ -9,6 +9,7 @@ import {
type TsSeries,
} from '../db/timeseries.js'
import { buildExcelXml, formatExportTs } from './excelXml.js'
import { ROOM_NAME_BY_ID } from './fromDevices.js'
const METRIC_LABEL: Record<string, string> = {
temp: '温度',
......@@ -45,6 +46,8 @@ export function sourceLabel(source: string) {
async function deviceNameMap() {
const devices = await listDevices()
const map = new Map<string, string>()
// 房间时序 id(lib-1 / sample-1 …)优先挂中文名,避免图例显示英文编号
for (const [id, name] of Object.entries(ROOM_NAME_BY_ID)) map.set(id, name)
for (const d of devices) map.set(d.id, d.name)
map.set('PAU201', 'PAU-201 机组')
map.set('lab', '实验室汇总')
......@@ -89,7 +92,7 @@ export async function getHistorySeries(opts: {
series: TsSeries[]
}> {
const range = resolveTsTimeRange({ hours: opts.hours, from: opts.from, to: opts.to })
const bucketMinutes = opts.bucketMinutes ?? 15
const bucketMinutes = opts.bucketMinutes ?? 60
const raw = await queryTsSeries({
source: opts.source,
metric: opts.metric,
......
......@@ -118,7 +118,7 @@ export async function buildScreenDashboard(): Promise<ScreenDashboard> {
listDevices(),
listPoints(),
listGateways(),
queryFridgeTempSeries({ hours: 24, bucketMinutes: 15 }).catch(() => [] as FridgeTempSeries[]),
queryFridgeTempSeries({ hours: 24, bucketMinutes: 60 }).catch(() => [] as FridgeTempSeries[]),
resolveGatewayBase()
? fetchGatewayHealth().catch(() => ({ ok: false as boolean }))
: Promise.resolve({ ok: false as boolean }),
......@@ -140,7 +140,7 @@ export async function buildScreenDashboard(): Promise<ScreenDashboard> {
{ key: 'meteringWater', source: 'metering', metric: 'water_m3' },
{ key: 'meteringCooling', source: 'metering', metric: 'cooling_kwh' },
],
{ hours: 24, bucketMinutes: 1 },
{ hours: 24, bucketMinutes: 60 },
).catch(() => ({}) as Record<string, TsSeries[]>),
])
......
......@@ -45,7 +45,7 @@ realtimeRouter.get('/history', async (req, res) => {
const hours = req.query.hours != null && req.query.hours !== '' ? Number(req.query.hours) : undefined
const from = req.query.from ? String(req.query.from) : undefined
const to = req.query.to ? String(req.query.to) : undefined
const bucketMinutes = Number(req.query.bucketMinutes) || 15
const bucketMinutes = Number(req.query.bucketMinutes) || 60
const deviceId = req.query.deviceId ? String(req.query.deviceId) : undefined
try {
const data = await getHistorySeries({ source, metric, hours, from, to, bucketMinutes, deviceId })
......@@ -98,7 +98,7 @@ realtimeRouter.get('/history/export', async (req, res) => {
/** 各冰箱近 24h 温度曲线(采集落库聚合) */
realtimeRouter.get('/fridges/temp-history', async (req, res) => {
const hours = Number(req.query.hours) || 24
const bucketMinutes = Number(req.query.bucketMinutes) || 15
const bucketMinutes = Number(req.query.bucketMinutes) || 60
try {
const series = await queryFridgeTempSeries({ hours, bucketMinutes })
res.json({ hours, bucketMinutes, series })
......
......@@ -40,7 +40,7 @@ async function loadHistory() {
loading.value = true
error.value = ''
try {
const res = await api<{ series: HistSeries[] }>('/api/realtime/fridges/temp-history?hours=24&bucketMinutes=15')
const res = await api<{ series: HistSeries[] }>('/api/realtime/fridges/temp-history?hours=24&bucketMinutes=60')
const next: Record<string, HistSeries> = {}
for (const s of res.series || []) next[s.id] = s
seriesMap.value = next
......
......@@ -15,7 +15,6 @@ import AppIcon from '@/components/icons/AppIcon.vue'
import MarkerNearDialog from '@/components/scene/MarkerNearDialog.vue'
import { api } from '@/api/http'
import {
MARKER_LEADER_HEIGHT_M,
preloadRtengineIcons,
useRtengineBridge,
type SceneMarkerHit,
......@@ -377,29 +376,11 @@ async function onLightControl(on: boolean) {
}
}
function cameraMarkerList() {
return cameras.value
.filter((d) => d.enabled && d.scenePoint)
.map((d) => ({
id: d.id,
name: d.name,
text: d.name,
x: d.scenePoint!.x,
y: d.scenePoint!.y,
z: d.scenePoint!.z,
icon: d.scenePoint!.icon || 'cctv-blue.png',
tag0: 'camera',
tag1: d.id,
leader: true,
leaderHeight: MARKER_LEADER_HEIGHT_M,
leaderThickness: 2,
leaderColor: '#00f7ff',
}))
}
/** 引擎就绪后:预加载图标 → 显示 POI → 摄像头 Marker(只同步一次) */
/** 场景书签「全景总览」= 模型默认初始视角 */
const OVERVIEW_BOOKMARK = '全景总览'
/** 引擎就绪后:预加载图标 → 按分类同步设施 POI */
/** 底栏「全景总览」飞到场景书签「主视图」 */
const OVERVIEW_BOOKMARK = '主视图'
/** 引擎就绪默认视角(与底栏主视图可不同) */
const DEFAULT_BOOKMARK = '全景总览'
async function onEngineReady() {
if (!useCloudFrame.value || engineReadyDone || engineBootstrapping) return
......@@ -412,8 +393,8 @@ async function onEngineReady() {
syncCameraMarkers(true)
applyCameraVisibility()
await syncModePois()
// 视角飞到「全景总览」默认相机,图标仍只留压差
flyToViewpoint(OVERVIEW_BOOKMARK)
// 就绪后飞默认相机;底栏「全景总览」另飞「主视图」
flyToViewpoint(DEFAULT_BOOKMARK)
// 引擎稍晚才 hydrate marker 列表,再补两次压差过滤
window.setTimeout(() => {
if (!markersSynced) syncCameraMarkers(true)
......@@ -431,27 +412,28 @@ async function onEngineReady() {
}
}
function cameraIconsVisible() {
return activeMode.value === 'home' || activeMode.value === 'camera'
}
/** 监控图标已改由设施 sensors(useScreenModePois)按分类显示,视频台账点仅用于点击预览匹配,不再向场景打点 */
function applyCameraVisibility() {
const show = cameraIconsVisible()
for (const d of cameras.value) {
if (!d.scenePoint) continue
bridge.setMarkerVisible(d.id, show)
bridge.setMarkerVisible(d.id, false)
}
}
function syncCameraMarkers(force = false) {
if (!useCloudFrame.value) return
if (markersSynced && !force) return
const list = cameraMarkerList()
if (!list.length) return
// 批量一次写入即可(逐条 + 批量会触发多次场景刷新)
bridge.addMarkers(list)
// 卸掉历史视频台账 Marker,避免与设施摄像头重复
for (const d of cameras.value) {
if (!d.scenePoint) continue
try {
bridge.setMarkerVisible(d.id, false)
bridge.removeMarker(d.id)
} catch {
/* ignore */
}
}
markersSynced = true
applyCameraVisibility()
}
function normalizeCamKey(v: unknown): string {
......@@ -698,8 +680,8 @@ function onSelectArea(areaId: string) {
}
function onSelectOverview() {
// 只飞到主视图书签,不改点位显隐(保持当前分类图标)
activeAreaId.value = OVERVIEW_AREA_ID
screenMode.setMode('home')
if (useCloudFrame.value) flyToViewpoint(OVERVIEW_BOOKMARK)
}
......
......@@ -131,7 +131,7 @@ function previewMarker(): RtengineMarker | null {
z: p.z,
tag0: 'pick-preview',
tag1: PREVIEW_ID,
scale: 1,
scale: 0.5,
icon: textOnly ? '' : (selectedIcon.value || '').trim(),
leader: true,
leaderHeight: MARKER_LEADER_HEIGHT_M,
......
......@@ -21,7 +21,7 @@ export function useMetricHistory(
source: q.source,
metric: q.metric,
hours: String(q.hours ?? 24),
bucketMinutes: String(q.bucketMinutes ?? 15),
bucketMinutes: String(q.bucketMinutes ?? 60),
})
const res = await api<{ series: HistorySeries[] }>(`/api/realtime/history?${params}`)
series.value = res.series || []
......
......@@ -122,8 +122,16 @@ const FACILITY_ICON_FALLBACK: Record<string, string> = {
access: 'access-control-blue.png',
}
function toSensorMarker(s: SensorSnapshot): RtengineMarker {
/** 引擎常见监控图标;cctv.png 若不存在则回落 cctv-blue */
function resolveFacilityIcon(s: SensorSnapshot): string {
const fallback = FACILITY_ICON_FALLBACK[s.category] || MODE_MARKER_ICON.pressure
const raw = (s.icon || '').trim()
if (!raw) return fallback
if (s.category === 'camera' && raw === 'cctv.png') return 'cctv-blue.png'
return raw
}
function toSensorMarker(s: SensorSnapshot): RtengineMarker {
const tag0 =
s.category in DEVICE_TAG
? DEVICE_TAG[s.category as keyof typeof DEVICE_TAG]
......@@ -143,7 +151,7 @@ function toSensorMarker(s: SensorSnapshot): RtengineMarker {
tag1: s.id,
scale: MODE_MARKER_SCALE,
// 压差:只显示温湿度压差文字,不挂图标
...(textOnly ? { icon: '' } : { icon: (s.icon || '').trim() || fallback }),
...(textOnly ? { icon: '' } : { icon: resolveFacilityIcon(s) }),
...MARKER_LEADER,
}
}
......@@ -172,15 +180,15 @@ function markersForMode(mode: ScreenMode, snap: RealtimeSnapshot): RtengineMarke
if (mode === 'vav') {
return sensorsOf(snap, 'vav').map(toSensorMarker)
}
// 监控点由 SceneViewport 视频台账打点,避免与设施重复
// 监控与门禁一致:走设施快照(含三维坐标/图标)
if (mode === 'camera') {
return []
return sensorsOf(snap, 'camera').map(toSensorMarker)
}
if (mode === 'access') {
return sensorsOf(snap, 'access').map(toSensorMarker)
}
if (mode === 'home') {
return sensorsOf(snap, 'pressure', 'lightN', 'lightE', 'fridge', 'vav', 'access').map(
return sensorsOf(snap, 'pressure', 'lightN', 'lightE', 'fridge', 'vav', 'access', 'camera').map(
toSensorMarker,
)
}
......@@ -228,7 +236,7 @@ export function useScreenModePois(bridge: BridgeLike, enabled: Ref<boolean>, _cl
/** 当前分类应显示的 tag0 集合 */
function tagsForMode(current: ScreenMode): Set<string> {
if (current === 'home') {
return new Set(ALL_DEVICE_TAGS.filter((t) => t !== 'camera'))
return new Set(ALL_DEVICE_TAGS)
}
if (current === 'e066') return new Set()
if (current in DEVICE_TAG) {
......@@ -241,7 +249,7 @@ export function useScreenModePois(bridge: BridgeLike, enabled: Ref<boolean>, _cl
return [...showTags].sort().join(',')
}
/** 引擎预设 / CAD 点:按分类显隐(摄像头留给 SceneViewport) */
/** 引擎预设 / CAD 点:按分类显隐(含监控 tag) */
function applyCadVisibility(current: ScreenMode, force = false) {
const showTags = tagsForMode(current)
const sig = tagVisSig(showTags)
......@@ -254,7 +262,6 @@ export function useScreenModePois(bridge: BridgeLike, enabled: Ref<boolean>, _cl
// 仅分类切换时才对引擎做 tag 级 show/hide(整屏刷新很重)
if (force || !modeSame || !tagsSame) {
for (const tag of ALL_DEVICE_TAGS) {
if (tag === 'camera') continue
if (showTags.has(tag)) bridge.showPois(tag)
else bridge.hidePois(tag)
}
......@@ -263,9 +270,9 @@ export function useScreenModePois(bridge: BridgeLike, enabled: Ref<boolean>, _cl
const live = bridge.listMarkers?.() || []
for (const marker of live) {
if (marker.id.startsWith(PREFIX)) continue
if (marker.id.startsWith('cam:') || marker.tag0 === 'camera') continue
if (marker.id.startsWith(SENSOR_PREFIX)) continue
const cat = categoryOfMarker(marker)
if (!cat || cat === 'camera') continue
if (!cat) continue
const show = current === 'home' || showTags.has(cat) || showTags.has(marker.tag0)
bridge.setMarkerVisible(marker.id, show)
}
......@@ -354,7 +361,6 @@ export function useScreenModePois(bridge: BridgeLike, enabled: Ref<boolean>, _cl
lastCadMode = ''
lastTagVisSig = ''
for (const tag of ALL_DEVICE_TAGS) {
if (tag === 'camera') continue
bridge.hidePois(tag)
}
} else {
......
......@@ -31,7 +31,7 @@ export const DEVICE_TAG: Record<DeviceCategory, string> = {
access: 'access',
}
export const MODE_MARKER_SCALE = 1
export const MODE_MARKER_SCALE = 0.5
export const SCREEN_MODES: { id: ScreenMode; label: string }[] = [
{ id: 'home', label: '全景总览' },
......
......@@ -96,6 +96,7 @@ export default {
envQualified: '{ok}/{total} OK',
deviceLedger: 'Device ledger',
envEmpty: 'Room T/H pending',
roomHumidityEmpty: 'Room humidity history accumulating',
roomTempEmpty: 'Room temp history accumulating',
coldTitle: 'Cold chain · 24h',
coldEmpty: 'Fridge temp history accumulating',
......
......@@ -96,6 +96,7 @@ export default {
envQualified: '{ok}/{total} OK',
deviceLedger: 'Inventário',
envEmpty: 'T/H das salas pendente',
roomHumidityEmpty: 'Histórico de humidade a acumular',
roomTempEmpty: 'Histórico de temp. a acumular',
coldTitle: 'Cadeia de frio · 24h',
coldEmpty: 'Histórico de frigoríficos a acumular',
......
......@@ -96,6 +96,7 @@ export default {
envQualified: '{ok}/{total} 合格',
deviceLedger: '设备台账',
envEmpty: '房间温湿度待采集',
roomHumidityEmpty: '房间湿度历史积累中',
roomTempEmpty: '房间温度历史积累中',
coldTitle: '冷链监测 · 24h',
coldEmpty: '冰箱温度历史积累中',
......
......@@ -96,6 +96,7 @@ export default {
envQualified: '{ok}/{total} 合格',
deviceLedger: '設備台帳',
envEmpty: '房間溫濕度待採集',
roomHumidityEmpty: '房間濕度歷史累積中',
roomTempEmpty: '房間溫度歷史累積中',
coldTitle: '冷鏈監測 · 24h',
coldEmpty: '冰箱溫度歷史累積中',
......
......@@ -22,7 +22,10 @@ const chartMuted = 'rgba(158,200,220,0.35)'
function formatTick(t: number) {
const d = new Date(t)
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}`
const hh = String(d.getHours()).padStart(2, '0')
const mm = d.getMinutes()
// 整点只显示小时,避免轴标签过密
return mm === 0 ? `${hh}:00` : `${hh}:${String(mm).padStart(2, '0')}`
}
/** 多设备历史折线(统一时间轴) */
......
......@@ -21,10 +21,10 @@ async function load() {
try {
const [tempRes, humidityRes] = await Promise.all([
api<{ series: typeof series.value }>(
'/api/realtime/history?source=fridge&metric=temp&hours=24&bucketMinutes=15',
'/api/realtime/history?source=fridge&metric=temp&hours=24&bucketMinutes=60',
),
api<{ series: typeof humidity.value }>(
'/api/realtime/history?source=fridge&metric=humidity&hours=24&bucketMinutes=15',
'/api/realtime/history?source=fridge&metric=humidity&hours=24&bucketMinutes=60',
),
])
series.value = tempRes.series || []
......
......@@ -7,7 +7,7 @@ import EChart, { type ECOption } from '@/components/charts/EChart.vue'
import { useScreenDashboard } from '@/composables/useScreenDashboard'
import { useRealtimeStore } from '@/stores/realtime'
import { multiLineOption, toHistorySeries } from '@/utils/historyChart'
import { compactTooltipBase, pieTooltip, roundNum } from '@/utils/chartTooltip'
import { pieTooltip } from '@/utils/chartTooltip'
const { t, te } = useI18n()
const realtime = useRealtimeStore()
......@@ -66,7 +66,6 @@ const kpiItems = computed<KpiFlipItem[]>(() => {
})
const chartText = '#9ec8dc'
const chartMuted = 'rgba(158,200,220,0.35)'
function statusLabel(key: string | undefined, fallback: string) {
if (key && te(`status.${key}`)) return t(`status.${key}`)
......@@ -89,75 +88,13 @@ function pauLabel(key: string | undefined, fallback: string) {
return fallback
}
/** 左1:环境气泡图 温度×湿度,大小=|压差| */
const envBubbleOption = computed<ECOption>(() => {
const rows = (data.value?.envBubbles || []).filter(
(b) => b.temp !== null && b.humidity !== null,
)
return {
backgroundColor: 'transparent',
animation: false,
animationDurationUpdate: 0,
grid: { left: 36, right: 12, top: 28, bottom: 28 },
tooltip: {
...compactTooltipBase,
trigger: 'item',
formatter: (p: unknown) => {
const x = p as {
data?: { name?: string; value?: number[]; pressure?: number | null }
}
const d = x.data
if (!d?.value) return ''
return (
`<div style="font-size:11px;color:#e8fbff;font-weight:600">${d.name ?? ''}</div>` +
`<div style="font-size:10px;margin-top:2px">${t('overview.tipTemp', {
temp: roundNum(d.value[0]),
humidity: roundNum(d.value[1]),
})}</div>` +
`<div style="font-size:10px">${t('overview.tipPressure', {
pressure: roundNum(d.pressure),
})}</div>`
)
},
},
xAxis: {
name: '℃',
nameTextStyle: { color: chartMuted, fontSize: 10 },
axisLabel: { color: chartText, fontSize: 10 },
splitLine: { lineStyle: { color: 'rgba(0,247,255,0.08)' } },
axisLine: { lineStyle: { color: chartMuted } },
},
yAxis: {
name: '%RH',
nameTextStyle: { color: chartMuted, fontSize: 10 },
axisLabel: { color: chartText, fontSize: 10 },
splitLine: { lineStyle: { color: 'rgba(0,247,255,0.08)' } },
axisLine: { lineStyle: { color: chartMuted } },
},
series: [
{
type: 'scatter',
symbolSize: (val: number[]) =>
Math.max(10, Math.min(36, Math.abs(Number(val[2]) || 0) * 1.2 + 10)),
data: rows.map((b) => ({
value: [
Math.round(b.temp! * 10) / 10,
Math.round(b.humidity! * 10) / 10,
Math.round(Math.abs(b.pressure ?? 0) * 10) / 10,
],
name: b.name,
pressure: b.pressure == null ? null : Math.round(b.pressure * 10) / 10,
itemStyle: {
color: b.ok ? 'rgba(82,196,26,0.85)' : 'rgba(250,173,20,0.9)',
},
})),
},
],
}
})
const curves = computed(() => data.value?.curves)
/** 环境总览上图:仅湿度历史曲线 */
const roomHumidityHistoryOption = computed<ECOption>(() =>
multiLineOption(curves.value?.roomHumidity || [], { unit: '%RH', maxSeries: 10 }),
)
const roomTempHistoryOption = computed<ECOption>(() =>
multiLineOption(curves.value?.roomTemp || [], { unit: '℃', maxSeries: 10 }),
)
......@@ -305,7 +242,11 @@ const energyDigits = computed(() => digits.value)
</span>
</template>
<div class="panel-stack">
<EChart class="chart-main" :option="envBubbleOption" :empty-text="t('overview.envEmpty')" />
<EChart
class="chart-main"
:option="roomHumidityHistoryOption"
:empty-text="t('overview.roomHumidityEmpty')"
/>
<EChart
class="chart-sub"
:option="roomTempHistoryOption"
......@@ -532,6 +473,7 @@ const energyDigits = computed(() => digits.value)
border-radius: 4px;
background: rgba(6, 28, 56, 0.45);
border: 1px solid rgba(0, 247, 255, 0.14);
text-align: center;
}
.digit-card.warn {
border-color: rgba(250, 173, 20, 0.4);
......@@ -550,7 +492,7 @@ const energyDigits = computed(() => digits.value)
}
.d-value small {
font-size: 10px;
color: rgba(200, 230, 245, 0.65);
color: #52c41a;
font-weight: 500;
}
.energy-digits {
......
......@@ -147,6 +147,29 @@ function pickPreferredIcons(s: Sensor | null) {
return SENSOR_PREFERRED_ICONS[s.category] || Object.values(FACILITY_DEFAULT_ICON)
}
/** 摄像头/门禁通信参数(对齐交底表:IP通道地址、协议、管理端口、用户名、密码) */
type CommForm = {
ip: string
protocol: string
port: string
username: string
password: string
}
function emptyComm(): CommForm {
return { ip: '', protocol: '海康威视', port: '8000', username: 'admin', password: '' }
}
function needsComm(category: string) {
return category === 'camera' || category === 'access'
}
function metaStr(meta: Record<string, unknown> | undefined, key: string, fallback = '') {
const v = meta?.[key]
if (v == null) return fallback
return String(v)
}
const form = reactive({
code: '',
name: '',
......@@ -165,6 +188,7 @@ const form = reactive({
airflow: '',
alarmCode: '',
} as Record<string, string>,
comm: emptyComm(),
})
function matchKeyword(parts: Array<string | number | null | undefined>, q: string) {
......@@ -249,6 +273,7 @@ function openCreate() {
airflow: '',
alarmCode: '',
}
form.comm = emptyComm()
error.value = ''
showEdit.value = true
}
......@@ -276,10 +301,37 @@ function openEdit(s: Sensor) {
for (const b of s.points || []) {
form.roles[b.role] = b.pointId
}
const meta = s.meta || {}
form.comm = {
ip: metaStr(meta, 'ip'),
protocol: metaStr(meta, 'protocol', '海康威视'),
port: metaStr(meta, 'port', '8000'),
username: metaStr(meta, 'username', 'admin'),
password: metaStr(meta, 'password'),
}
error.value = ''
showEdit.value = true
}
function buildMetaPayload(existing?: Record<string, unknown>) {
const meta: Record<string, unknown> = { ...(existing || {}) }
if (!needsComm(form.category)) {
delete meta.ip
delete meta.protocol
delete meta.port
delete meta.username
delete meta.password
return meta
}
meta.ip = form.comm.ip.trim()
meta.protocol = form.comm.protocol.trim() || '海康威视'
const portNum = Number(form.comm.port)
meta.port = Number.isFinite(portNum) && portNum > 0 ? portNum : 8000
meta.username = form.comm.username.trim()
meta.password = form.comm.password
return meta
}
function closeEdit() {
showEdit.value = false
error.value = ''
......@@ -303,6 +355,9 @@ async function save() {
saving.value = true
error.value = ''
message.value = ''
const current = editingId.value
? sensors.value.find((s) => s.id === editingId.value)
: undefined
const body = {
code,
name,
......@@ -312,6 +367,7 @@ async function save() {
sceneY: Number(form.sceneY),
sceneZ: Number(form.sceneZ),
points: buildPointsPayload(),
meta: buildMetaPayload(current?.meta),
}
try {
if (editingId.value) {
......@@ -411,7 +467,7 @@ onMounted(load)
</div>
<p class="desc">
设施含压差、照明 N/E 电、冰箱、通风柜、摄像头、门禁(后四类与交底表对齐)。摄像头/门禁无采集点绑定,可通过「三维打点」调整坐标与图标。
设施含压差、照明 N/E 电、冰箱、通风柜、摄像头、门禁(后四类与交底表对齐)。摄像头/门禁可编辑通信参数(IP、协议、管理端口、用户名、密码),并通过「三维打点」调整坐标与图标。
</p>
<div class="filters">
......@@ -449,7 +505,7 @@ onMounted(load)
<th>分类</th>
<th>启用</th>
<th>坐标</th>
<th>绑定点位</th>
<th>绑定点位 / 通信</th>
<th>操作</th>
</tr>
</thead>
......@@ -471,7 +527,14 @@ onMounted(load)
<td class="mono">
{{ s.sceneX.toFixed(6) }}, {{ s.sceneY.toFixed(6) }}, {{ s.sceneZ }}
</td>
<td class="binds">{{ bindsSummary(s) }}</td>
<td class="binds">
<template v-if="needsComm(s.category)">
{{ metaStr(s.meta, 'ip') || '未配置 IP' }}
<span v-if="metaStr(s.meta, 'port')"> · :{{ metaStr(s.meta, 'port') }}</span>
<span v-if="metaStr(s.meta, 'protocol')"> · {{ metaStr(s.meta, 'protocol') }}</span>
</template>
<template v-else>{{ bindsSummary(s) }}</template>
</td>
<td class="ops">
<button
v-if="auth.isAdmin"
......@@ -556,18 +619,58 @@ onMounted(load)
</div>
</div>
<h4 class="sub">点位绑定</h4>
<div class="form-grid roles">
<div v-for="role in rolesForCategory(form.category)" :key="role" class="field">
<label>{{ ROLE_LABEL[role] || role }}</label>
<select v-model="form.roles[role]">
<option value="">— 未选择 —</option>
<option v-for="p in pointOptions" :key="p.id" :value="p.id">
{{ pointLabel(p) }}
</option>
</select>
<template v-if="needsComm(form.category)">
<h4 class="sub">通信参数</h4>
<p class="comm-hint">参考交底表:IP 通道地址、协议、管理端口、用户名、密码。</p>
<div class="form-grid">
<div class="field">
<label>IP 通道地址</label>
<input v-model="form.comm.ip" type="text" placeholder="192.168.10.150" autocomplete="off" />
</div>
<div class="field">
<label>协议</label>
<input v-model="form.comm.protocol" type="text" placeholder="海康威视" list="comm-protocol-list" />
<datalist id="comm-protocol-list">
<option value="海康威视" />
<option value="sdk" />
<option value="rtsp" />
<option value="isapi" />
</datalist>
</div>
<div class="field">
<label>管理端口</label>
<input v-model="form.comm.port" type="text" placeholder="8000" inputmode="numeric" />
</div>
<div class="field">
<label>用户名</label>
<input v-model="form.comm.username" type="text" placeholder="admin" autocomplete="username" />
</div>
<div class="field">
<label>密码</label>
<input
v-model="form.comm.password"
type="password"
placeholder="设备登录密码"
autocomplete="new-password"
/>
</div>
</div>
</div>
</template>
<template v-else>
<h4 class="sub">点位绑定</h4>
<div class="form-grid roles">
<div v-for="role in rolesForCategory(form.category)" :key="role" class="field">
<label>{{ ROLE_LABEL[role] || role }}</label>
<select v-model="form.roles[role]">
<option value="">— 未选择 —</option>
<option v-for="p in pointOptions" :key="p.id" :value="p.id">
{{ pointLabel(p) }}
</option>
</select>
</div>
</div>
</template>
<p v-if="error" class="msg err">{{ error }}</p>
<div class="modal-actions">
......@@ -731,6 +834,12 @@ onMounted(load)
font-size: 13px;
color: #eaf4ff;
}
.comm-hint {
margin: -4px 0 10px;
font-size: 12px;
color: var(--panel-muted);
line-height: 1.45;
}
.modal-actions {
margin-top: 14px;
display: flex;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment