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'
import { func, confirm, rebootConfirm, alertMsg, axios_post, isEmpty,formatTime } from './lp.utils.js'
import { useDiskConf } from "./vue.hooks.js";
const {ref,reactive,toRefs,watch,watchEffect,
computed,onMounted,nextTick,defineAsyncComponent} = vue;
export const ignoreCustomElementPlugin = {
install: (app) => {
app.config.compilerOptions.isCustomElement = (tag) => tag === 'cn' || tag === 'en';
}
};
export const highlightTextPlugin = {
install(app, options) {
//const urlParam = options.urlParam || 'highlight';
//const urlValue = new URLSearchParams(window.location.search).get(urlParam);
const urlValue = "预"
if (urlValue) {
nextTick(()=>{
const elements = document.querySelectorAll('main cn, main en');
elements.forEach((el) => {
const textContent = el.textContent;
const startIndex = textContent.indexOf(urlValue);
if (startIndex !== -1) {
const endIndex = startIndex + urlValue.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;
}
})
})
}
}
};
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: `
`,
props: ['value','color'],
setup(props, context) {
const tmp_mask = ref(null);
const tmp_text = ref(null);
const { value } = toRefs(props);
watch(value,()=>{
tmp_mask.value.style.bottom = props.value + '%';
tmp_text.value.textContent = props.value + '℃';
})
onMounted(()=>{
tmp_mask.value.parentElement.style.background = props.color;
})
return { tmp_mask,tmp_text }
}
};
export const statusPieChartComponent = {
template: ``,
props: {
modelValue: {
type:Number,
default: 0
},
activeColor: {
type: String,
default: "#fb0"
},
trackColor: {
type: String,
default: "#777"
}
},
setup(props, context) {
const pie_chart = ref(null);
const pie_text = ref(null);
const { modelValue } = toRefs(props);
watch(modelValue,newValue => {
if($(pie_chart.value).data( 'easyPieChart' ))
$(pie_chart.value).data( 'easyPieChart' ).update( newValue);
})
onMounted(()=>{
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) + "%";
}
});
})
return { pie_chart,pie_text }
}
};
export const netFlotChartComponent = {
template: `
`,
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,
default:"#eee"
},
borderColor: {
type: String,
default: "#ccc"
},
tipBorderColor:{
type: String,
default: "#fb0"
},
tipBgColor: {
type: String,
default: "#fff"
},
tipTxtColor: {
type: String,
default: "#555"
}
},
setup(props,context) {
const net_chart = ref(null);
let plot = {};
const showTooltip = (x, y, color, contents) => {
$('' + contents + '
').css({
position: 'absolute',
display: 'none',
top: y - 40,
left: x - 120,
border: '2px solid ' + props.tipBorderColor,
padding: '3px',
'font-size': '9px',
'border-radius': '5px',
'color':props.tipTxtColor,
'background-color': props.tipBgColor,
'font-family': 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
opacity: 0.9
}).appendTo("body").fadeIn(200);
}
const initPlot = () => {
if(Object.keys(plot).length === 0) {
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,
tickFormatter: ( v, axis ) => {
if ( axis.max < 1024 )
return v + "Kb/s";
else {
v /= 1024;
if ( axis.max < 10240 )
return v.toFixed( 2 ) + "Mb/s";
else
return Math.floor( v ) + "Mb/s";
}
}
},
xaxis: {
show: false
},
grid: {
hoverable: true,
clickable: true,
tickColor: props.tickColor,
borderWidth: 1,
borderColor: props.borderColor,
},
colors: [ props.line1Color, props.line2Color ],
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];
if(data > 1024)
data = parseInt(data/1024)+"Mb/s";
else
data += "kb/s";
if (item.seriesIndex === 0)
showTooltip(item.pageX + 100, item.pageY - 10, color, "上行upward: " + data);
if (item.seriesIndex === 1)
showTooltip(item.pageX + 100, item.pageY - 10, color, "下行downward: " + data);
}
}
else {
prePoint = null;
preLabel = null;
$(this).css({
"cursor": "auto"
});
$("#tooltip").remove();
}
});
}
$(net_chart.value).tooltip();
}
}
const updatePlot = () => {
if(Object.keys(plot).length !== 0) {
let maxy = props.maxy;
let data1 = props.data1;
let data2 = props.data2;
plot.setData([data1, data2]);
plot.draw();
plot.getOptions().yaxes[ 0 ].max = maxy;
plot.getOptions().yaxes[ 0 ].tickSize = Math.floor( maxy / 5 );
plot.setupGrid();
}
}
watch(props.data1,()=>{
updatePlot();
},{deep: true})
onMounted(()=>{
setTimeout(initPlot,100);
})
return {net_chart}
}
}
export const bootstrapSwitchComponent = {
template: ``,
props: {
modelValue: {
type: Boolean,
default: false
},
size: {
type: String,
default:"small" //normal
}
},
setup(props, context) {
const { modelValue,size } = toRefs(props);
const bs_switch = ref(null);
watch(modelValue,()=>{
$(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);
}
})
})
return { bs_switch }
}
};
export const multipleSelectComponent = {
template: ``,
props: {
value1: {
type: [Number,String,Boolean],
default: 0
},
value2: {
type: [Number,String,Boolean],
default: 0
},
split: {
type: String,
default: 0
}
},
setup(props,context){
let selectValue = ref("");
watchEffect(()=>{
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);
};
const onSelectChange = () =>{
let [value1, value2] = selectValue.value.split(props.split);
context.emit('update:value1', parseValue(value1));
context.emit('update:value2', parseValue(value2));
}
onMounted(()=>{
selectValue.value = props.value1 + props.split + props.value2;
})
return {selectValue,onSelectChange}
}
};
export const multipleInputComponent = {
template: ``,
props: {
value1: {
type: [Number,String],
default: 0
},
value2: {
type: [Number,String],
default: 0
},
split: {
type: String,
default: 0
}
},
setup(props,context) {
let selectValue = ref("");
const { value1,value2 } = toRefs(props);
watchEffect(()=>{
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;
})
const onInputChange = () =>{
let [val1,val2] = selectValue.value.split(props.split);
val1 = isNaN(Number(val1)) ? val1 : Number(val1);
val2 = isNaN(Number(val2)) ? val2 : Number(val2);
if(typeof val1 === "string")
val1 = val1.trim();
if(typeof val2 === "string")
val2 = val2.trim();
context.emit('update:value1', val1);
context.emit('update:value2', val2);
selectValue.value = val1 + props.split + val2;
}
return {selectValue,onInputChange}
}
};
export const nouiSliderComponent = {
template: ``,
props: {
modelValue: {
type: [Number,String],
default: 0
},
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
}
},
setup(props,context) {
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 => {
if(isEmpty(props.format)) {
if(props.fix === 0)
value = parseInt(value);
else
value = parseFloat(value).toFixed(props.fix);
}
if(props.format === "time")
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},
});
if(!hover)
hideTooltip();
}
});
watch(() => props.funcValue, (newValue, oldValue) => {
if (slider.value && !isSlide) {
slider.value.noUiSlider.updateOptions({
start: newValue,
range: {'min': props.min, 'max': props.max},
});
if(!hover)
hideTooltip();
}
});
watch(() => props.max, (newValue, oldValue) => {
if (slider.value && !isSlide) {
slider.value.noUiSlider.updateOptions({
range: {'min': props.min, 'max': newValue},
});
if(!hover)
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,
});
if(props.disable)
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]));
context.emit('slide-end', formatTooltipValue(values[mark]),props.index);
});
})
return { slider }
}
};
export const h5PlayerComponent = {
template: ``,
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
}
},
setup(props,context) {
const { url,codec,audio,buffer,canplay } = toRefs(props);
const state = {
videoHandler: ref(null),
jessHandler: ref(null),
cloudHandler: ref(null),
hadInitPlayer: false,
flvJsModule: {},
h5Player: {},
}
watchEffect(()=>{
if(canplay.value) {
if(url.value !== "") {
if(state.hadInitPlayer)
destroyPlayer();
setTimeout(initPlayer,300);
}
} else {
if(state.hadInitPlayer)
destroyPlayer();
}
})
const initPlayer = async () => {
if(props.url === "")
return;
if(props.codec === "h265") {
state.videoHandler.value.style.display = 'none';
state.jessHandler.value.style.display = 'block';
if(!window.Jessibuca)
await import('../plugins/jessibuca/jessibuca.js');
state.h5Player = new Jessibuca({
container: state.jessHandler.value,
videoBuffer: buffer.value/1000,
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';
if(!window.flvjs)
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();
state.videoHandler.value.addEventListener("canplay",() => {
state.cloudHandler.value.style.display = 'none'
});
}
state.hadInitPlayer = true;
}
const destroyPlayer = () => {
if(Object.keys(state.h5Player).length > 0) {
if(state.h5Player.hasOwnProperty("unload")) {
state.h5Player.unload();
state.h5Player.detachMediaElement();
}
state.h5Player.destroy();
state.h5Player = {};
}
state.cloudHandler.value.style.display = 'flex';
state.videoHandler.value.removeEventListener("canplay",()=>{});
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);
return { ...state }
}
};
export const videoPlayerComponent = {
template: ``,
props: {
url: {
type: String,
default: ""
},
canplay: {
type: Boolean,
default: true
}
},
setup(props,context) {
const { url,canplay } = toRefs(props);
const state = {
videoHandler: ref(null),
cloudHandler: ref(null),
hadInitPlayer: false,
}
watchEffect(()=>{
if(canplay.value) {
if(url.value !== "") {
if(state.hadInitPlayer)
destroyPlayer();
setTimeout(initPlayer,300);
}
} else {
if(state.hadInitPlayer)
destroyPlayer();
}
})
const initPlayer = () => {
if(url.value === "")
return;
state.videoHandler.value.style.display = 'block';
state.videoHandler.value.src = url.value;
state.videoHandler.value.play();
state.videoHandler.value.addEventListener("canplay",() => {
state.cloudHandler.value.style.display = 'none'
});
state.hadInitPlayer = true;
}
const destroyPlayer = () => {
state.cloudHandler.value.style.display = 'flex';
state.videoHandler.value.removeEventListener("canplay",()=>{});
state.hadInitPlayer = false;
}
return { ...state }
}
};
export const timepickerComponent = {
template: `
`,
props: {
modelValue: {
type: String,
default: "00:00"
}
},
setup(props,context){
const timepicker = ref(null);
const { modelValue } = toRefs(props);
watch(modelValue,()=>{
$(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: ``,
props: ['modelValue','direct'],
components: {
"sketch-picker": defineAsyncComponent(() => {
return import('../plugins/vueColor/vue3.color.esm.js').then(module => {
const { Sketch } = module;
return Sketch;
})
}),
},
directives: {
"click-outside": clickOutsideDirective
},
setup(props,context){
const state = {
picker: ref(null),
popper: ref(null),
pickerColor: ref(""),
sketchColor: ref(""),
partyPopper: {},
popperOptions: reactive({}),
}
watch(state.sketchColor,()=>{
if(state.sketchColor.value.hasOwnProperty("hex")) {
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,
{ name: 'eventListeners', enabled: true },
],
}));
state.partyPopper.update();
}
const hidePopper = () => {
if(Object.keys(state.partyPopper).length > 0) {
state.popper.value.removeAttribute('data-show');
state.partyPopper.setOptions((options) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
}
}
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);
})
onMounted(()=>{
// state.pickerColor.value = props.modelValue;
state.sketchColor.value = {'hex':props.modelValue};
});
return {...state,clickOutside,pickerColorChange}
}
};
export const uploadModalComponent = {
template: ``,
props:['modalTitle','modalShow','modalFade','uploadTip',"uploadAction",'uploadAllow','uploadCount'],
setup(props,context) {
const { modalShow,modalFade } = toRefs(props);
const state = {
modal : ref(null),
modalTitle : ref(""),
uploadFile: ref(null),
uploadTip: "",
show : false,
bsModal : {},
uploadLang: "zh"
}
watch(modalShow,()=>{
state.show = !state.show;
if(state.show)
state.bsModal.show();
else
state.bsModal.hide();
})
const initBsModal = () => {
state.bsModal = new bootstrap.Modal(state.modal.value);
if(modalShow.value) {
state.bsModal.show();
state.show = true;
} else {
state.bsModal.hide();
state.show = false;
}
state.modal.value.addEventListener('hide.bs.modal',() => {
state.show = false;
context.emit('update:modelShow', false);
});
}
const updateLangText = () => {
const html = document.querySelector('html');
let lang = html.getAttribute('data-bs-language');
const [tip1,tip2] = props.uploadTip.split("&");
if(lang === "cn" || tip2 === undefined)
state.uploadTip = tip1;
else
state.uploadTip = tip2;
const [title1,title2] = props.modalTitle.split("&");
if(lang === "cn" || title2 === undefined)
state.modalTitle.value = title1;
else
state.modalTitle.value = title2;
state.uploadLang = lang;
if(lang === "cn")
state.uploadLang = "zh";
}
const initUploadFile = () => {
$(state.uploadFile.value).fileinput({
language: state.uploadLang,
theme: "fa6",
dropZoneTitle: state.uploadTip,
showClose: false,
browseClass:"btn btn-primary btn-df",
allowedFileExtensions: eval('('+props.uploadAllow+')'),
uploadUrl: props.uploadAction,
maxFileCount: isNaN(Number(props.uploadCount)) ? 1 : Number(props.uploadCount)
});
$(state.uploadFile.value).on('fileuploaded', function(event, data) {
state.bsModal.hide();
state.show = false;
$(state.uploadFile.value).fileinput('clear');
context.emit("upload-success",data)
});
$(state.uploadFile.value).on('fileuploaderror', function(event, data, msg) {
if(data.jqXHR.responseText) {
var errMsg = eval(data.jqXHR.responseText);
context.emit("upload-error",errMsg);
}
});
}
onMounted(()=>{
const html = document.querySelector('html');
html.addEventListener("loaded",()=>{
updateLangText();
initBsModal();
initUploadFile();
})
})
return { ...state,modalFade }
}
}
export const upgradeModalComponent = {
template: `
Tip:级别标记为重要的升级包不能跳过,更新之后才能继续更新。
Tip:Upgrade packages marked as impact cannot be skipped and can only be updated after they have been updated
`,
props:['modalShow','modalFade','checkUpgrade','patchSn'],
setup(props,context) {
const { modalFade,checkUpgrade,patchSn } = toRefs(props);
const state = {
modal: ref(null),
checkUpgrade: ref(false),
systemPatchs:reactive([]),
showLog:ref(false),
showLogPatch:ref({}),
hadUpdate:ref(false),
updatePercent:ref(0),
upgradePatch:ref({}),
facAliase:"",
bsModal: {},
}
watchEffect(async ()=>{
if(checkUpgrade.value) {
let result = await func("/upgrade/checkHelpNet");
if (result.status === "error") {
alertMsg(result.msg, "error");
return;
}
if(!patchSn.value) {
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("已经是最新版本It is the latest version", "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("已经是最新版本It is the latest version", "success");
context.emit('update:checkUpgrade', false);
return;
}
state.systemPatchs.splice(0);
state.systemPatchs.push(...result.data);
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: '注意Tip',
content: '设备可能升级过其他固件,如果继续升级,功能可能会被覆盖,是否继续?The device may have been upgraded with custom firmware, and the upgrade function may be overwritten. Do you want to continue?',
buttons: {
ok: {
text: "继续Continue",
btnClass: 'btn-primary',
keys: ['enter'],
action: () => {
state.bsModal.show();
}
},
cancel: {
text: "取消Cancel",
action: ()=>{
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("无效固件编号Invalid upgrade sn", "error");
context.emit('update:checkUpgrade', false);
return;
}
state.facAliase = result.data[0].aliase;
result = await func("/upgrade/getSystemPatchBySn",{"sn": patchSn.value});
if (result.data.length === 0) {
alertMsg("无效固件编号Invalid upgrade sn", "error");
context.emit('update:checkUpgrade', false);
return;
}
state.systemPatchs.splice(0);
state.systemPatchs.push(...result.data);
state.bsModal.show();
}
}
})
const handleVersionLogs = computed(()=>{
const regex = /[\r\n\t]/g;
state.showLogPatch.value.description = state.showLogPatch.value.description.replace(regex,"");
return state.showLogPatch.value.description.split(";").filter((item)=>{
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 => {
if(state.hadUpdate.value)
return;
state.upgradePatch.value = state.systemPatchs[idx];
const patch = state.systemPatchs[idx];
const chip = patch.chip;
let name = patch.name;
let type = "update";
if(name.indexOf("_sn_") > 0) {
name = name.replace("_sn_","_"+state.facAliase+"_");
type = "sn";
} else {
name = name.replace("_","_"+state.facAliase+"_");
type = "update";
}
const params = {
action:"update", name:name,
chip:chip, type:type
}
axios_post('/link/upgrade.php', params)
.then(async data => {
const total = Number(data.size);
state.hadUpdate.value = true;
state.updatePercent.value = 0;
if(total > 0) {
const timerId = setInterval(async function () {
const size = await getUpdateFileSize(name);
state.updatePercent.value = parseInt(size/total * 100);
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";
if(name.indexOf("_sn_") > 0) {
name = name.replace("_sn_","_"+state.facAliase+"_");
type = "sn";
} else {
name = name.replace("_","_"+state.facAliase+"_");
type = "update";
}
const params = {
action:"download", name:name,
chip:chip, type:type
}
// const fileName = name;
// axios_post('/link/upgrade.php',params, { responseType: 'arraybuffer' })
// .then(data => {
// const blob = new Blob([data], { type: 'application/octet-stream' });
// const url = URL.createObjectURL(blob);
// const a = document.createElement('a');
// a.href = url;
// a.download = fileName;
// document.body.appendChild(a);
// a.click();
// document.body.removeChild(a);
// URL.revokeObjectURL(url);
// })
const url = "http://help.linkpi.cn:5735/upgrade/"+chip+"/"+type+"/"+name;
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);
}
onMounted(()=>{
state.bsModal = new bootstrap.Modal(state.modal.value);
state.modal.value.addEventListener('hide.bs.modal',() => {
context.emit('update:modelShow', false);
context.emit('update:checkUpgrade', false);
});
})
return { ...state,modalFade,handleVersionLogs,showPatchVersionLog,hidePatchVersionLog,handleUpdatePatch,handleDownloadPatch }
}
}
export const customModalComponent = {
template: ``,
props: {
modalSize: {
type: String,
default: ""
},
hadHeader: {
type: Boolean,
default: true
},
hadFooter: {
type: Boolean,
default: true
},
modalTitle: {
type:String,
default: "标题"
},
modalShow: {
type: Boolean,
default: false
},
modalFade: {
type: Boolean,
default: true
},
bodyClass: {
type: String,
default: ""
},
contentClass: {
type: String,
default: ""
},
confirmBtnName: {
type: String,
default:"确定"
},
cancelBtnName: {
type: String,
default:"取消"
},
hadConfirmBtn: {
type: Boolean,
default: true
},
cancelCloseModal:{
type: Boolean,
default: true
}
},
setup(props,context) {
const { modalShow,modalFade,modalTitle } = toRefs(props);
const state = {
modal: ref(null),
modalTitle: ref(""),
modalConfirmBtnName:ref("确定"),
modalCancelBtnName:ref("取消"),
show: false,
bsModal: {},
}
watch(modalShow,() => {
state.show = !state.show;
if(state.show)
state.bsModal.show();
else
state.bsModal.hide();
context.emit('modal-visible', state.show);
})
watch(modalTitle,() => {
updateLangText();
})
const initBsModal = () => {
state.bsModal = new bootstrap.Modal(state.modal.value);
if(modalShow.value) {
state.bsModal.show();
state.show = true;
} else {
state.bsModal.hide();
state.show = false;
}
context.emit('modal-visible', state.show);
state.modal.value.addEventListener('hide.bs.modal',() => {
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');
if(props.modalTitle !== undefined) {
const [title1,title2] = props.modalTitle.split("&");
if(lang === "cn" || title2 === undefined)
state.modalTitle.value = title1;
else
state.modalTitle.value = title2;
}
if(props.confirmBtnName !== undefined) {
const [name1,name2] = props.confirmBtnName.split("&");
if(lang === "cn" || name2 === undefined)
state.modalConfirmBtnName.value = name1;
else
state.modalConfirmBtnName.value = name2;
}
if(props.cancelBtnName !== undefined) {
const [name1,name2] = props.cancelBtnName.split("&");
if(lang === "cn" || name2 === undefined)
state.modalCancelBtnName.value = name1;
else
state.modalCancelBtnName.value = name2;
}
}
onMounted(()=>{
const html = document.querySelector('html');
html.addEventListener("loaded",()=>{
updateLangText();
initBsModal();
})
const observer = new mutationObserver(() => {
updateLangText();
});
const config = {
attributes: true,
attributeFilter: ["data-bs-language"],
subtree: false
};
observer.observe(html, config);
})
return { ...state,modalFade,confirmBtnClick,cancelBtnClick }
}
}
export const loadingButtonComponent = {
template: ``,
props:['customClass','hadLoading'],
setup(props,context) {
const { hadLoading } = toRefs(props);
const onButtonClick = () => {
context.emit("button-click","click")
}
return { hadLoading,onButtonClick }
}
}
export const ptzDirectComponent = {
template: ``,
props: {
arrowClass: {
type: String,
default: "",
},
homeClass: {
type: String,
default: "",
},
gop: {
type: Number,
default: 5
},
sticks: {
type: Array,
default: ['left', 'left-up', 'up', 'right-up', 'right', 'right-down', 'down', 'left-down','home']
},
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
}
},
components:{
"noui-slider": nouiSliderComponent
},
setup(props,context) {
const state = {
zoom: ref(0),
presetVal: ref(0)
}
watch(()=>props.zoomVal,(newValue,oldValue) => {
console.log(newValue);
state.zoom.value = newValue;
})
const handlePtzMove = type => {
context.emit("ptz-move",type)
}
const updatePreset = val => {
state.presetVal.value = val;
}
const onTouchSlideEnd = val => {
context.emit('zoom-change', val);
}
const handleCallPreset = () => {
context.emit('call-preset',state.presetVal.value);
}
const handleSetPreset = () => {
context.emit('set-preset',state.presetVal.value);
}
return { ...state,handlePtzMove,onTouchSlideEnd,updatePreset,handleCallPreset,handleSetPreset }
}
}
export const usbOptionComponent = {
template:`
`,
setup(props,context) {
const hadMountInfo = reactive({});
const hadMountDisk = ref(false);
const { diskConf,handleDiskConf,updateDiskConf } = useDiskConf();
const unInstallDisk = () => {
confirm({
title: '卸载磁盘UnInstall Disk',
content: '是否卸载磁盘,请确保没有处于录制状态Whether to uninstall the disk, please make sure it is not in the recording state',
buttons: {
ok: {
text: "卸载Confirm",
btnClass: 'btn-primary',
action: () => {
func("/system/umountDisk").then(res => {
alertMsg(res.msg,res.status);
})
}
},
cancel: {
text: "取消Cancel",
action: () => {}
}
}
});
}
const formatDisk = () => {
confirm({
title: '格式化磁盘Formatted Disk',
content: `
`,
buttons: {
ok: {
text: "格式化Format",
btnClass: 'btn-primary',
action: () => {
const formatPasswd = document.querySelector("#formatPasswd").value;
func("/system/formatReady",{"psd":formatPasswd}).then (res => {
return new Promise((resolve,reject)=>{
if(res.status === "error") {
alertMsg(res.msg,res.status);
reject();
return;
}
resolve();
})
}).then(()=>{
const diskFormat = document.querySelector("#diskFormat").value;
const notify = alertMsg("正在格式化,请勿关闭此页面Do not close this page while formatting","success",99999999);
func("/system/formatDisk",{"format":diskFormat});
let interval = setInterval(()=>{
func("/system/checkFormatProgress").then(res => {
if(res.data === 0) {
clearInterval(interval);
notify.remove();
setTimeout(()=> alertMsg(res.msg,res.status),600);
}
})
},5000);
})
}
},
cancel: {
text: "取消Cancel",
action: () => {}
}
}
});
}
const checkMountDisk = () => {
func("/system/getMountDiskSpace").then(res => {
Object.assign(hadMountInfo,res.data);
hadMountDisk.value = (res.status === "success");
})
setTimeout(checkMountDisk,1000);
}
const turnMountDisk = () => {
const html = document.querySelector("html");
const lang = html.getAttribute("data-bs-language");
const jc = confirm({
title: '磁盘挂载Mount Disk',
content: `
`,
buttons: {
ok: {
text: "挂载Mount",
btnClass: 'btn-primary',
action: () => {
updateDiskConf({
enable: true,
used: document.querySelector('#mount_device').value,
shared: {
ip:document.querySelector('#shared_ip').value,
type: document.querySelector('#shared_protocol').value,
path: document.querySelector('#shared_path').value,
auth : {
uname: document.querySelector('#shared_uname').value,
passwd: document.querySelector('#shared_passwd').value,
}
},
local: {
device:document.querySelector('#local_devices').value
}
}).then(async ()=> {
handleDiskConf();
alertMsg("磁盘检测中,请稍后...Disk checking, please wait...","success");
const result = await func("/system/mountDisk");
if(result.status === "success")
jc.close();
setTimeout(() => alertMsg(result.msg,result.status),600);
});
return false;
}
},
cancel: {
text: "取消Cancel",
action: () => {}
}
},
onOpenBefore: ()=> {
const display = (type,protocol) => {
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');
if(type === "shared") {
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');
if(protocol === 'cifs')
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;
if(item.name === "/dev/mmcblk0p6") {
if(lang === "cn")
item.name = "内部存储";
else
item.name = "device storage";
}
option.text = item.name+"( "+item.size+" )";
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;
display(diskConf.used,diskConf.shared.type);
document.querySelector('#mount_device').addEventListener('change', () => {
const type = document.querySelector('#mount_device').value;
display(type,"cifs");
});
document.querySelector('#shared_protocol').addEventListener('change', () => {
const protocol = document.querySelector('#shared_protocol').value;
display("shared",protocol);
});
}
});
}
onMounted(checkMountDisk);
return { hadMountInfo,hadMountDisk, diskConf,unInstallDisk,formatDisk,turnMountDisk }
}
}