@ -49,6 +49,7 @@
] "
] "
@ mouseenter = "item.defectCarousel && pauseDefectCarousel()"
@ mouseenter = "item.defectCarousel && pauseDefectCarousel()"
@ mouseleave = "item.defectCarousel && startDefectCarousel()"
@ mouseleave = "item.defectCarousel && startDefectCarousel()"
@ click = "item.defectCarousel && openDefectRecords(activeDefectSlide)"
>
>
< template v-if ="item.defectCarousel" >
< template v-if ="item.defectCarousel" >
< div class = "overview-defect-viewport" >
< div class = "overview-defect-viewport" >
@ -186,7 +187,7 @@
< / e l - s e l e c t >
< / e l - s e l e c t >
< / div >
< / div >
< div class = "video-monitor-body" : class = "{ 'tree-visible': treeVisible }" >
< div class = "video-monitor-body" >
< div class = "video-monitor-main" >
< div class = "video-monitor-main" >
< div class = "camera-stats" >
< div class = "camera-stats" >
< div
< div
@ -228,10 +229,10 @@
< path d = "M32 20l12-6v20l-12-6z" fill = "none" stroke = "currentColor" stroke -width = " 2.4 " stroke -linejoin = " round " / >
< path d = "M32 20l12-6v20l-12-6z" fill = "none" stroke = "currentColor" stroke -width = " 2.4 " stroke -linejoin = " round " / >
< circle cx = "18" cy = "23" r = "5" fill = "none" stroke = "currentColor" stroke -width = " 2.4 " / >
< circle cx = "18" cy = "23" r = "5" fill = "none" stroke = "currentColor" stroke -width = " 2.4 " / >
< / svg >
< / svg >
< span class = "video-loading" > { { video . playbackError ? '视频加载失败 ' : ( video . loading ? '正在连接' : '等待视频' ) } } < / span >
< span class = "video-loading" > { { video . playbackError ? '等待 视频' : ( video . loading ? '正在连接' : '等待视频' ) } } < / span >
< / div >
< / div >
< div class = "video-mask" / >
< div class = "video-mask" / >
< span class = "video-dot" : class = "video.status === 'abnormal' ? 'abnormal' : 'normal'" / >
< span class = "video-dot" : class = "video.playbackError || video. status === 'abnormal' ? 'abnormal' : 'normal'" / >
< div class = "video-labels" >
< div class = "video-labels" >
< div class = "video-station" > { { video . stationName } } < / div >
< div class = "video-station" > { { video . stationName } } < / div >
< div class = "video-camera" > { { video . cameraName } } < / div >
< div class = "video-camera" > { { video . cameraName } } < / div >
@ -362,10 +363,10 @@ function createEmptyTrend() {
}
}
const DEFECT_SLIDES = [
const DEFECT_SLIDES = [
{ key : "slight" , label : "轻微缺陷" , fields : [ "slightDefects" , "minorDefects" ] } ,
{ key : "general" , label : "一般缺陷" , fields : [ "generalDefects" , "normalDefects" ] } ,
{ key : "serious" , label : "严重缺陷" , fields : [ "seriousDefects" ] } ,
{ key : "urgent" , label : "重大缺陷" , fields : [ "urgentDefects" ] }
{ key : "slight" , label : "轻微缺陷" , defectLevel : "4" , fields : [ "slightDefects" , "minorDefects" ] } ,
{ key : "general" , label : "一般缺陷" , defectLevel : "3" , fields : [ "generalDefects" , "normalDefects" ] } ,
{ key : "serious" , label : "严重缺陷" , defectLevel : "2" , fields : [ "seriousDefects" ] } ,
{ key : "urgent" , label : "重大缺陷" , defectLevel : "1" , fields : [ "urgentDefects" ] }
] ;
] ;
/ / 场 站 卡 片 下 方 的 缺 陷 趋 势 快 捷 筛 选
/ / 场 站 卡 片 下 方 的 缺 陷 趋 势 快 捷 筛 选
@ -404,7 +405,7 @@ export default {
navItems : [
navItems : [
{ key : "home" , label : "首页" } ,
{ key : "home" , label : "首页" } ,
{ key : "patrol" , label : "动环巡检" } ,
{ key : "patrol" , label : "动环巡检" } ,
/ / { k e y : " s y s t e m " , l a b e l : " 系 统 管 理 " }
{ key : "system" , label : "系统管理" }
] ,
] ,
stationButtons : STATION_BUTTONS ,
stationButtons : STATION_BUTTONS ,
defectSlides : DEFECT_SLIDES ,
defectSlides : DEFECT_SLIDES ,
@ -429,8 +430,10 @@ export default {
treeVisible : false ,
treeVisible : false ,
treeMounted : false ,
treeMounted : false ,
portalPlayers : { } ,
portalPlayers : { } ,
portalPlayTimers : { } ,
portalStartTimers : { } ,
portalStartTimers : { } ,
portalStartRequests : { } ,
portalStartRequests : { } ,
portalAttemptedCodes : { } ,
portalRequestSource : null ,
portalRequestSource : null ,
portalAlive : true ,
portalAlive : true ,
portalReleased : false ,
portalReleased : false ,
@ -624,6 +627,7 @@ export default {
return this . stopPortalVideos ( ) . then ( ( ) => {
return this . stopPortalVideos ( ) . then ( ( ) => {
/ / 切 页 后 停 流 才 返 回 时 , 不 能 再 把 播 放 器 挂 回 去 。
/ / 切 页 后 停 流 才 返 回 时 , 不 能 再 把 播 放 器 挂 回 去 。
if ( ! this . portalAlive ) return ;
if ( ! this . portalAlive ) return ;
this . portalAttemptedCodes = { } ;
this . videoList = this . pickRandomVideos ( videos , 4 ) ;
this . videoList = this . pickRandomVideos ( videos , 4 ) ;
this . activeVideoIndex = 0 ;
this . activeVideoIndex = 0 ;
this . $nextTick ( ( ) => this . startDefaultPortalVideos ( ) ) ;
this . $nextTick ( ( ) => this . startDefaultPortalVideos ( ) ) ;
@ -659,8 +663,7 @@ export default {
this . $set ( video , "playUrl" , stream . hlsUrl ) ;
this . $set ( video , "playUrl" , stream . hlsUrl ) ;
this . $set ( video , "flvUrl" , stream . flvUrl ) ;
this . $set ( video , "flvUrl" , stream . flvUrl ) ;
if ( ! stream . hlsUrl && ! stream . flvUrl ) {
if ( ! stream . hlsUrl && ! stream . flvUrl ) {
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , true ) ;
this . advancePortalVideo ( video , index ) ;
return ;
return ;
}
}
this . $nextTick ( ( ) => this . attachPortalPlayer ( video , index ) ) ;
this . $nextTick ( ( ) => this . attachPortalPlayer ( video , index ) ) ;
@ -670,8 +673,7 @@ export default {
}
}
/ / 切 页 取 消 的 请 求 不 要 再 改 状 态 , 组 件 可 能 已 经 销 毁 。
/ / 切 页 取 消 的 请 求 不 要 再 改 状 态 , 组 件 可 能 已 经 销 毁 。
if ( ! this . portalAlive || ( error && error . code === "ERR_CANCELED" ) ) return ;
if ( ! this . portalAlive || ( error && error . code === "ERR_CANCELED" ) ) return ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , true ) ;
if ( this . videoList [ index ] === video ) this . advancePortalVideo ( video , index ) ;
}
}
} ,
} ,
attachPortalPlayer ( video , index ) {
attachPortalPlayer ( video , index ) {
@ -705,8 +707,10 @@ export default {
} ) ;
} ) ;
const player = { hls , element , stopped : false } ;
const player = { hls , element , stopped : false } ;
this . $set ( this . portalPlayers , index , player ) ;
this . $set ( this . portalPlayers , index , player ) ;
this . armPortalPlayTimeout ( video , index , player ) ;
const markPlaying = ( ) => {
const markPlaying = ( ) => {
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
this . clearPortalPlayTimer ( index ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , false ) ;
this . $set ( video , "playbackError" , false ) ;
} ;
} ;
@ -723,7 +727,9 @@ export default {
} ) ;
} ) ;
hls . on ( Hls . Events . ERROR , ( _ , detail ) => {
hls . on ( Hls . Events . ERROR , ( _ , detail ) => {
if ( this . portalPlayers [ index ] !== player || player . stopped || ! detail || ! detail . fatal ) return ;
if ( this . portalPlayers [ index ] !== player || player . stopped || ! detail || ! detail . fatal ) return ;
if ( flvUrl ) {
if ( flvUrl && ! player . flvFallbackUsed ) {
player . flvFallbackUsed = true ;
this . clearPortalPlayTimer ( index ) ;
this . attachPortalFlv ( video , index , element , flvUrl ) ;
this . attachPortalFlv ( video , index , element , flvUrl ) ;
return ;
return ;
}
}
@ -733,14 +739,18 @@ export default {
} else if ( hlsUrl && element . canPlayType ( "application/vnd.apple.mpegurl" ) ) {
} else if ( hlsUrl && element . canPlayType ( "application/vnd.apple.mpegurl" ) ) {
const player = { native : true , element , stopped : false } ;
const player = { native : true , element , stopped : false } ;
this . $set ( this . portalPlayers , index , player ) ;
this . $set ( this . portalPlayers , index , player ) ;
this . armPortalPlayTimeout ( video , index , player ) ;
element . onplaying = ( ) => {
element . onplaying = ( ) => {
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
this . clearPortalPlayTimer ( index ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , false ) ;
this . $set ( video , "playbackError" , false ) ;
} ;
} ;
element . onerror = ( ) => {
element . onerror = ( ) => {
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
if ( flvUrl ) {
if ( flvUrl && ! player . flvFallbackUsed ) {
player . flvFallbackUsed = true ;
this . clearPortalPlayTimer ( index ) ;
this . attachPortalFlv ( video , index , element , flvUrl ) ;
this . attachPortalFlv ( video , index , element , flvUrl ) ;
return ;
return ;
}
}
@ -751,14 +761,12 @@ export default {
} else if ( flvUrl ) {
} else if ( flvUrl ) {
this . attachPortalFlv ( video , index , element , flvUrl ) ;
this . attachPortalFlv ( video , index , element , flvUrl ) ;
} else {
} else {
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , true ) ;
this . advancePortalVideo ( video , index ) ;
}
}
} ,
} ,
attachPortalFlv ( video , index , element , url ) {
attachPortalFlv ( video , index , element , url ) {
if ( ! url || ! flvjs . isSupported ( ) ) {
if ( ! url || ! flvjs . isSupported ( ) ) {
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , true ) ;
this . advancePortalVideo ( video , index ) ;
return ;
return ;
}
}
this . destroyPortalPlayer ( index ) ;
this . destroyPortalPlayer ( index ) ;
@ -768,8 +776,10 @@ export default {
) ;
) ;
const player = { flv , element , stopped : false } ;
const player = { flv , element , stopped : false } ;
this . $set ( this . portalPlayers , index , player ) ;
this . $set ( this . portalPlayers , index , player ) ;
this . armPortalPlayTimeout ( video , index , player ) ;
const markPlaying = ( ) => {
const markPlaying = ( ) => {
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
if ( this . portalPlayers [ index ] !== player || player . stopped ) return ;
this . clearPortalPlayTimer ( index ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , false ) ;
this . $set ( video , "playbackError" , false ) ;
} ;
} ;
@ -784,54 +794,94 @@ export default {
this . failPortalPlayer ( player , video , index ) ;
this . failPortalPlayer ( player , video , index ) ;
} ) ;
} ) ;
} ,
} ,
failPortalPlayer ( player , video , index ) {
if ( ! player || player . stopped ) return ;
releasePortalMedia ( player ) {
if ( ! player ) return ;
player . stopped = true ;
player . stopped = true ;
if ( player . hls ) {
if ( player . hls ) {
try { player . hls . stopLoad ( ) ; } catch ( _ ) { /* already stopped */ }
try { player . hls . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
const hls = player . hls ;
player . hls = null ;
player . hls = null ;
try { hls . stopLoad ( ) ; } catch ( _ ) { /* already stopped */ }
try { hls . detachMedia ( ) ; } catch ( _ ) { /* already detached */ }
try { hls . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
}
}
if ( player . flv ) {
if ( player . flv ) {
try { player . flv . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
const flv = player . flv ;
player . flv = null ;
player . flv = null ;
try { flv . pause ( ) ; } catch ( _ ) { /* already paused */ }
try { flv . unload ( ) ; } catch ( _ ) { /* already unloaded */ }
try { flv . detachMediaElement ( ) ; } catch ( _ ) { /* already detached */ }
try { flv . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
}
}
if ( player . element ) {
if ( player . element ) {
player . element . onplaying = null ;
player . element . onplaying = null ;
player . element . onloadeddata = null ;
player . element . onloadeddata = null ;
player . element . oncanplay = null ;
player . element . oncanplay = null ;
player . element . onerror = null ;
player . element . onerror = null ;
player . element . pause ( ) ;
try { player . element . pause ( ) ; } catch ( _ ) { /* element already gone */ }
player . element . removeAttribute ( "src" ) ;
player . element . removeAttribute ( "src" ) ;
player . element . load ( ) ;
try { player . element . load ( ) ; } catch ( _ ) { /* element already gone */ }
}
}
if ( this . videoList [ index ] === video ) {
this . $set ( video , "loading" , false ) ;
this . $set ( video , "playbackError" , true ) ;
} ,
failPortalPlayer ( player , video , index ) {
if ( ! player || player . stopped ) return ;
this . releasePortalMedia ( player ) ;
if ( this . videoList [ index ] === video ) this . advancePortalVideo ( video , index ) ;
} ,
clearPortalPlayTimer ( index ) {
if ( ! this . portalPlayTimers [ index ] ) return ;
window . clearTimeout ( this . portalPlayTimers [ index ] ) ;
this . $delete ( this . portalPlayTimers , index ) ;
} ,
armPortalPlayTimeout ( video , index , player ) {
this . clearPortalPlayTimer ( index ) ;
this . $set ( this . portalPlayTimers , index , window . setTimeout ( ( ) => {
this . $delete ( this . portalPlayTimers , index ) ;
if ( ! this . portalAlive || this . videoList [ index ] !== video || this . portalPlayers [ index ] !== player || player . stopped ) return ;
this . failPortalPlayer ( player , video , index ) ;
} , 10000 ) ) ;
} ,
clearPortalAttempted ( index ) {
this . $delete ( this . portalAttemptedCodes , index ) ;
} ,
nextPortalCandidate ( failedVideo , index ) {
const pool = this . filteredVideos . filter ( item => item && item . cameraCode && item . status !== "abnormal" ) ;
if ( ! pool . length ) return null ;
const attempted = this . portalAttemptedCodes [ index ] || [ ] ;
const occupied = new Set (
this . videoList
. filter ( ( item , slotIndex ) => item && item . cameraCode && slotIndex !== index )
. map ( item => item . cameraCode )
) ;
const currentIndex = Math . max ( 0 , pool . findIndex ( item => item . cameraCode === failedVideo . cameraCode ) ) ;
for ( let offset = 1 ; offset <= pool . length ; offset += 1 ) {
const candidate = pool [ ( currentIndex + offset ) % pool . length ] ;
if ( ! candidate || attempted . includes ( candidate . cameraCode ) || occupied . has ( candidate . cameraCode ) ) continue ;
return candidate ;
}
}
return null ;
} ,
async advancePortalVideo ( failedVideo , index ) {
if ( ! this . portalAlive || this . videoList [ index ] !== failedVideo ) return ;
const attempted = ( this . portalAttemptedCodes [ index ] || [ ] ) . slice ( ) ;
if ( failedVideo . cameraCode && ! attempted . includes ( failedVideo . cameraCode ) ) attempted . push ( failedVideo . cameraCode ) ;
this . $set ( this . portalAttemptedCodes , index , attempted ) ;
const nextVideo = this . nextPortalCandidate ( failedVideo , index ) ;
await this . stopPortalVideo ( failedVideo , index ) ;
if ( ! this . portalAlive || this . videoList [ index ] !== failedVideo ) return ;
if ( ! nextVideo ) {
this . $set ( failedVideo , "loading" , false ) ;
this . $set ( failedVideo , "playbackError" , true ) ;
return ;
}
const replacement = { ... nextVideo , loading : true , playbackError : false , playUrl : "" , flvUrl : "" , streamId : "" } ;
this . $set ( this . videoList , index , replacement ) ;
this . $nextTick ( ( ) => this . startPortalVideo ( replacement , index ) ) ;
} ,
} ,
destroyPortalPlayer ( index ) {
destroyPortalPlayer ( index ) {
this . clearPortalPlayTimer ( index ) ;
const player = this . portalPlayers [ index ] ;
const player = this . portalPlayers [ index ] ;
if ( ! player ) return ;
if ( ! player ) return ;
player . stopped = true ;
if ( player . hls ) {
try { player . hls . stopLoad ( ) ; } catch ( _ ) { /* already stopped */ }
try { player . hls . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
player . hls = null ;
}
if ( player . flv ) {
try { player . flv . destroy ( ) ; } catch ( _ ) { /* already destroyed */ }
player . flv = null ;
}
if ( player . element ) {
player . element . onplaying = null ;
player . element . onloadeddata = null ;
player . element . oncanplay = null ;
player . element . onerror = null ;
player . element . pause ( ) ;
player . element . removeAttribute ( "src" ) ;
player . element . load ( ) ;
}
this . releasePortalMedia ( player ) ;
this . $delete ( this . portalPlayers , index ) ;
this . $delete ( this . portalPlayers , index ) ;
} ,
} ,
clearPortalStartTimer ( index ) {
clearPortalStartTimer ( index ) {
@ -863,6 +913,7 @@ export default {
window . clearTimeout ( this . portalStartTimers [ videoId ] ) ;
window . clearTimeout ( this . portalStartTimers [ videoId ] ) ;
this . $delete ( this . portalStartTimers , videoId ) ;
this . $delete ( this . portalStartTimers , videoId ) ;
} ) ;
} ) ;
Object . keys ( this . portalPlayTimers ) . forEach ( videoId => this . clearPortalPlayTimer ( videoId ) ) ;
return Promise . all ( videos . map ( ( video , index ) => this . stopPortalVideo ( video , index ) ) ) ;
return Promise . all ( videos . map ( ( video , index ) => this . stopPortalVideo ( video , index ) ) ) ;
} ,
} ,
selectPortalVideoSlot ( index ) {
selectPortalVideoSlot ( index ) {
@ -882,6 +933,7 @@ export default {
if ( ( ! current . playUrl || current . playbackError ) && ! current . loading ) this . startPortalVideo ( current , index ) ;
if ( ( ! current . playUrl || current . playbackError ) && ! current . loading ) this . startPortalVideo ( current , index ) ;
return ;
return ;
}
}
this . clearPortalAttempted ( index ) ;
await this . stopPortalVideo ( current , index ) ;
await this . stopPortalVideo ( current , index ) ;
this . $set ( this . videoList , index , video ) ;
this . $set ( this . videoList , index , video ) ;
this . $nextTick ( ( ) => this . startPortalVideo ( video , index ) ) ;
this . $nextTick ( ( ) => this . startPortalVideo ( video , index ) ) ;
@ -969,6 +1021,16 @@ export default {
const field = slide . fields . find ( key => card [ key ] !== undefined && card [ key ] !== null ) ;
const field = slide . fields . find ( key => card [ key ] !== undefined && card [ key ] !== null ) ;
return field ? card [ field ] : 0 ;
return field ? card [ field ] : 0 ;
} ,
} ,
openDefectRecords ( slide ) {
if ( ! slide || slide . defectLevel === undefined || slide . defectLevel === "" ) return ;
this . $store . dispatch ( "siteContext/markFromPortal" ) ;
this . $store . dispatch ( "siteContext/exitSite" ) ;
this . releasePortalPage ( ) ;
this . $router . push ( {
path : "/defect-record/index" ,
query : { defectLevel : slide . defectLevel }
} ) . catch ( ( ) => undefined ) ;
} ,
setDefectSlide ( index ) {
setDefectSlide ( index ) {
if ( index === this . defectSlideIndex ) return ;
if ( index === this . defectSlideIndex ) return ;
this . defectSlideDirection = index > this . defectSlideIndex ? "next" : "prev" ;
this . defectSlideDirection = index > this . defectSlideIndex ? "next" : "prev" ;
@ -1000,13 +1062,8 @@ export default {
this . stopPortalVideos ( ) ;
this . stopPortalVideos ( ) ;
} ,
} ,
systemEntryPath ( ) {
systemEntryPath ( ) {
const routes = this . $store . getters . sidebarRouters || [ ] ;
const system = routes . find ( route => route && route . path === "/system" && ! route . hidden ) ;
const child = system && ( system . children || [ ] ) . find ( item => item && ! item . hidden ) ;
if ( ! child ) return "/system/user" ;
const childPath = String ( child . path || "" ) ;
if ( ! childPath ) return "/system/user" ;
return childPath . startsWith ( "/" ) ? childPath : ` /system/ ${ childPath } ` ;
/ / 固 定 进 已 注 册 的 用 户 管 理 。 后 台 菜 单 没 下 发 / s y s t e m 时 , 按 菜 单 树 拼 出 来 的 地 址 会 4 0 4 。
return "/system/user" ;
} ,
} ,
onNavClick ( item ) {
onNavClick ( item ) {
if ( item . key === "home" ) {
if ( item . key === "home" ) {
@ -1736,6 +1793,7 @@ $panel-border: rgba(84, 130, 255, 0.22);
}
}
. video - monitor - body {
. video - monitor - body {
position : relative ;
display : flex ;
display : flex ;
flex : 1 ;
flex : 1 ;
min - height : 0 ;
min - height : 0 ;
@ -1750,22 +1808,27 @@ $panel-border: rgba(84, 130, 255, 0.22);
}
}
. portal - device - tree {
. portal - device - tree {
align - self : flex - start ;
flex : 0 0 46 % ;
width : 46 % ;
height : calc ( 100 % + 1 px ) ;
min - width : 280 px ;
max - width : 360 px ;
position : absolute ;
top : 0 ;
right : 0 ;
bottom : 0 ;
z - index : 4 ;
width : 242 px ;
min - width : 0 ;
min - height : 0 ;
min - height : 0 ;
padding : 0 ;
padding : 0 ;
margin : - 1 px 0 14 px ;
margin : 0 ;
overflow : hidden ;
overflow : hidden ;
background : transparent ! important ;
background : rgba ( 7 , 24 , 78 , 0.42 ) ! important ;
border : 1 px solid rgba ( 63 , 127 , 216 , 0.72 ) ;
box - shadow : inset 0 0 18 px rgba ( 36 , 110 , 200 , 0.14 ) , 0 0 8 px rgba ( 36 , 120 , 210 , 0.22 ) ;
: : v - deep . nvr - tree {
: : v - deep . portal - tree {
width : 100 % ;
width : 100 % ;
min - width : 0 ;
min - width : 0 ;
background : transparent ! important ;
background : transparent ! important ;
border : 0 ;
box - shadow : none ;
}
}
: : v - deep . tree - title {
: : v - deep . tree - title {
@ -1773,15 +1836,53 @@ $panel-border: rgba(84, 130, 255, 0.22);
}
}
: : v - deep . tree - filters {
: : v - deep . tree - filters {
padding - right : 0 ;
padding - left : 0 ;
padding - right : 8 px ;
padding - left : 8 px ;
background : transparent ! important ;
background : transparent ! important ;
}
}
: : v - deep . tree - filters . el - input__inner {
color : # f4fbff ! important ;
- webkit - text - fill - color : # f4fbff ;
background - color : transparent ! important ;
border - color : # 4 aa6ff ! important ;
box - shadow : none ;
}
: : v - deep . tree - filters . el - input__inner : : placeholder {
color : rgba ( 214 , 242 , 255 , 0.78 ) ;
- webkit - text - fill - color : rgba ( 214 , 242 , 255 , 0.78 ) ;
}
: : v - deep . tree - filters . el - button {
color : # e7f8ff ;
border - color : # 4 aa6ff ;
background : transparent ;
}
: : v - deep . tree - content ,
: : v - deep . tree - content ,
: : v - deep . el - tree {
: : v - deep . el - tree {
background : transparent ! important ;
background : transparent ! important ;
}
}
: : v - deep . tree - content {
scrollbar - color : rgba ( 96 , 186 , 255 , 0.6 ) transparent ;
}
: : v - deep . tree - content : : - webkit - scrollbar - track {
background : transparent ;
}
: : v - deep . tree - content : : - webkit - scrollbar - thumb {
background : rgba ( 96 , 186 , 255 , 0.55 ) ;
border - color : transparent ;
}
: : v - deep . el - tree - node__content : hover ,
: : v - deep . el - tree - node : focus > . el - tree - node__content ,
: : v - deep . el - tree -- highlight - current . el - tree - node . is - current > . el - tree - node__content {
background - color : rgba ( 11 , 37 , 103 , 0.45 ) ! important ;
}
}
}
. tree - toggle {
. tree - toggle {
@ -1811,10 +1912,8 @@ $panel-border: rgba(84, 130, 255, 0.22);
filter : brightness ( 1.2 ) drop - shadow ( 0 0 6 px rgba ( 32 , 218 , 255 , 0.65 ) ) ;
filter : brightness ( 1.2 ) drop - shadow ( 0 0 6 px rgba ( 32 , 218 , 255 , 0.65 ) ) ;
}
}
/ * 树 展 开 时 : 按 钮 贴 到 树 面 板 左 缘 , 显 示 收 起 箭 头
树宽被 min - width / max - width 钳制 , 按钮用同样的 clamp 规则才能在任何屏幕下对齐树缘 * /
& . open {
& . open {
right : clamp ( 280 px , 46 % , 360 px ) ;
right : 242 px ;
}
}
}
}
@ -1885,23 +1984,7 @@ $panel-border: rgba(84, 130, 255, 0.22);
padding : 0 14 px 12 px ;
padding : 0 14 px 12 px ;
}
}
. video - monitor - body . tree - visible {
. camera - stats {
grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ;
gap : 10 px 12 px ;
padding - right : 12 px ;
padding - left : 12 px ;
}
. video - grid {
grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ;
grid - template - rows : repeat ( 2 , minmax ( 0 , 1 fr ) ) ;
gap : 8 px ;
overflow : hidden ;
}
}
. video - monitor - body : not ( . tree - visible ) . video - grid {
. video - monitor - body . video - grid {
padding - right : 28 px ;
padding - right : 28 px ;
}
}
@ -2037,19 +2120,6 @@ $panel-border: rgba(84, 130, 255, 0.22);
}
}
}
}
. portal - device - tree {
min - width : 260 px ;
}
/* 窄屏下树宽下限变为 260px,按钮同步对齐 */
. tree - toggle . open {
right : clamp ( 260 px , 46 % , 360 px ) ;
}
. video - monitor - body . tree - visible . camera - stat {
padding - right : 6 px ;
padding - left : 6 px ;
}
}
}
. video - grid {
. video - grid {
@ -2115,8 +2185,8 @@ $panel-border: rgba(84, 130, 255, 0.22);
display : block ;
display : block ;
width : 100 % ;
width : 100 % ;
height : 100 % ;
height : 100 % ;
/* contain:完整显示画面不裁切;树打开格子变窄时两侧留底色而不是切割视频 */
object - fit : contain ;
/* cover:铺满格子,和实时监控嵌入页一样不留黑边 */
object - fit : cover ;
background : # 050 b24 ;
background : # 050 b24 ;
& . hidden {
& . hidden {