2024-02-15 22:07:50 +01:00
import vue from "./vue.build.js" ;
import $ from '../plugins/jquery/jquery.esm.js' ;
import '../plugins/switch/js/bootstrap-switch.min.js' ;
import "../plugins/timepicker/js/bootstrap-timepicker.js" ;
import * as noUiSlider from "../plugins/nouislider/js/nouislider.esm.js" ;
import mutationObserver from '../plugins/polyfill/mutationobserver.esm.js'
2024-02-15 22:07:54 +01:00
import { md5 } from "../plugins/md5/js.md5.esm.js" ;
import { func , confirm , rebootConfirm , alertMsg , axios _post , isEmpty , formatTime , clearReactiveArray , getUrlParam } from './lp.utils.js'
2024-02-15 22:07:50 +01:00
import { useDiskConf } from "./vue.hooks.js" ;
2024-02-15 22:07:54 +01:00
const { ref , reactive , toRefs , watch , watchEffect , computed , onMounted , nextTick , defineAsyncComponent } = vue ;
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
export const ignoreCustomElementPlugin = {
2024-02-15 22:07:50 +01:00
install : ( app ) => {
app . config . compilerOptions . isCustomElement = ( tag ) => tag === 'cn' || tag === 'en' ;
}
} ;
2024-02-15 22:07:54 +01:00
export const filterKeywordPlugin = {
install ( app ) {
const filter = getUrlParam ( "filter" ) ;
if ( ! filter )
return ;
const param = { "url" : location . pathname , "filter" : filter }
func ( "/root/getFilterKeywords" , param ) . then ( result => {
const keyword = result . data ;
if ( keyword ) {
// nextTick(() => {
setTimeout ( ( ) => {
const elements = document . querySelectorAll ( 'main cn, main en' ) ;
elements . forEach ( ( el ) => {
const textContent = el . textContent ;
const startIndex = textContent . indexOf ( keyword ) ;
if ( startIndex !== - 1 ) {
let currentElement = el . parentNode ;
while ( currentElement ) {
currentElement = currentElement . parentNode ;
if ( currentElement ) {
let classList = currentElement . classList ;
if ( classList && classList . contains ( "tab-pane" ) ) {
let tabId = currentElement . id ;
let navLinks = document . querySelectorAll ( ".nav.nav-tabs > .nav-item > .nav-link" ) ;
navLinks . forEach ( item => {
if ( item . getAttribute ( 'href' ) === '#' + tabId ) {
if ( item . classList )
item . classList . add ( "active" ) ;
} else {
if ( item . classList )
item . classList . remove ( "active" ) ;
}
} )
const siblings = Array . from ( currentElement . parentElement . children ) ;
siblings . forEach ( ( sibling ) => {
sibling . classList . remove ( 'active' ) ;
sibling . classList . remove ( 'show' ) ;
} ) ;
currentElement . classList . add ( 'active' ) ;
currentElement . classList . add ( 'show' ) ;
}
}
}
const endIndex = startIndex + keyword . length ;
const beforeText = textContent . slice ( 0 , startIndex ) ;
const highlightedText = textContent . slice ( startIndex , endIndex ) ;
const afterText = textContent . slice ( endIndex ) ;
const highlightedElement = document . createElement ( 'span' ) ;
highlightedElement . style . fontWeight = '700' ;
highlightedElement . style . color = 'red' ;
highlightedElement . textContent = highlightedText ;
el . innerHTML = beforeText ;
el . appendChild ( highlightedElement ) ;
el . innerHTML += afterText ;
}
} )
} , 100 ) ;
// })
}
} )
2024-02-15 22:07:50 +01:00
}
} ;
export const languageOptionDirective = {
mounted ( el , binding , vnode ) {
const update = ( ) => {
const lang = html . getAttribute ( 'data-bs-language' ) ;
el . textContent = el . getAttribute ( lang ) ;
}
const html = document . querySelector ( 'html' ) ;
update ( ) ;
const observer = new mutationObserver ( ( ) => {
update ( ) ;
} ) ;
const config = {
attributes : true ,
attributeFilter : [ "data-bs-language" ] ,
subtree : false
} ;
observer . observe ( html , config ) ;
}
} ;
export const clickOutsideDirective = {
mounted ( el , binding ) {
const eventHandler = ( e ) => {
if ( el . contains ( e . target ) ) {
return false
}
if ( binding . value && typeof binding . value === 'function' ) {
binding . value ( e )
}
}
el . _ _click _outside _ _ = eventHandler
document . addEventListener ( 'click' , eventHandler )
} ,
beforeUnmount ( el ) {
document . removeEventListener ( 'click' , el . _ _click _outside _ _ )
delete el . _ _click _outside _ _
}
}
export const statusTemperatureComponent = {
template : ` <div class="pie">
< div class = "temperature" >
< div class = "bar" >
< div class = "mask" ref = "tmp_mask" > < / d i v >
< span class = "percent" ref = "tmp_text" > 0 ℃ < / s p a n >
< / d i v >
< / d i v >
< / d i v > ` ,
2024-02-15 22:07:52 +01:00
props : {
modelValue : {
type : Number ,
default : 0
} ,
activeColor : {
type : String ,
default : "#fb0"
}
} ,
2024-02-15 22:07:50 +01:00
setup ( props , context ) {
const tmp _mask = ref ( null ) ;
const tmp _text = ref ( null ) ;
2024-02-15 22:07:54 +01:00
const { modelValue , activeColor } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
watch ( modelValue , ( ) => {
2024-02-15 22:07:52 +01:00
tmp _mask . value . style . bottom = modelValue . value + '%' ;
tmp _text . value . textContent = modelValue . value + '℃' ;
2024-02-15 22:07:50 +01:00
} )
2024-02-15 22:07:52 +01:00
onMounted ( ( ) => tmp _mask . value . parentElement . style . background = activeColor . value ) ;
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
return { tmp _mask , tmp _text }
2024-02-15 22:07:50 +01:00
}
} ;
export const statusPieChartComponent = {
template : ` <div class="pie">
< div class = "chart" ref = "pie_chart" > < / d i v >
< span class = "percent" ref = "pie_text" > < / s p a n >
< / d i v > ` ,
props : {
modelValue : {
2024-02-15 22:07:54 +01:00
type : Number ,
default : 0
2024-02-15 22:07:50 +01:00
} ,
activeColor : {
type : String ,
default : "#fb0"
} ,
trackColor : {
type : String ,
default : "#777"
}
} ,
setup ( props , context ) {
const pie _chart = ref ( null ) ;
const pie _text = ref ( null ) ;
2024-02-15 22:07:54 +01:00
const { modelValue } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
watch ( modelValue , newValue => {
if ( $ ( pie _chart . value ) . data ( 'easyPieChart' ) )
$ ( pie _chart . value ) . data ( 'easyPieChart' ) . update ( newValue ) ;
2024-02-15 22:07:50 +01:00
} )
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
pie _text . value . textContent = "0%" ;
$ ( pie _chart . value ) . easyPieChart ( {
easing : 'easeOutElastic' ,
delay : 2000 ,
barColor : props . activeColor ,
trackColor : props . trackColor ,
scaleColor : false ,
lineWidth : 20 ,
trackWidth : 16 ,
lineCap : 'butt' ,
width : 50 ,
onStep : ( from , to , percent ) => {
pie _text . value . textContent = Math . round ( percent ) + "%" ;
}
} ) ;
} )
2024-02-15 22:07:54 +01:00
return { pie _chart , pie _text }
2024-02-15 22:07:50 +01:00
}
} ;
export const netFlotChartComponent = {
template : ` <div class="col-lg-12 netState" ref="net_chart"> </div> ` ,
props : {
line1Color : {
type : String ,
default : "#FB0"
} ,
line2Color : {
type : String ,
default : "#555"
} ,
maxy : {
type : Number ,
maxy : 800
} ,
data1 : {
type : Array ,
default : [ ] ,
} ,
data2 : {
type : Array ,
default : [ ]
} ,
tickColor : {
type : String ,
2024-02-15 22:07:54 +01:00
default : "#eee"
2024-02-15 22:07:50 +01:00
} ,
borderColor : {
type : String ,
default : "#ccc"
} ,
2024-02-15 22:07:54 +01:00
tipBorderColor : {
2024-02-15 22:07:50 +01:00
type : String ,
default : "#fb0"
} ,
tipBgColor : {
type : String ,
default : "#fff"
} ,
tipTxtColor : {
type : String ,
default : "#555"
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const net _chart = ref ( null ) ;
let plot = { } ;
const showTooltip = ( x , y , color , contents ) => {
$ ( '<div id="tooltip">' + contents + '</div>' ) . css ( {
position : 'absolute' ,
display : 'none' ,
top : y - 40 ,
left : x - 120 ,
border : '2px solid ' + props . tipBorderColor ,
padding : '3px' ,
'font-size' : '9px' ,
'border-radius' : '5px' ,
2024-02-15 22:07:54 +01:00
'color' : props . tipTxtColor ,
2024-02-15 22:07:50 +01:00
'background-color' : props . tipBgColor ,
'font-family' : 'Verdana, Arial, Helvetica, Tahoma, sans-serif' ,
opacity : 0.9
} ) . appendTo ( "body" ) . fadeIn ( 200 ) ;
}
const initPlot = ( ) => {
2024-02-15 22:07:54 +01:00
if ( Object . keys ( plot ) . length === 0 ) {
2024-02-15 22:07:50 +01:00
let color = props . color ;
let data1 = props . data1 ;
let data2 = props . data2 ;
plot = $ . plot ( net _chart . value , [
{
data : data1 ,
lines : {
fill : true ,
}
} ,
{
data : data2 ,
lines : {
show : true ,
}
} ]
,
{
series : {
lines : {
show : true ,
fill : true ,
} ,
shadowSize : 0
} ,
yaxis : {
min : 0 ,
max : 800 ,
tickSize : 160 ,
2024-02-15 22:07:54 +01:00
tickFormatter : ( v , axis ) => {
if ( axis . max < 1024 )
2024-02-15 22:07:50 +01:00
return v + "Kb/s" ;
else {
v /= 1024 ;
2024-02-15 22:07:54 +01:00
if ( axis . max < 10240 )
return v . toFixed ( 2 ) + "Mb/s" ;
2024-02-15 22:07:50 +01:00
else
2024-02-15 22:07:54 +01:00
return Math . floor ( v ) + "Mb/s" ;
2024-02-15 22:07:50 +01:00
}
}
} ,
xaxis : {
show : false
} ,
grid : {
hoverable : true ,
clickable : true ,
tickColor : props . tickColor ,
borderWidth : 1 ,
borderColor : props . borderColor ,
} ,
2024-02-15 22:07:54 +01:00
colors : [ props . line1Color , props . line2Color ] ,
2024-02-15 22:07:50 +01:00
tooltip : false
} ) ;
$ . fn . tooltip = ( ) => {
let prePoint = null , preLabel = null ;
$ ( net _chart . value ) . bind ( "plothover" , ( event , pos , item ) => {
if ( item ) {
if ( ( preLabel !== item . series . label ) || ( prePoint !== item . dataIndex ) ) {
prePoint = item . dataIndex ;
preLabel = item . series . label ;
$ ( "#tooltip" ) . remove ( ) ;
$ ( this ) . css ( {
"cursor" : "pointer"
} )
let data = item . series . data [ item . dataIndex ] [ 1 ] ;
2024-02-15 22:07:54 +01:00
if ( data > 1024 )
data = parseInt ( data / 1024 ) + "Mb/s" ;
2024-02-15 22:07:50 +01:00
else
data += "kb/s" ;
if ( item . seriesIndex === 0 )
showTooltip ( item . pageX + 100 , item . pageY - 10 , color , "<cn>上行</cn><en>upward</en>: " + data ) ;
if ( item . seriesIndex === 1 )
showTooltip ( item . pageX + 100 , item . pageY - 10 , color , "<cn>下行</cn><en>downward</en>: " + data ) ;
}
2024-02-15 22:07:54 +01:00
} else {
2024-02-15 22:07:50 +01:00
prePoint = null ;
preLabel = null ;
$ ( this ) . css ( {
"cursor" : "auto"
} ) ;
$ ( "#tooltip" ) . remove ( ) ;
}
} ) ;
}
$ ( net _chart . value ) . tooltip ( ) ;
}
}
const updatePlot = ( ) => {
2024-02-15 22:07:54 +01:00
if ( Object . keys ( plot ) . length !== 0 ) {
2024-02-15 22:07:50 +01:00
let maxy = props . maxy ;
let data1 = props . data1 ;
let data2 = props . data2 ;
plot . setData ( [ data1 , data2 ] ) ;
plot . draw ( ) ;
2024-02-15 22:07:54 +01:00
plot . getOptions ( ) . yaxes [ 0 ] . max = maxy ;
plot . getOptions ( ) . yaxes [ 0 ] . tickSize = Math . floor ( maxy / 5 ) ;
2024-02-15 22:07:50 +01:00
plot . setupGrid ( ) ;
}
}
2024-02-15 22:07:54 +01:00
watch ( props . data1 , ( ) => {
2024-02-15 22:07:50 +01:00
updatePlot ( ) ;
2024-02-15 22:07:54 +01:00
} , { deep : true } )
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
setTimeout ( initPlot , 100 ) ;
2024-02-15 22:07:50 +01:00
} )
return { net _chart }
}
}
export const bootstrapSwitchComponent = {
template : ` <input type="checkbox" class="switch form-control" ref="bs_switch"> ` ,
props : {
modelValue : {
type : Boolean ,
default : false
} ,
size : {
type : String ,
2024-02-15 22:07:54 +01:00
default : "small" //normal
2024-02-15 22:07:50 +01:00
}
} ,
setup ( props , context ) {
2024-02-15 22:07:54 +01:00
const { modelValue , size } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const bs _switch = ref ( null ) ;
2024-02-15 22:07:54 +01:00
watch ( modelValue , ( ) => {
2024-02-15 22:07:50 +01:00
$ ( bs _switch . value ) . bootstrapSwitch ( 'state' , modelValue . value , true ) ;
} )
onMounted ( ( ) => {
$ ( bs _switch . value ) . bootstrapSwitch ( {
"state" : props . modelValue ,
"size" : size . value ,
onInit ( dom , event , state ) {
$ ( bs _switch . value ) . on ( 'focus.bootstrapSwitch' , ( ) => {
this . $wrapper . removeClass ( "bootstrap-switch-focused" )
} )
} ,
onSwitchChange ( event , state ) {
context . emit ( 'update:modelValue' , state ) ;
context . emit ( 'switch-change' , state ) ;
}
} )
} )
2024-02-15 22:07:54 +01:00
return { bs _switch }
2024-02-15 22:07:50 +01:00
}
} ;
export const multipleSelectComponent = {
template : ` <select class="form-select" v-model="selectValue" @change="onSelectChange">
< slot > < / s l o t >
< / s e l e c t > ` ,
props : {
value1 : {
2024-02-15 22:07:54 +01:00
type : [ Number , String , Boolean ] ,
default : 0
2024-02-15 22:07:50 +01:00
} ,
value2 : {
2024-02-15 22:07:54 +01:00
type : [ Number , String , Boolean ] ,
2024-02-15 22:07:50 +01:00
default : 0
} ,
split : {
type : String ,
default : 0
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
let selectValue = ref ( "" ) ;
2024-02-15 22:07:54 +01:00
watchEffect ( ( ) => {
2024-02-15 22:07:50 +01:00
selectValue . value = props . value1 + props . split + props . value2 ;
} )
const parseValue = ( value ) => {
if ( value === "true" || value === "false" ) {
return JSON . parse ( value ) ;
}
return isNaN ( Number ( value ) ) ? value : Number ( value ) ;
} ;
2024-02-15 22:07:54 +01:00
const onSelectChange = ( ) => {
2024-02-15 22:07:50 +01:00
let [ value1 , value2 ] = selectValue . value . split ( props . split ) ;
context . emit ( 'update:value1' , parseValue ( value1 ) ) ;
context . emit ( 'update:value2' , parseValue ( value2 ) ) ;
}
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
selectValue . value = props . value1 + props . split + props . value2 ;
} )
2024-02-15 22:07:54 +01:00
return { selectValue , onSelectChange }
2024-02-15 22:07:50 +01:00
}
} ;
export const multipleInputComponent = {
template : ` <input type="text" class="form-control" v-model="selectValue" @change="onInputChange"> ` ,
props : {
value1 : {
2024-02-15 22:07:54 +01:00
type : [ Number , String ] ,
2024-02-15 22:07:50 +01:00
default : 0
} ,
value2 : {
2024-02-15 22:07:54 +01:00
type : [ Number , String ] ,
2024-02-15 22:07:50 +01:00
default : 0
} ,
split : {
type : String ,
default : 0
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
let selectValue = ref ( "" ) ;
2024-02-15 22:07:54 +01:00
const { value1 , value2 } = toRefs ( props ) ;
watchEffect ( ( ) => {
2024-02-15 22:07:50 +01:00
const val1 = ( typeof value1 . value === "string" ) ? value1 . value . trim ( ) : value1 . value ;
const val2 = ( typeof value2 . value === "string" ) ? value2 . value . trim ( ) : value2 . value ;
selectValue . value = val1 + props . split + val2 ;
} )
2024-02-15 22:07:54 +01:00
const onInputChange = ( ) => {
let [ val1 , val2 ] = selectValue . value . split ( props . split ) ;
2024-02-15 22:07:50 +01:00
val1 = isNaN ( Number ( val1 ) ) ? val1 : Number ( val1 ) ;
val2 = isNaN ( Number ( val2 ) ) ? val2 : Number ( val2 ) ;
2024-02-15 22:07:54 +01:00
if ( typeof val1 === "string" )
2024-02-15 22:07:50 +01:00
val1 = val1 . trim ( ) ;
2024-02-15 22:07:54 +01:00
if ( typeof val2 === "string" )
2024-02-15 22:07:50 +01:00
val2 = val2 . trim ( ) ;
context . emit ( 'update:value1' , val1 ) ;
context . emit ( 'update:value2' , val2 ) ;
selectValue . value = val1 + props . split + val2 ;
}
2024-02-15 22:07:54 +01:00
return { selectValue , onInputChange }
2024-02-15 22:07:50 +01:00
}
} ;
export const nouiSliderComponent = {
template : ` <div class="slider-wrap lp-cursor-pointer" ref="slider"></div> ` ,
props : {
modelValue : {
2024-02-15 22:07:54 +01:00
type : [ Number , String ] ,
default : 0
2024-02-15 22:07:50 +01:00
} ,
min : {
type : Number ,
default : 0
} ,
max : {
type : Number ,
default : 100
} ,
step : {
type : Number ,
default : 1
} ,
fix : {
type : Number ,
default : 0
} ,
funcValue : {
type : Number ,
} ,
format : {
type : String ,
default : ""
} ,
disable : {
type : Boolean ,
default : false
} ,
index : {
type : Number ,
default : 0
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const slider = ref ( null ) ;
let handle = ref ( null ) ;
let hover = false ;
let isSlide = false ;
const showTooltip = ( ) => {
let tooltip = handle . value . querySelector ( ".noUi-tooltip" )
tooltip . style . display = 'block' ;
hover = true ;
}
const hideTooltip = ( ) => {
let tooltip = handle . value . querySelector ( ".noUi-tooltip" )
tooltip . style . display = 'none' ;
hover = false ;
}
const formatTooltipValue = value => {
2024-02-15 22:07:54 +01:00
if ( isEmpty ( props . format ) ) {
if ( props . fix === 0 )
2024-02-15 22:07:50 +01:00
value = parseInt ( value ) ;
else
value = parseFloat ( value ) . toFixed ( props . fix ) ;
}
2024-02-15 22:07:54 +01:00
if ( props . format === "time" )
2024-02-15 22:07:50 +01:00
value = formatTime ( value ) ;
return value ;
}
watch ( ( ) => props . modelValue , ( newValue , oldValue ) => {
if ( slider . value && ! isSlide ) {
slider . value . noUiSlider . updateOptions ( {
start : newValue ,
range : { 'min' : props . min , 'max' : props . max } ,
} ) ;
2024-02-15 22:07:54 +01:00
if ( ! hover )
2024-02-15 22:07:50 +01:00
hideTooltip ( ) ;
}
} ) ;
watch ( ( ) => props . funcValue , ( newValue , oldValue ) => {
if ( slider . value && ! isSlide ) {
slider . value . noUiSlider . updateOptions ( {
start : newValue ,
range : { 'min' : props . min , 'max' : props . max } ,
} ) ;
2024-02-15 22:07:54 +01:00
if ( ! hover )
2024-02-15 22:07:50 +01:00
hideTooltip ( ) ;
}
} ) ;
watch ( ( ) => props . max , ( newValue , oldValue ) => {
if ( slider . value && ! isSlide ) {
slider . value . noUiSlider . updateOptions ( {
range : { 'min' : props . min , 'max' : newValue } ,
} ) ;
2024-02-15 22:07:54 +01:00
if ( ! hover )
2024-02-15 22:07:50 +01:00
hideTooltip ( ) ;
}
} ) ;
onMounted ( async ( ) => {
noUiSlider . create ( slider . value , {
start : props . modelValue ,
connect : [ true , false ] ,
tooltips : {
to : formatTooltipValue ,
} ,
range : { 'min' : props . min , 'max' : props . max } ,
step : props . step ,
} ) ;
2024-02-15 22:07:54 +01:00
if ( props . disable )
2024-02-15 22:07:50 +01:00
slider . value . noUiSlider . disable ( ) ;
handle . value = slider . value . querySelector ( '.noUi-handle' ) ;
hideTooltip ( ) ;
slider . value . addEventListener ( 'mouseenter' , ( ) => {
showTooltip ( ) ;
} ) ;
slider . value . addEventListener ( 'mouseleave' , ( ) => {
hideTooltip ( ) ;
} ) ;
slider . value . noUiSlider . on ( 'slide' , ( values , mark ) => {
isSlide = true ;
} ) ;
// slider.value.noUiSlider.on('end', (values, mark) => {
// isSlide = false;
// context.emit('update:modelValue', formatTooltipValue(values[mark]));
// context.emit('slide-end', formatTooltipValue(values[mark]),props.index);
// });
slider . value . noUiSlider . on ( 'change' , ( values , mark ) => {
isSlide = false ;
context . emit ( 'update:modelValue' , formatTooltipValue ( values [ mark ] ) ) ;
2024-02-15 22:07:54 +01:00
context . emit ( 'slide-end' , formatTooltipValue ( values [ mark ] ) , props . index ) ;
2024-02-15 22:07:50 +01:00
} ) ;
} )
2024-02-15 22:07:54 +01:00
return { slider }
2024-02-15 22:07:50 +01:00
}
} ;
export const h5PlayerComponent = {
template : ` <div style="width:100%; padding-bottom: 56.25%; position: relative;">
< video autoplay controls muted style = "width:100%;height: 100%; position: absolute; background: #555;" ref = "videoHandler" > < / v i d e o >
< div style = "position: absolute;width: 100%;height: 100%" ref = "jessHandler" > < / d i v >
< div class = "lp-video-cloud" ref = "cloudHandler" >
< div class = "loading" > < / d i v >
< / d i v >
< / d i v > ` ,
props : {
url : {
type : String ,
default : ""
} ,
codec : {
type : String ,
default : "h264"
} ,
audio : {
type : Boolean ,
default : true
} ,
buffer : {
type : Number ,
default : 200
} ,
canplay : {
type : Boolean ,
default : true
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
const { url , codec , audio , buffer , canplay } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const state = {
videoHandler : ref ( null ) ,
jessHandler : ref ( null ) ,
cloudHandler : ref ( null ) ,
hadInitPlayer : false ,
flvJsModule : { } ,
h5Player : { } ,
}
2024-02-15 22:07:54 +01:00
watchEffect ( ( ) => {
if ( canplay . value ) {
if ( url . value !== "" ) {
if ( state . hadInitPlayer )
2024-02-15 22:07:50 +01:00
destroyPlayer ( ) ;
2024-02-15 22:07:54 +01:00
setTimeout ( initPlayer , 300 ) ;
2024-02-15 22:07:50 +01:00
}
} else {
2024-02-15 22:07:54 +01:00
if ( state . hadInitPlayer )
2024-02-15 22:07:50 +01:00
destroyPlayer ( ) ;
}
} )
const initPlayer = async ( ) => {
2024-02-15 22:07:54 +01:00
if ( props . url === "" )
2024-02-15 22:07:50 +01:00
return ;
2024-02-15 22:07:54 +01:00
if ( props . codec === "h265" ) {
2024-02-15 22:07:50 +01:00
state . videoHandler . value . style . display = 'none' ;
state . jessHandler . value . style . display = 'block' ;
2024-02-15 22:07:54 +01:00
if ( ! window . Jessibuca )
2024-02-15 22:07:50 +01:00
await import ( '../plugins/jessibuca/jessibuca.js' ) ;
2024-02-15 22:07:54 +01:00
state . h5Player = new Jessibuca ( {
2024-02-15 22:07:50 +01:00
container : state . jessHandler . value ,
2024-02-15 22:07:54 +01:00
videoBuffer : buffer . value / 1000 ,
2024-02-15 22:07:50 +01:00
decoder : "assets/plugins/jessibuca/decoder.js" ,
isResize : false ,
audio : JSON . parse ( audio . value ) ,
operateBtns : {
fullscreen : true ,
play : true ,
audio : JSON . parse ( audio . value ) ,
} ,
forceNoOffscreen : true ,
isNotMute : false ,
} ) ;
state . h5Player . play ( url . value ) ;
state . h5Player . on ( "play" , ( flag ) => {
state . cloudHandler . value . style . display = 'none'
} )
} else {
state . videoHandler . value . style . display = 'block' ;
state . jessHandler . value . style . display = 'none' ;
2024-02-15 22:07:54 +01:00
if ( ! window . flvjs )
2024-02-15 22:07:50 +01:00
await import ( '../plugins/flvjs/flv.js' ) ;
state . h5Player = flvjs . createPlayer ( {
type : 'flv' ,
url : url . value ,
audio : JSON . parse ( audio . value ) ,
} ) ;
state . h5Player . attachMediaElement ( state . videoHandler . value ) ;
state . h5Player . load ( ) ;
state . h5Player . play ( ) ;
2024-02-15 22:07:54 +01:00
state . videoHandler . value . addEventListener ( "canplay" , ( ) => {
2024-02-15 22:07:50 +01:00
state . cloudHandler . value . style . display = 'none'
} ) ;
}
state . hadInitPlayer = true ;
}
const destroyPlayer = ( ) => {
2024-02-15 22:07:54 +01:00
if ( Object . keys ( state . h5Player ) . length > 0 ) {
if ( state . h5Player . hasOwnProperty ( "unload" ) ) {
2024-02-15 22:07:50 +01:00
state . h5Player . unload ( ) ;
state . h5Player . detachMediaElement ( ) ;
}
state . h5Player . destroy ( ) ;
state . h5Player = { } ;
}
state . cloudHandler . value . style . display = 'flex' ;
2024-02-15 22:07:54 +01:00
state . videoHandler . value . removeEventListener ( "canplay" , ( ) => {
} ) ;
2024-02-15 22:07:50 +01:00
state . hadInitPlayer = false ;
}
const checkDelay = ( ) => {
// if (Object.keys(state.h5Player).length > 0 && state.h5Player.hasOwnProperty("buffered") && state.h5Player.buffered.length > 0) {
// if (state.h5Player.buffered.end(0) - state.h5Player.currentTime > 1.5) {
// state.h5Player.currentTime = state.h5Player.buffered.end(0) - 0.2;
// }
// }
// setTimeout(checkDelay,1000);
}
onMounted ( checkDelay ) ;
2024-02-15 22:07:54 +01:00
return { ... state }
2024-02-15 22:07:50 +01:00
}
} ;
export const videoPlayerComponent = {
template : ` <div style="width:100%; padding-bottom: 56.25%; position: relative;">
< video autoplay controls muted style = "width:100%;height: 100%; position: absolute; background: #555;" ref = "videoHandler" > < / v i d e o >
< div class = "lp-video-cloud" ref = "cloudHandler" >
< div class = "loading" > < / d i v >
< / d i v >
< / d i v > ` ,
props : {
url : {
type : String ,
default : ""
} ,
canplay : {
type : Boolean ,
default : true
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
const { url , canplay } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const state = {
videoHandler : ref ( null ) ,
cloudHandler : ref ( null ) ,
hadInitPlayer : false ,
}
2024-02-15 22:07:54 +01:00
watchEffect ( ( ) => {
if ( canplay . value ) {
if ( url . value !== "" ) {
if ( state . hadInitPlayer )
2024-02-15 22:07:50 +01:00
destroyPlayer ( ) ;
2024-02-15 22:07:54 +01:00
setTimeout ( initPlayer , 300 ) ;
2024-02-15 22:07:50 +01:00
}
} else {
2024-02-15 22:07:54 +01:00
if ( state . hadInitPlayer )
2024-02-15 22:07:50 +01:00
destroyPlayer ( ) ;
}
} )
const initPlayer = ( ) => {
2024-02-15 22:07:54 +01:00
if ( url . value === "" )
2024-02-15 22:07:50 +01:00
return ;
state . videoHandler . value . style . display = 'block' ;
state . videoHandler . value . src = url . value ;
state . videoHandler . value . play ( ) ;
2024-02-15 22:07:54 +01:00
state . videoHandler . value . addEventListener ( "canplay" , ( ) => {
2024-02-15 22:07:50 +01:00
state . cloudHandler . value . style . display = 'none'
} ) ;
state . hadInitPlayer = true ;
}
2024-02-15 22:07:54 +01:00
2024-02-15 22:07:50 +01:00
const destroyPlayer = ( ) => {
state . cloudHandler . value . style . display = 'flex' ;
2024-02-15 22:07:54 +01:00
state . videoHandler . value . removeEventListener ( "canplay" , ( ) => {
} ) ;
2024-02-15 22:07:50 +01:00
state . hadInitPlayer = false ;
}
2024-02-15 22:07:54 +01:00
return { ... state }
2024-02-15 22:07:50 +01:00
}
} ;
export const timepickerComponent = {
template : ` <div class="input-group bootstrap-timepicker">
< input type = "text" class = "form-control" ref = "timepicker" >
< span class = "input-group-text input-group-addon" > < i class = "fa-regular fa-clock" > < / i > < / s p a n >
< / d i v > ` ,
props : {
modelValue : {
type : String ,
default : "00:00"
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const timepicker = ref ( null ) ;
2024-02-15 22:07:54 +01:00
const { modelValue } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
watch ( modelValue , ( ) => {
2024-02-15 22:07:50 +01:00
$ ( timepicker . value ) . timepicker ( 'setTime' , modelValue . value ) ;
} )
onMounted ( ( ) => {
$ ( timepicker . value ) . timepicker ( {
minuteStep : 1 ,
defaultTime : props . modelValue ,
showMeridian : false ,
icons : {
up : 'fa-solid fa-angle-up' ,
down : 'fa-solid fa-angle-down'
} ,
} ) ;
$ ( timepicker . value ) . on ( "changeTime.timepicker" , event => {
context . emit ( 'update:modelValue' , event . time . value ) ;
} ) ;
} )
return { timepicker }
}
} ;
export const vueColorPickerComponent = {
template : ` <div class="color-picker" v-click-outside="clickOutside">
< input class = "form-control" type = "text" v - model . trim . lazy = "pickerColor" ref = "picker" @ change = "pickerColorChange" >
< div ref = "popper" class = "popper" >
< sketch - picker v - model = "sketchColor" > < / s k e t c h - p i c k e r >
< div class = "arrow" data - popper - arrow > < / d i v >
< / d i v >
< / d i v > ` ,
2024-02-15 22:07:52 +01:00
props : {
modelValue : {
type : String ,
default : ""
} ,
direct : {
type : String ,
default : "bottom"
}
} ,
2024-02-15 22:07:50 +01:00
components : {
"sketch-picker" : defineAsyncComponent ( ( ) => {
return import ( '../plugins/vueColor/vue3.color.esm.js' ) . then ( module => {
2024-02-15 22:07:54 +01:00
const { Sketch } = module ;
2024-02-15 22:07:50 +01:00
return Sketch ;
} )
} ) ,
} ,
directives : {
"click-outside" : clickOutsideDirective
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const state = {
picker : ref ( null ) ,
popper : ref ( null ) ,
pickerColor : ref ( "" ) ,
sketchColor : ref ( "" ) ,
partyPopper : { } ,
popperOptions : reactive ( { } ) ,
}
2024-02-15 22:07:54 +01:00
watch ( state . sketchColor , ( ) => {
if ( state . sketchColor . value . hasOwnProperty ( "hex" ) ) {
2024-02-15 22:07:50 +01:00
state . pickerColor . value = state . sketchColor . value . hex ;
context . emit ( 'update:modelValue' , state . pickerColor . value ) ;
}
} ) ;
const pickerColorChange = ( ) => {
state . sketchColor . value = state . pickerColor . value ;
context . emit ( 'update:modelValue' , state . pickerColor . value ) ;
}
const showPopper = ( ) => {
state . popper . value . setAttribute ( 'data-show' , '' ) ;
state . partyPopper . setOptions ( ( options ) => ( {
... options ,
modifiers : [
... options . modifiers ,
2024-02-15 22:07:54 +01:00
{ name : 'eventListeners' , enabled : true } ,
2024-02-15 22:07:50 +01:00
] ,
} ) ) ;
state . partyPopper . update ( ) ;
}
const hidePopper = ( ) => {
2024-02-15 22:07:54 +01:00
if ( Object . keys ( state . partyPopper ) . length > 0 ) {
2024-02-15 22:07:50 +01:00
state . popper . value . removeAttribute ( 'data-show' ) ;
state . partyPopper . setOptions ( ( options ) => ( {
... options ,
modifiers : [
... options . modifiers ,
2024-02-15 22:07:54 +01:00
{ name : 'eventListeners' , enabled : false } ,
2024-02-15 22:07:50 +01:00
] ,
} ) ) ;
}
}
const clickOutside = ( event ) => {
hidePopper ( ) ;
}
nextTick ( async ( ) => {
const Popper = await import ( '../plugins/popper/popper.esm.js' ) ;
state . partyPopper = Popper . createPopper ( state . picker . value , state . popper . value , {
placement : props . direct ,
modifiers : [
{
name : 'offset' ,
options : {
offset : [ 0 , 8 ] ,
} ,
} ,
{
name : 'computeStyles' ,
options : {
gpuAcceleration : false ,
adaptive : false
}
}
] ,
} ) ;
state . picker . value . addEventListener ( "focus" , showPopper ) ;
} )
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
// state.pickerColor.value = props.modelValue;
2024-02-15 22:07:54 +01:00
state . sketchColor . value = { 'hex' : props . modelValue } ;
2024-02-15 22:07:50 +01:00
} ) ;
2024-02-15 22:07:54 +01:00
return { ... state , clickOutside , pickerColorChange }
2024-02-15 22:07:50 +01:00
}
} ;
export const uploadModalComponent = {
template : ` <div :class="['modal',{'fade':modalFade===undefined ? false : JSON.parse(modalFade)}]" tabindex="-1" aria-hidden="true" ref="modal">
< div class = "modal-dialog modal-lg modal-dialog-centered" >
< div class = "modal-content" >
< div class = "modal-header" >
< h5 class = "modal-title" > { { modalTitle } } < / h 5 >
< button type = "button" class = "btn-close" data - bs - dismiss = "modal" aria - label = "Close" > < / b u t t o n >
< / d i v >
< div class = "modal-body" >
< input type = "file" ref = "uploadFile" name = "uploadFile" multiple / >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ,
2024-02-15 22:07:54 +01:00
props : {
2024-02-15 22:07:52 +01:00
modalTitle : {
type : String ,
default : ""
} ,
modalShow : {
type : Boolean ,
default : false
} ,
modalFade : {
type : Boolean ,
default : false
} ,
uploadTip : {
type : String ,
default : ""
} ,
uploadAction : {
type : String ,
default : ""
} ,
uploadAllow : {
type : Array ,
default : ""
} ,
uploadCount : {
2024-02-15 22:07:54 +01:00
type : [ Number , String ] ,
2024-02-15 22:07:52 +01:00
default : 1
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
const { modalShow , modalFade , uploadAllow } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const state = {
2024-02-15 22:07:54 +01:00
modal : ref ( null ) ,
modalTitle : ref ( "" ) ,
2024-02-15 22:07:50 +01:00
uploadFile : ref ( null ) ,
uploadTip : "" ,
2024-02-15 22:07:54 +01:00
show : false ,
bsModal : { } ,
2024-02-15 22:07:50 +01:00
uploadLang : "zh"
}
2024-02-15 22:07:54 +01:00
watch ( modalShow , ( ) => {
2024-02-15 22:07:50 +01:00
state . show = ! state . show ;
2024-02-15 22:07:54 +01:00
if ( state . show )
2024-02-15 22:07:50 +01:00
state . bsModal . show ( ) ;
else
state . bsModal . hide ( ) ;
} )
const initBsModal = ( ) => {
state . bsModal = new bootstrap . Modal ( state . modal . value ) ;
2024-02-15 22:07:54 +01:00
if ( modalShow . value ) {
2024-02-15 22:07:50 +01:00
state . bsModal . show ( ) ;
state . show = true ;
} else {
state . bsModal . hide ( ) ;
state . show = false ;
}
2024-02-15 22:07:54 +01:00
state . modal . value . addEventListener ( 'hide.bs.modal' , ( ) => {
2024-02-15 22:07:50 +01:00
state . show = false ;
context . emit ( 'update:modelShow' , false ) ;
} ) ;
}
const updateLangText = ( ) => {
const html = document . querySelector ( 'html' ) ;
let lang = html . getAttribute ( 'data-bs-language' ) ;
2024-02-15 22:07:54 +01:00
const [ tip1 , tip2 ] = props . uploadTip . split ( "&" ) ;
if ( lang === "cn" || tip2 === undefined )
2024-02-15 22:07:50 +01:00
state . uploadTip = tip1 ;
else
state . uploadTip = tip2 ;
2024-02-15 22:07:54 +01:00
const [ title1 , title2 ] = props . modalTitle . split ( "&" ) ;
if ( lang === "cn" || title2 === undefined )
2024-02-15 22:07:50 +01:00
state . modalTitle . value = title1 ;
else
state . modalTitle . value = title2 ;
state . uploadLang = lang ;
2024-02-15 22:07:54 +01:00
if ( lang === "cn" )
2024-02-15 22:07:50 +01:00
state . uploadLang = "zh" ;
}
const initUploadFile = ( ) => {
$ ( state . uploadFile . value ) . fileinput ( {
language : state . uploadLang ,
theme : "fa6" ,
dropZoneTitle : state . uploadTip ,
showClose : false ,
2024-02-15 22:07:54 +01:00
browseClass : "btn btn-primary btn-df" ,
2024-02-15 22:07:52 +01:00
allowedFileExtensions : uploadAllow . value ,
2024-02-15 22:07:50 +01:00
uploadUrl : props . uploadAction ,
maxFileCount : isNaN ( Number ( props . uploadCount ) ) ? 1 : Number ( props . uploadCount )
} ) ;
2024-02-15 22:07:54 +01:00
$ ( state . uploadFile . value ) . on ( 'fileuploaded' , function ( event , data ) {
2024-02-15 22:07:50 +01:00
state . bsModal . hide ( ) ;
state . show = false ;
$ ( state . uploadFile . value ) . fileinput ( 'clear' ) ;
2024-02-15 22:07:54 +01:00
context . emit ( "upload-success" , data )
2024-02-15 22:07:50 +01:00
} ) ;
2024-02-15 22:07:54 +01:00
$ ( state . uploadFile . value ) . on ( 'fileuploaderror' , function ( event , data , msg ) {
if ( data . jqXHR . responseText ) {
2024-02-15 22:07:50 +01:00
var errMsg = eval ( data . jqXHR . responseText ) ;
2024-02-15 22:07:54 +01:00
context . emit ( "upload-error" , errMsg ) ;
2024-02-15 22:07:50 +01:00
}
} ) ;
}
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
const html = document . querySelector ( 'html' ) ;
2024-02-15 22:07:54 +01:00
html . addEventListener ( "loaded" , ( ) => {
2024-02-15 22:07:50 +01:00
updateLangText ( ) ;
initBsModal ( ) ;
initUploadFile ( ) ;
} )
2024-02-15 22:07:52 +01:00
const observer = new mutationObserver ( ( ) => {
updateLangText ( ) ;
} ) ;
const config = {
attributes : true ,
attributeFilter : [ "data-bs-language" ] ,
subtree : false
} ;
observer . observe ( html , config ) ;
2024-02-15 22:07:50 +01:00
} )
2024-02-15 22:07:54 +01:00
return { ... state , modalFade }
2024-02-15 22:07:50 +01:00
}
}
export const upgradeModalComponent = {
template : ` <div :class="['modal',{'fade':modalFade===undefined ? false : JSON.parse(modalFade)}]" data-bs-backdrop="static" tabindex="-1" aria-hidden="true" ref="modal">
< div class = "modal-dialog modal-lg modal-dialog-centered" >
< div : class = "['modal-content front',{'front0':!showLog},{'front180':showLog}]" >
< div class = "modal-header" >
< h5 class = "modal-title" >
< cn > 升级包 < / c n >
< en > Upgrade < / e n >
< / h 5 >
< button type = "button" class = "btn-close" data - bs - dismiss = "modal" aria - label = "Close" > < / b u t t o n >
< / d i v >
< div class = "modal-body px-3" >
< table class = "table table-bordered" >
< thead >
< tr >
< th >
< cn > 序号 < / c n >
< en > Num < / e n >
< / t h >
< th >
< cn > 名称 < / c n >
< en > Name < / e n >
< / t h >
< th >
< cn > 版本 < / c n >
< en > Build < / e n >
< / t h >
< th >
< cn > 日期 < / c n >
< en > Date < / e n >
< / t h >
< th >
< cn > 级别 < / c n >
< en > Impact < / e n >
< / t h >
< th >
< cn > 日志 < / c n >
< en > Log < / e n >
< / t h >
< th >
< cn > 操作 < / c n >
< en > Option < / e n >
< / t h >
< th >
< cn > 下载 < / c n >
< en > Download < / e n >
< / t h >
< / t r >
< / t h e a d >
< tbody >
< tr v - for = "(item,index) in systemPatchs" : key = "item.id" >
< td > { { index + 1 } } < / t d >
< td > { { item . name } } < / t d >
< td > { { item . build } } < / t d >
< td > { { item . sys _ver } } < / t d >
< td v - if = "item.impact === '1'" class = "lp-color-red" >
< cn > 重要 < / c n >
< en > impact < / e n >
< / t d >
< td v - else >
< cn > 普通 < / c n >
< en > normal < / e n >
< / t d >
< td >
< a class = "lp-cursor-pointer" @ click = "showPatchVersionLog(index)" >
< cn > 更新日志 < / c n >
< en > Show logs < / e n >
< / a >
< / t d >
< td >
2024-02-15 22:07:52 +01:00
< a v - if = "item.allow" class = "lp-cursor-pointer" @ click = "handleUpdatePatch(index)" >
2024-02-15 22:07:50 +01:00
< div v - if = "upgradePatch.id === item.id && hadUpdate" > { { updatePercent } } % < / d i v >
< div v - else >
< cn > 更新 < / c n >
< en > Update < / e n >
< / d i v >
< / a >
2024-02-15 22:07:52 +01:00
< a v - else > / < / a >
2024-02-15 22:07:50 +01:00
< / t d >
< td >
2024-02-15 22:07:52 +01:00
< a v - if = "item.allow" class = "lp-cursor-pointer" @ click = "handleDownloadPatch(index)" >
2024-02-15 22:07:50 +01:00
< cn > 下载 < / c n >
< en > Download < / e n >
< / a >
2024-02-15 22:07:52 +01:00
< a v - else > / < / a >
2024-02-15 22:07:50 +01:00
< / t d >
< / t r >
< / t b o d y >
< / t a b l e >
< div class = "row mt-4 mb-2" >
< div class = "col-lg-12" >
< cn > Tip : 级别标记为 < cn style = "color: red" > 重要 < / c n > 的 升 级 包 不 能 跳 过 , 更 新 之 后 才 能 继 续 更 新 。 < / c n >
< en > Tip : Upgrade packages marked as < en style = "color: red" > impact < / e n > c a n n o t b e s k i p p e d a n d c a n o n l y b e u p d a t e d a f t e r t h e y h a v e b e e n u p d a t e d < / e n >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< div : class = "['modal-content rear',{'rear180':!showLog},{'rear0':showLog}]" >
< div v - if = "Object.keys(showLogPatch).length > 0" >
< div class = "modal-header" >
< h5 class = "modal-title" >
Build { { showLogPatch . sys _ver } }
< / h 5 >
< button type = "button" class = "btn-close" @ click = "hidePatchVersionLog" > < / b u t t o n >
< / d i v >
< div class = "modal-body" >
< ul >
< li class = "mt-2" v - for = "(it,idx) in handleVersionLogs" : key = "idx" style = "font-size: 15px;white-space:pre-wrap;" > { { it } } < / l i >
< / u l >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ,
2024-02-15 22:07:52 +01:00
props : {
modalShow : {
type : Boolean ,
default : false
} ,
modalFade : {
2024-02-15 22:07:54 +01:00
type : Boolean ,
2024-02-15 22:07:52 +01:00
default : true
} ,
checkUpgrade : {
type : Boolean ,
default : false
} ,
patchSn : {
type : String ,
2024-02-15 22:07:54 +01:00
default : ""
2024-02-15 22:07:52 +01:00
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
const { modalFade , checkUpgrade , patchSn } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const state = {
modal : ref ( null ) ,
checkUpgrade : ref ( false ) ,
2024-02-15 22:07:54 +01:00
systemPatchs : reactive ( [ ] ) ,
showLog : ref ( false ) ,
showLogPatch : ref ( { } ) ,
hadUpdate : ref ( false ) ,
updatePercent : ref ( 0 ) ,
upgradePatch : ref ( { } ) ,
facAliase : "" ,
2024-02-15 22:07:50 +01:00
bsModal : { } ,
}
2024-02-15 22:07:54 +01:00
watchEffect ( async ( ) => {
if ( checkUpgrade . value ) {
2024-02-15 22:07:50 +01:00
let result = await func ( "/upgrade/checkHelpNet" ) ;
if ( result . status === "error" ) {
alertMsg ( result . msg , "error" ) ;
return ;
}
2024-02-15 22:07:54 +01:00
if ( ! patchSn . value ) {
2024-02-15 22:07:50 +01:00
result = await func ( "/upgrade/getSystemAliase" ) ;
if ( result . status === "error" ) {
alertMsg ( result . msg , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
if ( result . data . length === 0 ) {
alertMsg ( "<cn>已经是最新版本</cn><en>It is the latest version</en>" , "success" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
state . facAliase = result . data [ 0 ] . aliase ;
result = await func ( "/upgrade/getAllSystemPatch" ) ;
if ( result . status === "error" ) {
alertMsg ( result . msg , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
if ( result . data . length === 0 ) {
alertMsg ( "<cn>已经是最新版本</cn><en>It is the latest version</en>" , "success" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
state . systemPatchs . splice ( 0 ) ;
state . systemPatchs . push ( ... result . data ) ;
2024-02-15 22:07:52 +01:00
let hadImpact = false ;
2024-02-15 22:07:54 +01:00
for ( let i = 0 ; i < state . systemPatchs . length ; i ++ ) {
2024-02-15 22:07:52 +01:00
state . systemPatchs [ i ] . allow = true ;
2024-02-15 22:07:54 +01:00
if ( ! hadImpact ) {
2024-02-15 22:07:52 +01:00
const impact = state . systemPatchs [ i ] . impact ;
hadImpact = impact === "1" ;
} else {
state . systemPatchs [ i ] . allow = false ;
}
}
2024-02-15 22:07:50 +01:00
result = await func ( "/upgrade/checkVersionMaster" ) ;
if ( result . status === "error" ) {
alertMsg ( result . msg , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
if ( result . data === 0 ) {
confirm ( {
title : '<cn>注意</cn><en>Tip</en>' ,
content : '<cn>设备可能升级过其他固件,如果继续升级,功能可能会被覆盖,是否继续?</cn><en>The device may have been upgraded with custom firmware, and the upgrade function may be overwritten. Do you want to continue?</en>' ,
buttons : {
ok : {
text : "<cn>继续</cn><en>Continue</en>" ,
btnClass : 'btn-primary' ,
keys : [ 'enter' ] ,
action : ( ) => {
state . bsModal . show ( ) ;
}
} ,
cancel : {
text : "<cn>取消</cn><en>Cancel</en>" ,
2024-02-15 22:07:54 +01:00
action : ( ) => {
2024-02-15 22:07:50 +01:00
context . emit ( 'update:checkUpgrade' , false ) ;
}
}
}
} ) ;
} else {
state . bsModal . show ( ) ;
}
} else {
let result = await func ( "/upgrade/getSystemAliase" ) ;
if ( result . status === "error" ) {
alertMsg ( result . msg , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
if ( result . data . length === 0 ) {
alertMsg ( "<cn>无效固件编号</cn><en>Invalid upgrade sn</en>" , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
state . facAliase = result . data [ 0 ] . aliase ;
2024-02-15 22:07:54 +01:00
result = await func ( "/upgrade/getSystemPatchBySn" , { "sn" : patchSn . value } ) ;
2024-02-15 22:07:50 +01:00
if ( result . data . length === 0 ) {
alertMsg ( "<cn>无效固件编号</cn><en>Invalid upgrade sn</en>" , "error" ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
return ;
}
state . systemPatchs . splice ( 0 ) ;
state . systemPatchs . push ( ... result . data ) ;
2024-02-15 22:07:52 +01:00
let hadImpact = false ;
2024-02-15 22:07:54 +01:00
for ( let i = 0 ; i < state . systemPatchs . length ; i ++ ) {
2024-02-15 22:07:52 +01:00
state . systemPatchs [ i ] . allow = true ;
2024-02-15 22:07:54 +01:00
if ( ! hadImpact ) {
2024-02-15 22:07:52 +01:00
const impact = state . systemPatchs [ i ] . impact ;
hadImpact = impact === "1" ;
} else {
state . systemPatchs [ i ] . allow = false ;
}
}
2024-02-15 22:07:50 +01:00
state . bsModal . show ( ) ;
}
}
} )
2024-02-15 22:07:54 +01:00
const handleVersionLogs = computed ( ( ) => {
2024-02-15 22:07:50 +01:00
const regex = /[\r\n\t]/g ;
2024-02-15 22:07:54 +01:00
state . showLogPatch . value . description = state . showLogPatch . value . description . replace ( regex , "" ) ;
return state . showLogPatch . value . description . split ( ";" ) . filter ( ( item ) => {
2024-02-15 22:07:50 +01:00
return item !== "" ;
} )
} )
const showPatchVersionLog = idx => {
state . showLogPatch . value = state . systemPatchs [ idx ] ;
state . showLog . value = true ;
}
const hidePatchVersionLog = ( ) => {
state . showLog . value = false ;
}
const getUpdateFileSize = async name => {
const params = {
"action" : "get_file_size" ,
"name" : name
} ;
const data = await axios _post ( "/link/upgrade.php" , params ) ;
return data . size ;
} ;
const handleUpdatePatch = idx => {
2024-02-15 22:07:54 +01:00
if ( state . hadUpdate . value )
2024-02-15 22:07:50 +01:00
return ;
state . upgradePatch . value = state . systemPatchs [ idx ] ;
const patch = state . systemPatchs [ idx ] ;
const chip = patch . chip ;
let name = patch . name ;
let type = "update" ;
2024-02-15 22:07:54 +01:00
if ( name . indexOf ( "_sn_" ) > 0 ) {
name = name . replace ( "_sn_" , "_" + state . facAliase + "_" ) ;
2024-02-15 22:07:50 +01:00
type = "sn" ;
} else {
2024-02-15 22:07:54 +01:00
name = name . replace ( "_" , "_" + state . facAliase + "_" ) ;
2024-02-15 22:07:50 +01:00
type = "update" ;
}
const params = {
2024-02-15 22:07:54 +01:00
action : "update" , name : name ,
chip : chip , type : type
2024-02-15 22:07:50 +01:00
}
axios _post ( '/link/upgrade.php' , params )
. then ( async data => {
const total = Number ( data . size ) ;
state . hadUpdate . value = true ;
state . updatePercent . value = 0 ;
2024-02-15 22:07:54 +01:00
if ( total > 0 ) {
2024-02-15 22:07:50 +01:00
const timerId = setInterval ( async function ( ) {
const size = await getUpdateFileSize ( name ) ;
2024-02-15 22:07:54 +01:00
state . updatePercent . value = parseInt ( size / total * 100 ) ;
2024-02-15 22:07:50 +01:00
if ( size >= total ) {
clearInterval ( timerId ) ;
state . bsModal . hide ( ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
state . hadUpdate . value = false ;
state . upgradePatch . value = { } ;
rebootConfirm ( '下载完成,是否立即重启系统完成更新?' ) ;
}
} , 1000 ) ;
}
} )
}
const handleDownloadPatch = idx => {
state . upgradePatch . value = state . systemPatchs [ idx ] ;
const patch = state . systemPatchs [ idx ] ;
const chip = patch . chip ;
let name = patch . name ;
let type = "update" ;
2024-02-15 22:07:54 +01:00
if ( name . indexOf ( "_sn_" ) > 0 ) {
name = name . replace ( "_sn_" , "_" + state . facAliase + "_" ) ;
2024-02-15 22:07:50 +01:00
type = "sn" ;
} else {
2024-02-15 22:07:54 +01:00
name = name . replace ( "_" , "_" + state . facAliase + "_" ) ;
2024-02-15 22:07:50 +01:00
type = "update" ;
}
2024-02-15 22:07:54 +01:00
const url = "http://help.linkpi.cn:5735/upgrade/" + chip + "/" + type + "/" + name ;
2024-02-15 22:07:50 +01:00
const downName = "" ;
const a = document . createElement ( 'a' ) ;
const e = document . createEvent ( 'MouseEvents' ) ;
e . initEvent ( 'click' , false , false ) ;
a . href = url ;
a . download = downName ;
a . dispatchEvent ( e ) ;
}
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
state . bsModal = new bootstrap . Modal ( state . modal . value ) ;
2024-02-15 22:07:54 +01:00
state . modal . value . addEventListener ( 'hide.bs.modal' , ( ) => {
2024-02-15 22:07:50 +01:00
context . emit ( 'update:modelShow' , false ) ;
context . emit ( 'update:checkUpgrade' , false ) ;
} ) ;
} )
2024-02-15 22:07:54 +01:00
return {
... state ,
modalFade ,
handleVersionLogs ,
showPatchVersionLog ,
hidePatchVersionLog ,
handleUpdatePatch ,
handleDownloadPatch
}
2024-02-15 22:07:50 +01:00
}
}
export const customModalComponent = {
template : ` <div :class="['modal',{'fade':modalFade}]" tabindex="-1" aria-hidden="true" ref="modal">
< div : class = "['modal-dialog modal-dialog-centered',modalSize]" >
< div : class = "['modal-content',contentClass]" >
< div class = "modal-header" v - if = "hadHeader" >
< h5 class = "modal-title" > { { modalTitle } } < / h 5 >
< button type = "button" class = "btn-close" data - bs - dismiss = "modal" aria - label = "Close" > < / b u t t o n >
< / d i v >
< div : class = "['modal-body',bodyClass]" >
< slot > < / s l o t >
< / d i v >
< div class = "modal-footer" v - if = "hadFooter" >
< button v - if = "cancelCloseModal" type = "button" class = "btn btn-secondary" data - bs - dismiss = "modal" > { { modalCancelBtnName } } < / b u t t o n >
< button v - else type = "button" class = "btn btn-secondary" @ click = "cancelBtnClick" > { { modalCancelBtnName } } < / b u t t o n >
< button type = "button" v - if = "hadConfirmBtn" class = "btn btn-primary" @ click = "confirmBtnClick" > { { modalConfirmBtnName } } < / b u t t o n >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ,
props : {
modalSize : {
2024-02-15 22:07:54 +01:00
type : String ,
default : ""
2024-02-15 22:07:50 +01:00
} ,
hadHeader : {
type : Boolean ,
default : true
} ,
hadFooter : {
type : Boolean ,
default : true
} ,
modalTitle : {
2024-02-15 22:07:54 +01:00
type : String ,
2024-02-15 22:07:50 +01:00
default : "标题"
} ,
modalShow : {
type : Boolean ,
default : false
} ,
modalFade : {
type : Boolean ,
default : true
} ,
bodyClass : {
type : String ,
default : ""
} ,
contentClass : {
type : String ,
default : ""
} ,
confirmBtnName : {
type : String ,
2024-02-15 22:07:54 +01:00
default : "确定"
2024-02-15 22:07:50 +01:00
} ,
cancelBtnName : {
type : String ,
2024-02-15 22:07:54 +01:00
default : "取消"
2024-02-15 22:07:50 +01:00
} ,
hadConfirmBtn : {
type : Boolean ,
default : true
} ,
2024-02-15 22:07:54 +01:00
cancelCloseModal : {
2024-02-15 22:07:50 +01:00
type : Boolean ,
default : true
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
2024-02-15 22:07:54 +01:00
const { modalShow , modalFade , modalTitle } = toRefs ( props ) ;
2024-02-15 22:07:50 +01:00
const state = {
modal : ref ( null ) ,
modalTitle : ref ( "" ) ,
2024-02-15 22:07:54 +01:00
modalConfirmBtnName : ref ( "确定" ) ,
modalCancelBtnName : ref ( "取消" ) ,
2024-02-15 22:07:50 +01:00
show : false ,
bsModal : { } ,
}
2024-02-15 22:07:54 +01:00
watch ( modalShow , ( ) => {
if ( Object . keys ( state . bsModal ) . length === 0 )
return ;
2024-02-15 22:07:50 +01:00
state . show = ! state . show ;
2024-02-15 22:07:54 +01:00
if ( state . show )
2024-02-15 22:07:50 +01:00
state . bsModal . show ( ) ;
else
state . bsModal . hide ( ) ;
context . emit ( 'modal-visible' , state . show ) ;
} )
2024-02-15 22:07:54 +01:00
watch ( modalTitle , ( ) => {
2024-02-15 22:07:50 +01:00
updateLangText ( ) ;
} )
const initBsModal = ( ) => {
state . bsModal = new bootstrap . Modal ( state . modal . value ) ;
2024-02-15 22:07:54 +01:00
if ( modalShow . value ) {
2024-02-15 22:07:50 +01:00
state . bsModal . show ( ) ;
state . show = true ;
} else {
state . bsModal . hide ( ) ;
state . show = false ;
}
context . emit ( 'modal-visible' , state . show ) ;
2024-02-15 22:07:54 +01:00
state . modal . value . addEventListener ( 'hide.bs.modal' , ( ) => {
2024-02-15 22:07:50 +01:00
state . show = false ;
context . emit ( 'update:modelShow' , state . show ) ;
context . emit ( 'modal-visible' , state . show ) ;
} ) ;
}
const confirmBtnClick = ( ) => {
context . emit ( "confirm-btn-click" ) ;
}
const cancelBtnClick = ( ) => {
context . emit ( "cancel-btn-click" ) ;
}
const updateLangText = ( ) => {
const html = document . querySelector ( 'html' ) ;
let lang = html . getAttribute ( 'data-bs-language' ) ;
2024-02-15 22:07:54 +01:00
if ( props . modalTitle !== undefined ) {
const [ title1 , title2 ] = props . modalTitle . split ( "&" ) ;
if ( lang === "cn" || title2 === undefined )
2024-02-15 22:07:50 +01:00
state . modalTitle . value = title1 ;
else
state . modalTitle . value = title2 ;
}
2024-02-15 22:07:54 +01:00
if ( props . confirmBtnName !== undefined ) {
const [ name1 , name2 ] = props . confirmBtnName . split ( "&" ) ;
if ( lang === "cn" || name2 === undefined )
2024-02-15 22:07:50 +01:00
state . modalConfirmBtnName . value = name1 ;
else
state . modalConfirmBtnName . value = name2 ;
}
2024-02-15 22:07:54 +01:00
if ( props . cancelBtnName !== undefined ) {
const [ name1 , name2 ] = props . cancelBtnName . split ( "&" ) ;
if ( lang === "cn" || name2 === undefined )
2024-02-15 22:07:50 +01:00
state . modalCancelBtnName . value = name1 ;
else
state . modalCancelBtnName . value = name2 ;
}
}
2024-02-15 22:07:54 +01:00
onMounted ( ( ) => {
2024-02-15 22:07:50 +01:00
const html = document . querySelector ( 'html' ) ;
2024-02-15 22:07:54 +01:00
html . addEventListener ( "loaded" , ( ) => {
2024-02-15 22:07:50 +01:00
updateLangText ( ) ;
initBsModal ( ) ;
} )
const observer = new mutationObserver ( ( ) => {
updateLangText ( ) ;
} ) ;
const config = {
attributes : true ,
attributeFilter : [ "data-bs-language" ] ,
subtree : false
} ;
observer . observe ( html , config ) ;
} )
2024-02-15 22:07:54 +01:00
return { ... state , modalFade , confirmBtnClick , cancelBtnClick }
2024-02-15 22:07:50 +01:00
}
}
export const loadingButtonComponent = {
template : ` <button type="button" :class="customClass" @click="onButtonClick">
< span v - if = "hadLoading" class = "spinner-border spinner-border-sm" > < / s p a n >
< span v - else >
< slot > < / s l o t >
< / s p a n >
< / b u t t o n > ` ,
2024-02-15 22:07:52 +01:00
props : {
customClass : {
type : String ,
default : ""
} ,
hadLoading : {
type : Boolean ,
default : false
}
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const onButtonClick = ( ) => {
2024-02-15 22:07:54 +01:00
context . emit ( "button-click" , "click" )
2024-02-15 22:07:50 +01:00
}
2024-02-15 22:07:54 +01:00
return { onButtonClick }
2024-02-15 22:07:50 +01:00
}
}
export const ptzDirectComponent = {
template : ` <div class="row">
< div class = "col-lg-12" >
< div class = "row" >
< div class = "col-lg-6 text-center" >
< cn > 云台控制 < / c n >
< en > PTZ < / e n >
< / d i v >
< div class = "col-lg-6 text-center" >
< cn > 预置位 < / c n >
< en > Preset < / e n >
< / d i v >
< / d i v >
< / d i v >
< div class = "col-lg-12 mt-3" >
< div class = "row" >
< div class = "col-lg-6" >
< div class = "row" >
< div class = "col-lg-12 text-center" >
< button type = "button" @ mousedown = "handlePtzMove('left-up')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('left-up')}]" >
< i class = "fa-solid fa-circle-arrow-up" style = "transform: rotate(-45deg);-o-transform: rotate(-45deg);-webkit-transform: rotate(-45deg);-moz-transform: rotate(-45deg);" > < / i >
< / b u t t o n >
< button type = "button" @ mousedown = "handlePtzMove('up')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('up')}]" : style = "{'margin':'0px '+gop+'px'}" >
< i class = "fa-solid fa-circle-arrow-up" > < / i >
< / b u t t o n >
< button type = "button" @ mousedown = "handlePtzMove('right-up')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('right-up')}]" >
< i class = "fa-solid fa-circle-arrow-up" style = "transform: rotate(45deg);-o-transform: rotate(45deg);-webkit-transform: rotate(45deg);-moz-transform: rotate(45deg);" > < / i >
< / b u t t o n >
< / d i v >
< div class = "col-lg-12 text-center" : style = "{'marginTop':gop+'px'}" >
< button type = "button" @ mousedown = "handlePtzMove('left')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('left')}]" >
< i class = "fa-solid fa-circle-arrow-left" > < / i >
< / b u t t o n >
< button type = "button" @ mouseup = "handlePtzMove('home')" : class = "['btn btn-primary',homeClass,{'lp-visibility-hide':!sticks.includes('home')}]" : style = "{'margin':'0px '+gop+'px'}" >
< i class = "fa-solid fa-house" > < / i >
< / b u t t o n >
< button type = "button" @ mousedown = "handlePtzMove('right')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('right')}]" >
< i class = "fa-solid fa-circle-arrow-right" > < / i >
< / b u t t o n >
< / d i v >
< div class = "col-lg-12 text-center" : style = "{'marginTop':gop+'px'}" >
< button type = "button" @ mousedown = "handlePtzMove('left-down')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('left-down')}]" >
< i class = "fa-solid fa-circle-arrow-up" style = "transform: rotate(-135deg);-o-transform: rotate(-135deg);-webkit-transform: rotate(-135deg);-moz-transform: rotate(-135deg);" > < / i >
< / b u t t o n >
< button type = "button" @ mousedown = "handlePtzMove('down')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('down')}]" : style = "{'margin':'0px '+gop+'px'}" >
< i class = "fa-solid fa-circle-arrow-down" > < / i >
< / b u t t o n >
< button type = "button" @ mousedown = "handlePtzMove('right-down')" @ mouseup = "handlePtzMove('move-stop')" : class = "['btn btn-primary',arrowClass,{'lp-visibility-hide':!sticks.includes('right-down')}]" >
< i class = "fa-solid fa-circle-arrow-up" style = "transform: rotate(135deg);-o-transform: rotate(135deg);-webkit-transform: rotate(135deg);-moz-transform: rotate(130deg);" > < / i >
< / b u t t o n >
< / d i v >
< / d i v >
< div class = "row mt-4" >
< div class = "col-lg-3 text-center" >
< cn > 焦距 < / c n >
< en > Zoom < / e n >
< / d i v >
< div class = "col-lg-7 pt-2" >
< noui - slider v - model = "zoom" : min = "zoomMin" : max = "zoomMax" : step = "zoomStep" : fix = "zoomFix" @ slide - end = "onTouchSlideEnd" > < / n o u i - s l i d e r >
< / d i v >
< / d i v >
< / d i v >
< div class = "col-lg-6" >
< div class = "row" >
< div class = "col-lg-12 text-center" >
< button type = "button" @ click = "updatePreset(1)" : class = "['btn',{'btn-primary':presetVal===1},{'btn-default':presetVal!==1},arrowClass]" >
1
< / b u t t o n >
< button type = "button" @ click = "updatePreset(2)" : class = "['btn',{'btn-primary':presetVal===2},{'btn-default':presetVal!==2},arrowClass]" : style = "{'margin':'0px '+gop+'px'}" >
2
< / b u t t o n >
< button type = "button" @ click = "updatePreset(3)" : class = "['btn',{'btn-primary':presetVal===3},{'btn-default':presetVal!==3},arrowClass]" >
3
< / b u t t o n >
< / d i v >
< div class = "col-lg-12 text-center" : style = "{'marginTop':gop+'px'}" >
< button type = "button" @ click = "updatePreset(4)" : class = "['btn',{'btn-primary':presetVal===4},{'btn-default':presetVal!==4},arrowClass]" >
4
< / b u t t o n >
< button type = "button" @ click = "updatePreset(5)" : class = "['btn',{'btn-primary':presetVal===5},{'btn-default':presetVal!==5},arrowClass]" : style = "{'margin':'0px '+gop+'px'}" >
5
< / b u t t o n >
< button type = "button" @ click = "updatePreset(6)" : class = "['btn',{'btn-primary':presetVal===6},{'btn-default':presetVal!==6},arrowClass]" >
6
< / b u t t o n >
< / d i v >
< div class = "col-lg-12 text-center" : style = "{'marginTop':gop+'px'}" >
< button type = "button" @ click = "updatePreset(7)" : class = "['btn',{'btn-primary':presetVal===7},{'btn-default':presetVal!==7},arrowClass]" >
7
< / b u t t o n >
< button type = "button" @ click = "updatePreset(8)" : class = "['btn',{'btn-primary':presetVal===8},{'btn-default':presetVal!==8},arrowClass]" : style = "{'margin':'0px '+gop+'px'}" >
8
< / b u t t o n >
< button type = "button" @ click = "updatePreset(9)" : class = "['btn',{'btn-primary':presetVal===9},{'btn-default':presetVal!==9},arrowClass]" >
9
< / b u t t o n >
< / d i v >
< / d i v >
< div class = "row mt-3" >
< div class = "row-lg-12 text-center" >
< button type = "button" class = "btn btn-primary border-3 px-3 me-1" @ click = "handleCallPreset" >
< cn > 调用 < / c n >
< en > Get < / e n >
< / b u t t o n >
< button type = "button" class = "btn btn-primary border-3 px-3" @ click = "handleSetPreset" >
< cn > 设置 < / c n >
< en > Set < / e n >
< / b u t t o n >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ,
props : {
arrowClass : {
type : String ,
default : "" ,
} ,
homeClass : {
type : String ,
default : "" ,
} ,
gop : {
type : Number ,
default : 5
} ,
sticks : {
type : Array ,
2024-02-15 22:07:54 +01:00
default : [ 'left' , 'left-up' , 'up' , 'right-up' , 'right' , 'right-down' , 'down' , 'left-down' , 'home' ]
2024-02-15 22:07:50 +01:00
} ,
zoomVal : {
type : Number ,
default : 0
} ,
zoomMin : {
type : Number ,
default : 0
} ,
zoomMax : {
type : Number ,
default : 10
} ,
zoomStep : {
type : Number ,
default : 1
} ,
zoomFix : {
type : Number ,
default : 0
}
} ,
2024-02-15 22:07:54 +01:00
components : {
2024-02-15 22:07:50 +01:00
"noui-slider" : nouiSliderComponent
} ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const state = {
zoom : ref ( 0 ) ,
presetVal : ref ( 0 )
}
2024-02-15 22:07:54 +01:00
watch ( ( ) => props . zoomVal , ( newValue , oldValue ) => {
2024-02-15 22:07:50 +01:00
state . zoom . value = newValue ;
} )
const handlePtzMove = type => {
2024-02-15 22:07:54 +01:00
context . emit ( "ptz-move" , type )
2024-02-15 22:07:50 +01:00
}
const updatePreset = val => {
state . presetVal . value = val ;
}
const onTouchSlideEnd = val => {
context . emit ( 'zoom-change' , val ) ;
}
const handleCallPreset = ( ) => {
2024-02-15 22:07:54 +01:00
context . emit ( 'call-preset' , state . presetVal . value ) ;
2024-02-15 22:07:50 +01:00
}
const handleSetPreset = ( ) => {
2024-02-15 22:07:54 +01:00
context . emit ( 'set-preset' , state . presetVal . value ) ;
2024-02-15 22:07:50 +01:00
}
2024-02-15 22:07:54 +01:00
return { ... state , handlePtzMove , onTouchSlideEnd , updatePreset , handleCallPreset , handleSetPreset }
2024-02-15 22:07:50 +01:00
}
}
export const usbOptionComponent = {
2024-02-15 22:07:54 +01:00
template : ` <a :class="['nav-link lp-usb-ctx',{'active':hadMountDisk}]" data-bs-toggle="dropdown">
2024-02-15 22:07:50 +01:00
< div class = "lp-usb-drive" >
< div class = "lp-usb-body" > < / d i v >
< div class = "lp-usb-metal" > < / d i v >
< div class = "lp-usb-hole" > < / d i v >
< / d i v >
< / a >
< div class = "dropdown" >
< ul class = "dropdown-menu dropdown-menu-end" >
< li v - if = "hadMountDisk" >
< a class = "dropdown-item" href = "javascript:;" @ click = "unInstallDisk" >
< span class = "material-symbols-outlined me-2" >
< i class = "fa-solid fa-arrow-up-from-bracket me-2" > < / i >
< cn > 弹出设备 < / c n >
< en > Uninstall < / e n >
< / s p a n >
< / a >
< / l i >
< li v - if = "hadMountDisk" > < hr > < / l i >
< li v - if = "hadMountDisk && Object.keys(diskConf).length > 0 && diskConf.used==='local' && diskConf.local.device!=='/dev/mmcblk0p6'" >
< a class = "dropdown-item" href = "javascript:;" @ click = "formatDisk" >
< span class = "material-symbols-outlined me-2" >
< i class = "fa-solid fa-circle-nodes me-2" > < / i >
< cn > 格式化 < / c n >
< en > Format Disk < / e n >
< / s p a n >
< / a >
< / l i >
< li v - if = "hadMountDisk && Object.keys(diskConf).length > 0 && diskConf.used==='local' && diskConf.local.device!=='/dev/mmcblk0p6'" > < hr > < / l i >
< li >
< a class = "dropdown-item" href = "javascript:;" @ click = "turnMountDisk" >
< span class = "material-symbols-outlined me-2" >
< i class = "fa-solid fa-right-left me-2" > < / i >
< cn > 切换挂载 < / c n >
< en > Change Disk < / e n >
< / s p a n >
< / a >
< / l i >
< li v - if = "hadMountDisk" > < hr > < / l i >
< li v - if = "hadMountDisk" >
< a class = "dropdown-item text-center" href = "javascript:;" >
< span class = "material-symbols-outlined me-2" >
< cn > 已用 < / c n > < e n > U s e d < / e n >
{ { hadMountInfo . used + ' / ' + hadMountInfo . total } }
< / s p a n >
< / a >
< / l i >
< / u l >
< / d i v > ` ,
2024-02-15 22:07:54 +01:00
setup ( props , context ) {
2024-02-15 22:07:50 +01:00
const hadMountInfo = reactive ( { } ) ;
const hadMountDisk = ref ( false ) ;
2024-02-15 22:07:54 +01:00
const { diskConf , handleDiskConf , updateDiskConf } = useDiskConf ( ) ;
2024-02-15 22:07:50 +01:00
const unInstallDisk = ( ) => {
confirm ( {
title : '<cn>卸载磁盘</cn><en>UnInstall Disk</en>' ,
content : '<cn>是否卸载磁盘,请确保没有处于录制状态</cn><en>Whether to uninstall the disk, please make sure it is not in the recording state</en>' ,
buttons : {
ok : {
text : "<cn>卸载</cn><en>Confirm</en>" ,
btnClass : 'btn-primary' ,
action : ( ) => {
func ( "/system/umountDisk" ) . then ( res => {
2024-02-15 22:07:54 +01:00
alertMsg ( res . msg , res . status ) ;
2024-02-15 22:07:50 +01:00
} )
}
} ,
cancel : {
text : "<cn>取消</cn><en>Cancel</en>" ,
2024-02-15 22:07:54 +01:00
action : ( ) => {
}
2024-02-15 22:07:50 +01:00
}
}
} ) ;
}
const formatDisk = ( ) => {
confirm ( {
title : '<cn>格式化磁盘</cn><en>Formatted Disk</en>' ,
content : ` <div class="row">
< div class = "col-lg-11" >
< div class = "row mt-2" >
< div class = "col-lg-3 lp-align-center" >
< label >
< cn > 磁盘格式 < / c n >
< en > Format < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-9" >
< select class = "form-select" id = "diskFormat" >
< option value = "ext4" > EXT4 < / o p t i o n >
< option value = "fat32" > FAT32 < / o p t i o n >
< / s e l e c t >
< / d i v >
< / d i v >
< div class = "row mt-2" >
< div class = "col-lg-3 lp-align-center" >
< label >
< cn > 登录密码 < / c n >
< en > Password < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-9" >
< input class = "form-control" type = "password" id = "formatPasswd" autocomplete = "off" >
< / d i v >
< / d i v >
< div class = "row mt-4" >
< div class = "col-lg-12 p-0" >
< label class = "ms-3" >
< cn > Tip : 格式化将清空磁盘数据 , 且不可逆转 , 请谨慎操作 。 < / c n >
< en > Tip : Formatting will erase disk data and is irreversible . < / e n >
< / l a b e l >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ,
buttons : {
ok : {
text : "<cn>格式化</cn><en>Format</en>" ,
btnClass : 'btn-primary' ,
action : ( ) => {
const formatPasswd = document . querySelector ( "#formatPasswd" ) . value ;
2024-02-15 22:07:54 +01:00
func ( "/system/formatReady" , { "psd" : formatPasswd } ) . then ( res => {
return new Promise ( ( resolve , reject ) => {
if ( res . status === "error" ) {
alertMsg ( res . msg , res . status ) ;
2024-02-15 22:07:50 +01:00
reject ( ) ;
return ;
}
resolve ( ) ;
} )
2024-02-15 22:07:54 +01:00
} ) . then ( ( ) => {
2024-02-15 22:07:50 +01:00
const diskFormat = document . querySelector ( "#diskFormat" ) . value ;
2024-02-15 22:07:54 +01:00
const notify = alertMsg ( "<cn>正在格式化,请勿关闭此页面</cn><en>Do not close this page while formatting</en>" , "success" , 99999999 ) ;
func ( "/system/formatDisk" , { "format" : diskFormat } ) ;
let interval = setInterval ( ( ) => {
2024-02-15 22:07:50 +01:00
func ( "/system/checkFormatProgress" ) . then ( res => {
2024-02-15 22:07:54 +01:00
if ( res . data === 0 ) {
2024-02-15 22:07:50 +01:00
clearInterval ( interval ) ;
notify . remove ( ) ;
2024-02-15 22:07:54 +01:00
setTimeout ( ( ) => alertMsg ( res . msg , res . status ) , 600 ) ;
2024-02-15 22:07:50 +01:00
}
} )
2024-02-15 22:07:54 +01:00
} , 5000 ) ;
2024-02-15 22:07:50 +01:00
} )
}
} ,
cancel : {
text : "<cn>取消</cn><en>Cancel</en>" ,
2024-02-15 22:07:54 +01:00
action : ( ) => {
}
2024-02-15 22:07:50 +01:00
}
}
} ) ;
}
const checkMountDisk = ( ) => {
func ( "/system/getMountDiskSpace" ) . then ( res => {
2024-02-15 22:07:54 +01:00
Object . assign ( hadMountInfo , res . data ) ;
2024-02-15 22:07:50 +01:00
hadMountDisk . value = ( res . status === "success" ) ;
} )
2024-02-15 22:07:54 +01:00
setTimeout ( checkMountDisk , 1000 ) ;
2024-02-15 22:07:50 +01:00
}
const turnMountDisk = ( ) => {
const html = document . querySelector ( "html" ) ;
const lang = html . getAttribute ( "data-bs-language" ) ;
const jc = confirm ( {
title : '<cn>磁盘挂载</cn><en>Mount Disk</en>' ,
content : ` <div class="row">
< div class = "col-lg-12" >
< div class = "row mt-3" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 类型 < / c n >
< en > Type < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< select class = "form-select" id = "mount_device" >
< option value = "shared" > $ { lang === "cn" ? "网络磁盘" : "net disk" } < / o p t i o n >
< option value = "local" > $ { lang === "cn" ? "移动磁盘" : "usb disk" } < / o p t i o n >
< / s e l e c t >
< / d i v >
< / d i v >
< div class = "row mt-3 local-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 设备 < / c n >
< en > Device < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< select class = "form-select" id = "local_devices" > < / s e l e c t >
< / d i v >
< / d i v >
< div class = "row mt-3 share-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 协议 < / c n >
< en > Protocol < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< select class = "form-select" id = "shared_protocol" >
< option value = "cifs" > $ { lang === "cn" ? "cifs (windows共享目录)" : "cifs (windows shared directory)" } < / o p t i o n >
< option value = "nfs" > nfs < / o p t i o n >
< / s e l e c t >
< / d i v >
< / d i v >
< div class = "row mt-3 cifs-auth share-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 用户名 < small style = "color: gray;font-size: 11px;" > ( 选填 ) < / s m a l l > < / c n >
< en > Username < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< input class = "form-control" id = "shared_uname" >
< / d i v >
< / d i v >
< div class = "row mt-3 cifs-auth share-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 密码 < small style = "color: gray;font-size: 11px;" > ( 选填 ) < / s m a l l > < / c n >
< en > Password < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< input class = "form-control" id = "shared_passwd" >
< / d i v >
< / d i v >
< div class = "row mt-3 share-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > IP地址 < / c n >
< en > IP Address < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< input class = "form-control" id = "shared_ip" >
< / d i v >
< / d i v >
< div class = "row mt-3 share-device" >
< div class = "col-lg-3 offset-lg-1 lp-align-center" >
< label >
< cn > 挂载路径 < / c n >
< en > Mount Path < / e n >
< / l a b e l >
< / d i v >
< div class = "col-lg-7" >
< input class = "form-control" id = "shared_path" >
< / d i v >
< / d i v >
< div class = "row" style = "padding-top: 30px;padding-left: 30px;color: gray" >
< label class = "col-lg-12" >
< cn > Tip : 更换挂载设备时 , 请确保没有处于录制状态 < / c n >
< en > Tip : Make sure that you are not recording when you change the mounted device < / e n >
< / l a b e l >
< / d i v >
< / d i v >
< / d i v > ` ,
buttons : {
ok : {
text : "<cn>挂载</cn><en>Mount</en>" ,
btnClass : 'btn-primary' ,
action : ( ) => {
updateDiskConf ( {
enable : true ,
used : document . querySelector ( '#mount_device' ) . value ,
shared : {
2024-02-15 22:07:54 +01:00
ip : document . querySelector ( '#shared_ip' ) . value ,
2024-02-15 22:07:50 +01:00
type : document . querySelector ( '#shared_protocol' ) . value ,
path : document . querySelector ( '#shared_path' ) . value ,
2024-02-15 22:07:54 +01:00
auth : {
2024-02-15 22:07:50 +01:00
uname : document . querySelector ( '#shared_uname' ) . value ,
passwd : document . querySelector ( '#shared_passwd' ) . value ,
}
} ,
local : {
2024-02-15 22:07:54 +01:00
device : document . querySelector ( '#local_devices' ) . value
2024-02-15 22:07:50 +01:00
}
2024-02-15 22:07:54 +01:00
} ) . then ( async ( ) => {
2024-02-15 22:07:50 +01:00
handleDiskConf ( ) ;
2024-02-15 22:07:54 +01:00
alertMsg ( "<cn>磁盘检测中,请稍后...</cn><en>Disk checking, please wait...</en>" , "success" ) ;
2024-02-15 22:07:50 +01:00
const result = await func ( "/system/mountDisk" ) ;
2024-02-15 22:07:54 +01:00
if ( result . status === "success" )
2024-02-15 22:07:50 +01:00
jc . close ( ) ;
2024-02-15 22:07:54 +01:00
setTimeout ( ( ) => alertMsg ( result . msg , result . status ) , 600 ) ;
2024-02-15 22:07:50 +01:00
} ) ;
return false ;
}
} ,
cancel : {
text : "<cn>取消</cn><en>Cancel</en>" ,
2024-02-15 22:07:54 +01:00
action : ( ) => {
}
2024-02-15 22:07:50 +01:00
}
} ,
2024-02-15 22:07:54 +01:00
onOpenBefore : ( ) => {
const display = ( type , protocol ) => {
2024-02-15 22:07:50 +01:00
const shareElements = document . querySelectorAll ( '.share-device' ) ;
const localElements = document . querySelectorAll ( '.local-device' ) ;
shareElements . forEach ( element => element . style . display = 'none' ) ;
localElements . forEach ( element => element . style . display = 'none' ) ;
2024-02-15 22:07:54 +01:00
if ( type === "shared" ) {
2024-02-15 22:07:50 +01:00
shareElements . forEach ( element => element . style . display = '' ) ;
const cifsAuthElements = document . querySelectorAll ( '.cifs-auth' ) ;
document . querySelector ( '#shared_protocol' ) . value = protocol ;
cifsAuthElements . forEach ( element => element . style . display = 'none' ) ;
2024-02-15 22:07:54 +01:00
if ( protocol === 'cifs' )
2024-02-15 22:07:50 +01:00
cifsAuthElements . forEach ( element => element . style . display = '' ) ;
return ;
}
localElements . forEach ( element => element . style . display = '' ) ;
}
func ( "/system/getLocalDisk" ) . then ( result => {
const html = document . querySelector ( "html" ) ;
const lang = html . getAttribute ( "data-bs-language" ) ;
result . data . forEach ( item => {
const option = document . createElement ( 'option' ) ;
option . value = item . name ;
2024-02-15 22:07:54 +01:00
if ( item . name === "/dev/mmcblk0p6" ) {
if ( lang === "cn" )
2024-02-15 22:07:50 +01:00
item . name = "内部存储" ;
else
item . name = "device storage" ;
}
2024-02-15 22:07:54 +01:00
option . text = item . name + "( " + item . size + " )" ;
2024-02-15 22:07:50 +01:00
document . querySelector ( '#local_devices' ) . add ( option ) ;
} )
} )
document . querySelector ( '#mount_device' ) . value = diskConf . used ;
document . querySelector ( '#local_devices' ) . value = diskConf . local . device ;
document . querySelector ( '#shared_protocol' ) . value = diskConf . shared . type ;
document . querySelector ( '#shared_uname' ) . value = diskConf . shared . auth . uname ;
document . querySelector ( '#shared_passwd' ) . value = diskConf . shared . auth . passwd ;
document . querySelector ( '#shared_ip' ) . value = diskConf . shared . ip ;
document . querySelector ( '#shared_path' ) . value = diskConf . shared . path ;
2024-02-15 22:07:54 +01:00
display ( diskConf . used , diskConf . shared . type ) ;
2024-02-15 22:07:50 +01:00
document . querySelector ( '#mount_device' ) . addEventListener ( 'change' , ( ) => {
const type = document . querySelector ( '#mount_device' ) . value ;
2024-02-15 22:07:54 +01:00
display ( type , "cifs" ) ;
2024-02-15 22:07:50 +01:00
} ) ;
document . querySelector ( '#shared_protocol' ) . addEventListener ( 'change' , ( ) => {
const protocol = document . querySelector ( '#shared_protocol' ) . value ;
2024-02-15 22:07:54 +01:00
display ( "shared" , protocol ) ;
2024-02-15 22:07:50 +01:00
} ) ;
}
} ) ;
}
onMounted ( checkMountDisk ) ;
2024-02-15 22:07:54 +01:00
return { hadMountInfo , hadMountDisk , diskConf , unInstallDisk , formatDisk , turnMountDisk }
2024-02-15 22:07:50 +01:00
}
}