2024-02-15 22:07:50 +01:00
< ? php include ( " ./link/session.php " ) ?>
<! doctype html >
< html lang = " uft-8 " >
< head >
< ? php include ( " ./public/head.inc " ) ?>
</ head >
< body >
< ? php include ( " ./public/menu.inc " ) ?>
< div data - simplebar >
< main class = " page-content dashboard " id = " app " v - cloak >
< div class = " row " >
< div class = " col-lg-6 " >
< div class = " card " >
< div class = " card-header bg-transparent " >
< div class = " p-2 mb-0 d-flex align-items-end " >
< cn > 系统状态 </ cn >
< en > System state </ en >
</ div >
</ div >
< div class = " card-body " >
< div class = " row row-cols-3 text-center " >
< div class = " col-lg-4 " >
< pie - chart v - model = " cpu " : active - color = " theme_color " ></ pie - chart >
< div >
< cn > CPU使用率 </ cn >
< en > CPU usage </ en >
</ div >
</ div >
< div class = " col-lg-4 text-center " >
< pie - chart v - model = " mem " : active - color = " theme_color " ></ pie - chart >
< div >
< cn > 内存使用率 </ cn >
< en > Memory usage </ en >
</ div >
</ div >
< div class = " col-lg-4 text-center " >
2024-02-15 22:07:52 +01:00
< tmp - compt v - model = " tmp " : active - color = " theme_color " ></ tmp - compt >
2024-02-15 22:07:50 +01:00
< div >
< cn > 核心温度 </ cn >
< en > Core temperature </ en >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
< div class = " col-lg-6 " >
< div class = " card " >
< div class = " card-header bg-transparent " >
< div class = " p-2 mb-0 d-flex align-items-end " >
< cn > 网络状态 </ cn >
< en > Network state </ en >
</ div >
</ div >
< div class = " card-body " >
< net - chart v - if = " tx.length > 0 " : maxy = " maxy " : data1 = " tx " : data2 = " rx " : key = " netFlotKey "
: line1 - color = " theme_color " : line2 - color = " line2_color " : tick - color = " tickColor " : border - color = " borderColor "
: tip - border - color = " tipBorderColor " : tip - bg - color = " tipBgColor " : tip - txt - color = " tipTxtColor " ></ net - chart >
</ div >
</ div >
</ div >
</ div >
< div class = " row " >
< div class = " col-lg-12 " >
< div class = " card " >
< div class = " card-body iface py-3 " >
< div v - for = " (item,index) in input " : key = " index " : class = " ['me-5', { 'hdmi':item.protocol==='HDMI'}, { 'sdi':item.protocol==='SDI'}, { 'disable':!item.avalible}] " >
< span class = " info " > {{ item . info }} </ span >
< div class = " icon my-1 " ></ div >
< span class = " name " > {{ item . name }} </ span >
</ div >
</ div >
</ div >
</ div >
</ div >
< div class = " row mt-2 " >
< div class = " col-lg-12 " >
< div class = " card " >
< div class = " card-header bg-transparent " >
< div class = " p-2 mb-0 d-flex align-items-end " >
< cn > 预览 </ cn >
< en > Preview </ en >
< small style = " margin-left: 5px;color: grey;font-size: 12px; " >
< cn > 非实时视频,仅预览图片 </ cn >
< en > Not a realtime video , picture only </ en >
</ small >
</ div >
</ div >
< div class = " card-body " >
< div class = " row row-cols-2 row-cols-lg-4 g-3 " >
< div v - for = " (item,index) in preview " : key = " index " class = " col " >
< div class = " card " >
< img : src = " makeImgUrl(item.id) " class = " card-img-top " >
< div class = " chn-volume " : style = " { 'width':handleChnVolume(item.id,'L')} " ></ div >
< div class = " chn-volume " : style = " { 'width':handleChnVolume(item.id,'R')} " ></ div >
< div class = " card-body " >
< p class = " card-text text-center " > {{ item . name }} </ p >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ div >
</ main >
</ div >
< ? php include ( " ./public/foot.inc " ) ?>
< script src = " assets/plugins/easyPieChart/jquery.easypiechart.js " type = " module " ></ script >
< script src = " assets/plugins/flotChart/jquery.flot.js " type = " module " ></ script >
< script src = " assets/plugins/flotChart/jquery.flot.resize.js " type = " module " ></ script >
< script type = " module " >
import { rpc } from " ./assets/js/lp.utils.js " ;
2024-02-15 22:07:52 +01:00
import { useDefaultConf } from " ./assets/js/vue.hooks.js " ;
2024-02-15 22:07:50 +01:00
import { ignoreCustomElementPlugin , bootstrapSwitchComponent , statusPieChartComponent , statusTemperatureComponent , netFlotChartComponent } from " ./assets/js/vue.helper.js "
import vue from " ./assets/js/vue.build.js " ;
import mutationObserver from './assets/plugins/polyfill/mutationobserver.esm.js' ;
const { createApp , ref , reactive , onMounted } = vue ;
const app = createApp ({
components : {
" bs-switch " : bootstrapSwitchComponent ,
" net-chart " : netFlotChartComponent ,
" pie-chart " : statusPieChartComponent ,
" tmp-compt " : statusTemperatureComponent
},
setup ( prop , context ){
const state = {
cpu : ref ( 0 ),
tmp : ref ( 0 ),
mem : ref ( 0 ),
maxy : ref ( 0 ),
tx : reactive ([]),
rx : reactive ([]),
data1 : reactive ([]),
data2 : reactive ([]),
theme_color : ref ( " #ffbb00 " ),
line2_color : ref ( " #555555 " ),
tipBorderColor : ref ( " #ffbb00 " ),
tipBgColor : ref ( " #ffffff " ),
tipTxtColor : ref ( " #555555 " ),
tickColor : ref ( " #eeeeee " ),
borderColor : ref ( " #cccccc " ),
netFlotKey : ref ( 0 ),
preview : reactive ([]),
input : reactive ([]),
volume : reactive ([])
}
const { defaultConf } = useDefaultConf ();
const getData1 = ( d ) => {
state . data1 . shift ();
state . data1 . push ( d );
state . tx . splice ( 0 );
for ( let i = 0 ; i < 100 ; i ++ )
state . tx . push ([ i , state . data1 [ i ]]);
}
const getData2 = ( d ) => {
state . data2 . shift ();
state . data2 . push ( d );
state . rx . splice ( 0 );
for ( let i = 0 ; i < 100 ; i ++ )
state . rx . push ([ i , state . data2 [ i ]]);
}
const updateNetState = () => {
if ( state . data1 . length === 0 && state . data2 . length === 0 ) {
for ( let i = 0 ; i < 100 ; i ++ ) {
state . data1 . push ( 0 );
state . data2 . push ( 0 );
}
}
rpc ( " enc.getNetState " ) . then ( data => {
getData1 ( data . tx );
getData2 ( data . rx );
if ( data . tx * 1.3 > state . maxy . value )
state . maxy . value = data . tx * 1.3 ;
if ( data . rx * 1.3 > state . maxy . value )
state . maxy . value = data . rx * 1.3 ;
if ( state . maxy . value < 1024 )
state . maxy . value = Math . ceil ( state . maxy . value / 100 ) * 100 ;
else
state . maxy . value = Math . ceil ( state . maxy . value / 1024 ) * 1024 ;
if ( state . maxy . value > 1024000 )
state . maxy . value = 1024000 ;
setTimeout ( updateNetState , 500 );
});
}
const updateSysState = () => {
rpc ( " enc.getSysState " ) . then ( data => {
state . cpu . value = data . cpu ;
state . mem . value = data . mem ;
state . tmp . value = data . temperature ;
setTimeout ( updateSysState , 2000 );
});
}
const makeImgUrl = ( id ) => {
return " snap/snap " + id + " .jpg?rnd= " + Math . random ();
}
const updatePreview = () => {
if ( state . preview . length === 0 ) {
for ( let i = 0 ; i < defaultConf . length ; i ++ ) {
if ( ! defaultConf [ i ] . enable || ( defaultConf [ i ] . type === " net " && ! defaultConf [ i ] . net . decodeV ))
continue ;
state . preview . push ( defaultConf [ i ]);
}
}
setTimeout (() => rpc ( " enc.snap " ), 300 );
setTimeout ( updatePreview , 800 );
}
const handleChnVolume = ( chnId , type ) => {
let volume = state . volume . filter (( item , index ) => {
return chnId === index ;
})
let retVal = 0 ;
if ( volume . length > 0 )
retVal = volume [ 0 ][ type ] * 100 / 96 ;
return retVal + " % " ;
}
const updateVolume = () => {
rpc ( " enc.getVolume " ) . then ( data => {
state . volume . splice ( 0 , state . volume . length , ... data );
});
if ( window . location . host === " wx.linkpi.cn " )
setTimeout ( updateVolume , 1000 );
else
setTimeout ( updateVolume , 500 );
}
const updateInputState = () => {
rpc ( " enc.getInputState " ) . then ( ret => {
state . input . splice ( 0 , state . input . length , ... ret );
for ( let i = 0 ; i < state . input . length ; i ++ ) {
let ipt = state . input [ i ];
ipt . info = " - - - " ;
if ( ipt . avalible )
ipt . info = " " + ipt . height + ( ipt . interlace ? " I " : " P " ) + ipt . framerate ;
state . input [ i ] = ipt ;
}
});
setTimeout ( updateInputState , 3000 );
}
const onListenThemeChange = () => {
const html = document . querySelector ( 'html' );
const observer = new mutationObserver ( mutations => {
mutations . forEach ( mutation => {
if ( mutation . type === 'attributes' && mutation . attributeName === " data-bs-theme " ) {
const theme = mutation . target . getAttribute ( " data-bs-theme " );
if ( theme === " default " ) {
state . tickColor . value = '#eee' ;
state . borderColor . value = '#ccc' ;
state . tipBgColor . value = '#fff' ;
state . tipBorderColor . value = '#fb0' ;
state . tipTxtColor . value = '#555' ;
state . line2_color . value = '#555' ;
}
if ( theme === " dark " ) {
state . tickColor . value = '#555' ;
state . borderColor . value = '#555' ;
state . tipBgColor . value = '#333' ;
state . tipBorderColor . value = '#aaa' ;
state . tipTxtColor . value = '#adb5bd' ;
state . line2_color . value = '#999' ;
}
state . netFlotKey . value ++ ;
}
});
});
const config = {
attributes : true ,
attributeFilter : [ " data-bs-theme " ],
subtree : false
};
observer . observe ( html , config );
}
onMounted (() => {
updateSysState ();
updateNetState ();
updatePreview ();
updateInputState ();
updateVolume ();
onListenThemeChange ();
}
)
return { ... state , makeImgUrl , handleChnVolume }
}
})
app . use ( ignoreCustomElementPlugin );
app . mount ( '#app' )
</ script >
</ body >
</ html >