Commit 00e7d150 by 潘建波

1.修改flv播放控件到fl.js

2.完成博关算法配置
1 parent 5454a14c
.DS_Store
node_modules
/dist
dist
dist.*
dist.*.*
# local env files
.env.local
.env.*.local
......
This file is too large to display.
No preview for this file type
No preview for this file type
......@@ -17,6 +17,7 @@
"core-js": "^3.3.2",
"echarts": "^4.5.0",
"element-ui": "^2.12.0",
"flv.js": "^1.5.0",
"js-sha1": "^0.6.0",
"moment": "^2.24.0",
"ol": "^6.1.1",
......@@ -43,6 +44,7 @@
"eslint": "^5.16.0",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-vue": "^5.0.0",
"fabric": "^4.4.0",
"generate-asset-webpack-plugin": "^0.3.0",
"node-sass": "^4.12.0",
"prettier": "^1.18.2",
......
{"commit":"226e28357cc713ecc9f9cf3535515e003387c606","commitDate":"2021-2-23 18:45","buildDate":"2021-4-23 11:7","version":"2.1.0","info":"feat✨ 设备树搜索改为服务端搜索"}
\ No newline at end of file
{"commit":"5454a14cc08221039f6a0eb3af9e4064cd8dded4","commitDate":"2021-4-23 11:9","buildDate":"2021-5-11 10:38","version":"2.0.9","info":"feat✨ chrome视频播放"}
\ No newline at end of file
......@@ -15,9 +15,9 @@ export default {
this.$store.dispatch("GetMenuRole", menus).then(res => {});
}
let token = localStorage.getItem("atoken");
if (!token) {
this.$router.push("/login").catch(err => {err});
}
// if (!token) {
// this.$router.push("/").catch(err => {err});
// }
},
mounted() {
window.videoEquitTableHeight = document.body.clientHeight - 142 + "px";
......
......@@ -14,15 +14,15 @@ let flvIP = "";
switch (process.env.NODE_ENV) {
case "development":
wsIP = window.config.https?"192.168.9.227:20070":"192.168.9.233:20080"; // 测试环境url
flvIP = window.config.https?"192.168.9.245:8080":"192.168.9.245:8080";
flvIP = window.config.https?"192.168.9.233:8080":"192.168.9.233:8080";
break;
case "pre":
wsIP = ""; // 预上线环境url
break;
case "production":
wsIP = location.host; // 生产环境url
flvIP = "192.168.9.245" + ":8080"
// flvIP = location.hostname + ":8080"
// flvIP = "192.168.9.245" + ":8080"
flvIP = location.hostname + ":38080"
break;
}
export default {
......
......@@ -12,7 +12,6 @@ switch (process.env.NODE_ENV) {
baseUrl = "https://pre-server.feleti.cn"; // 预上线环境url
break;
case "production":
baseUrl = window.config.https?`https://${location.host}`:`http://${location.host}`; // 生产环境url
break;
}
......
......@@ -217,7 +217,24 @@ Vue.prototype.showLocalTime = function(obj) {
}
return time;
};
/**
*
* @param {*} key
* @param {*} val
*/
Vue.prototype.uuid = function() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
/**
* 本地存储相机信息
*/
......
......@@ -322,10 +322,22 @@ a:active{
.video-box .el-radio-button{
display: block;
}
.video-box .safebox .el-radio-button{
display: inline-block;
}
.editbtn .el-radio-button:first-child .el-radio-button__inner{
border:0;
}
.b-box .el-radio-button{
display: inline-block!important;
}
.b-box .el-checkbox.is-bordered+.el-checkbox.is-bordered{
margin-left: 0;
}
.b-box .el-checkbox {
margin-right: 7px;
}
/* 抓拍展示 */
.pic-box {
width: 98%;
......@@ -647,4 +659,12 @@ a:active{
}
.displaybtn-box .playIcon{
font-size: 15px;
}
//@at-root
.b-box .el-checkbox__input.is-disabled+span.el-checkbox__label{
color: #2d8cf0;
}
.b-box .el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{
border-color: #2d8cf0;
}
\ No newline at end of file
......@@ -7,7 +7,7 @@ import router from "./router";
import store from "./store";
import resetCss from "./assets/resetElementCss/index.scss";
import api from "./api/install";
import log from "./api/log"
import log from "./api/log";
import "./assets/css/public.css";
import echarts from "echarts";
import "./assets/icon/icon/iconfont.css";
......
<template>
<div id="login" :style="{ height: innerHeight + 'px' }" class="js-count-particles" >
<div class="ddclosebtn"><span class="el-icon-close" @click="closedd" v-if="isdd" v-show="showdd"></span></div>
<div
id="login"
:style="{ height: innerHeight + 'px' }"
class="js-count-particles"
>
<div class="ddclosebtn">
<span
class="el-icon-close"
@click="closedd"
v-if="isdd"
v-show="showdd"
></span>
</div>
<!-- ie空白解决方法https://blog.csdn.net/heyNewbie/article/details/99623550 -->
<!-- <vue-particles
color="#dedede"
......@@ -22,7 +33,7 @@
</vue-particles> -->
<div class="box">
<h1>AI视频分析平台</h1>
<div style="width: 60%;margin: 0 auto;">
<div style="width: 60%; margin: 0 auto">
<el-form
:model="ruleForm"
:rules="rules"
......@@ -50,9 +61,9 @@
</el-form-item>
</el-form>
<div class="ddbox" v-show="isdd">
<img class="ddimg" src="../assets/img/login/dd@2x.png" alt="">
<img class="ddimg" src="../assets/img/login/dd@2x.png" alt="" />
<span class="title" @click="switchLogin">钉钉登录</span>
</div>
</div>
<div class="syversion">版本:v{{ versioninfo.version }}</div>
</div>
</div>
......@@ -62,7 +73,7 @@
<script>
let particlesConfig = require("../assets/js/particles.json");
let versioninfo = require("../../public/js/version");
import {config} from "../../public/js/config";
import { config } from "../../public/js/config";
import types from "../store/types.js";
export default {
name: "Login",
......@@ -84,27 +95,27 @@ export default {
return {
username: "",
password: "",
showdd:true,
showdd: true,
innerHeight: 0,
logintitle:"",
isdd:window.config.isdd,
webSocketL:null,
ddWindow:null,
logintitle: "",
isdd: window.config.isdd,
webSocketL: null,
ddWindow: null,
ruleForm: {
username: "",
password: ""
password: "",
},
ddurl:`${window.config.ddurl}/oauth/authorize?response_type=code&scope=read&client_id=KLjmdAH0&redirect_uri=${window.config.ddloginurl}/api/v1/huasan/code/call`,
ddurl: `${window.config.ddurl}/oauth/authorize?response_type=code&scope=read&client_id=KLjmdAH0&redirect_uri=${window.config.ddloginurl}/api/v1/huasan/code/call`,
versioninfo: versioninfo,
rules: {
password: [{ validator: validatePass, trigger: "change" }],
username: [{ validator: validateUser, trigger: "change" }]
}
username: [{ validator: validateUser, trigger: "change" }],
},
};
},
methods: {
submitForm(formName) {
this.$refs[formName].validate(valid => {
this.$refs[formName].validate((valid) => {
if (valid) {
this.login();
} else {
......@@ -112,7 +123,7 @@ export default {
}
});
},
closedd(){
closedd() {
this.showdd = false;
},
initHeight() {
......@@ -124,50 +135,50 @@ export default {
username: this.ruleForm.username,
password: this.baseencode(this.ruleForm.password),
// password: this.ruleForm.password,
user_type: "user"
user_type: "user",
})
.then(res => {
.then((res) => {
if (!res.ecode) {
this.loginMount(res,"user")
this.loginMount(res, "user");
} else {
this.$message({
type: "error",
message: res.enote
message: res.enote,
});
}
})
.catch(err => {
this.$message({
this.$message({
type: "error",
message: err
message: err,
});
});
},
loginMount(res,logintype){
this.$store.commit(types.ATOKEN, res.atoken);
// localStorage.setItem('rtoken',m.data.rtoken)
sessionStorage.setItem("user_unid", res.user_unid);
//本系统可以直接用本地缓存做
localStorage.setItem("atoken", res.atoken);
localStorage.setItem("uname", res.user_name);
this.$logs.oplogs(res.user_name,'serv_login',`登录了平台`);
localStorage.setItem("access_token",res.access_token || '')
// 处理登录用户权限菜单显示问题;
// if(res.firstLogin && logintype !== "dingding") {
// this.$router.push('resetpass')
// return;
// }
//算法配置列表
this.algoList();
//存储配置列表
this.storeConfList();
//code列表
this.getCatesList();
this.getCodeList();
this.getCustomCode();
this.getEventList();
this.getDev();
this.getMenu(res.user_unid);
loginMount(res, logintype) {
this.$store.commit(types.ATOKEN, res.atoken);
// localStorage.setItem('rtoken',m.data.rtoken)
sessionStorage.setItem("user_unid", res.user_unid);
//本系统可以直接用本地缓存做
localStorage.setItem("atoken", res.atoken);
localStorage.setItem("uname", res.user_name);
this.$logs.oplogs(res.user_name, "serv_login", `登录了平台`);
localStorage.setItem("access_token", res.access_token || "");
// 处理登录用户权限菜单显示问题;
// if(res.firstLogin && logintype !== "dingding") {
// this.$router.push('resetpass')
// return;
// }
//算法配置列表
this.algoList();
//存储配置列表
this.storeConfList();
//code列表
this.getCatesList();
this.getCodeList();
this.getCustomCode();
this.getEventList();
this.getDev();
this.getMenu(res.user_unid);
},
getMenu(id) {
//获取菜单
......@@ -175,7 +186,7 @@ export default {
.getMenus({
shape: "tree"
})
.then(res => {
.then( res => {
localStorage.setItem(
"menu",
JSON.stringify(res.menu_tree[0].children)
......@@ -183,8 +194,11 @@ export default {
this.$store
.dispatch("GetMenuRole", res.menu_tree[0].children)
.then(r => {
this.$router.push(res.menu_tree[0].children[0].children[0].path).catch(err => {err});
this.$router
.push(res.menu_tree[0].children[0].children[0].path)
.catch(err => {
err;
});
});
});
},
......@@ -217,35 +231,35 @@ export default {
getCodeList() {
this.$api.codes
.cates()
.then(res => {
res.list_data.forEach(item => {
.then((res) => {
res.list_data.forEach((item) => {
this.$api.codes
.codes({active:true}, item.cate_unid)
.then(res => {
.codes({ active: true }, item.cate_unid)
.then((res) => {
// 存储code列表
window.localStorage.setItem(
item.name,
JSON.stringify(res.list_data)
);
// 存储单独code
res.list_data.forEach(chilItem => {
res.list_data.forEach((chilItem) => {
window.localStorage.setItem(
item.name + "-" + chilItem.code,
chilItem.name
);
});
})
.catch(err => {});
.catch((err) => {});
});
})
.catch(err => {});
.catch((err) => {});
},
getCustomCode() {
this.$api.codes
.customCode()
.then(res => {
.then((res) => {
if (res.list_data.length > 0) {
res.list_data.forEach(item => {
res.list_data.forEach((item) => {
window.localStorage.setItem(
item.name + "-" + item.cate,
item.unid
......@@ -254,41 +268,41 @@ export default {
} else {
this.$message({
type: "warning",
message: "获取自定义编码失败!"
message: "获取自定义编码失败!",
});
}
})
.catch(err => {});
.catch((err) => {});
},
getCatesList() {
this.$api.codes.eventCates({}).then(res => {
this.$api.codes.eventCates({}).then((res) => {
// 存储cate列表
window.localStorage.setItem("cate列表", JSON.stringify(res.list_data));
// 存储单独code
res.list_data.forEach(item => {
res.list_data.forEach((item) => {
this.getOneEventList(item.code, item.event_cate_unid);
});
});
},
switchLogin(){},
switchLogin() {},
getOneEventList(code, id) {
this.$api.codes.eventType({}, id).then(res => {
this.$api.codes.eventType({}, id).then((res) => {
// 存储cate列表
window.localStorage.setItem(code, JSON.stringify(res.list_data));
});
},
getEventList() {
this.$api.search.eventTypes({active:true}).then(res => {
this.$api.search.eventTypes({ active: true }).then((res) => {
// 存储code列表
window.localStorage.setItem("安防事件", JSON.stringify(res.list_data));
// 存储单独code
res.list_data.forEach(item => {
res.list_data.forEach((item) => {
window.localStorage.setItem("安防事件-" + item.code, item.name);
});
});
},
getDev() {
this.$api.resource.devs().then(res => {
this.$api.resource.devs().then((res) => {
localStorage.setItem("dev_unid", res[0].dev_unid);
this.getDevsName(res[0].dev_unid);
});
......@@ -297,20 +311,20 @@ export default {
this.$api.resource
.getDevsName(
{
is_leaf: 0
is_leaf: 0,
},
id
)
.then(res => {
.then((res) => {
if (res.list_data.length > 0) {
sessionStorage.setItem("device_id", res.list_data[0].device_id);
}
});
}
},
},
watch: {},
mounted() {
particlesJS('login',particlesConfig);
particlesJS("login", particlesConfig);
document.body.style.overflow = "hidden";
},
created() {
......@@ -318,19 +332,19 @@ export default {
this.initHeight();
// this.isdd? this.switchLogin():null;
let _this = this;
document.onkeydown = function(e) {
document.onkeydown = function (e) {
let _key = window.event.keyCode;
if (_key === 13) {
_this.submitForm("ruleForm");
}
};
}
},
};
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="scss">
#login{
#login {
width: 100%;
height: 100%;
background-color: #e76392;
......@@ -371,7 +385,7 @@ export default {
font-size: 18px;
font-family: "隶书";
}
.box .title{
.box .title {
line-height: 50px;
}
.loginTitle > div span:last-child {
......@@ -403,7 +417,6 @@ h1 {
box-shadow: none;
}
.box {
width: 25%;
position: absolute;
......@@ -450,7 +463,7 @@ p:nth-child(1) {
}
.ddbox {
margin-top: -10px;
.ddimg{
.ddimg {
height: 20px;
width: 20px;
vertical-align: middle;
......@@ -462,18 +475,18 @@ p:nth-child(1) {
font-size: 14px;
}
}
.ddiframe{
.ddiframe {
position: relative;
height: 100%;
width: 100%;
z-index: 1000;
}
.ddclosebtn{
.ddclosebtn {
position: absolute;
right: 20px;
top: 10px;
color: #ccc;
z-index:10001;
z-index: 10001;
cursor: pointer;
}
</style>
......@@ -14,7 +14,7 @@ export default {
let host = `http://${location.host}`;
this.ddLoginUrl = `${
window.config.huasanDD
}&redirect_uri=${`${ window.config.host}/#/ddlogin`}`;
}&redirect_uri=${`${window.config.host}/#/ddlogin`}`;
this.switchLogin();
},
mounted() {},
......@@ -36,7 +36,6 @@ export default {
}, 200);
},
getLoginInfo(code) {
this.$api.login.ddlogin({"code":code.split("=")[1]}).then(res => {
if (res.code == 200) {
this.loginMount(res.data);
......
......@@ -417,9 +417,11 @@ export default {
} else {
return false;
}
});
},
editFun(formName) {
this.$refs[formName].validate(valid => {
if (valid) {
this.$api.ops
......
<template>
<div class="ocxbox">
<canvas id="video1" style="width:100%;height:100%;" class="fvideo"></canvas>
<video id="flvvideo" autoplay style="width: 100%; height: 100%" class="fvideo"></video>
<div class="control" hidden>
<span :class="{'videostatus':true,'el-icon-video-play':videostatus,'el-icon-video-pause':!videostatus }" @click="controlvideo"></span>
<span
:class="{
videostatus: true,
'el-icon-video-play': videostatus,
'el-icon-video-pause': !videostatus,
}"
@click="controlvideo"
></span>
<!-- <span :class="{'el-icon-full-screen':!furllstatus,'el-icon-circle-close':furllstatus,'videostatus':true, 'full-icon':true}" @click="fullvideo" id="full"></span> -->
</div>
</div>
</template>
<script>
var player;
import flv from "flv.js";
export default {
data() {
return {
show: true,
videostatus:false,
furllstatus:false
videostatus: false,
furllstatus: false,
player: "",
};
},
computed: {},
methods: {
controlvideo() {
this.videostatus = !this.videostatus
if(!this.videostatus) {
this.startFunc()
} else {
this.stopFunc()
initflv() {
if (flv.isSupported()) {
this.player = flv.createPlayer({
type: "flv",
});
}
},
fullvideo(ev){
if(!this.furllstatus){
this.furllstatus = true;
this.fullel();
} else {
this.furllstatus = false;
this.exitFullscreen();
}
},
fullel(){
var ele = document.getElementById("full")
if (ele.requestFullscreen) {
ele.requestFullscreen();
} else if (ele.mozRequestFullScreen) {
ele.mozRequestFullScreen();
} else if (ele.webkitRequestFullScreen) {
ele.webkitRequestFullScreen();
}
},
exitFullscreen(){
var de = document
if (de.exitFullscreen) {
de.exitFullscreen();
} else if (de.mozCancelFullScreen) {
de.mozCancelFullScreen();
} else if (de.webkitCancelFullScreen) {
de.webkitCancelFullScreen();
}
},
startFunc(url) {
this.stopFunc()
/**
* 设置解密密码,必须是16字节
*/
player.setCryptoKey("");
/**
* 开始播放,参数为 http-flv或 websocket-flv 的url
*/
player.start(url);
},
stopFunc() {
/**
* 停止播放
*/
player.stop();
let playerel = document.getElementById("flvvideo");
// if (typeof player !== "undefined") {
// if (this.player != null) {
// // this.player.unload();
// // this.player.detachMediaElement();
// // this.player.destroy();
// // this.player = null;
// this.flv_destroy();
// }
// }
this.player = flv.createPlayer({
type: "flv",
isLive: true,
hasAudio: false,
url: url,
});
this.player.attachMediaElement(playerel);
this.player.load();
this.player.play();
},
fullFunc() {
/**
* 全屏播放
*/
player.fullscreen();
flv_start() {
this.player.play();
},
volumeChange(event) {
/**
* 设置音量
* 0.0 ~~ 1.0
* 当为0.0时,完全静音, 最大1.0
*/
player.setVolume(event.target.value / 100.0);
flv_pause() {
this.player.pause();
},
bufferChange(event) {
player.setBufferTime(event.target.value);
flv_destroy() {
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.player.destroy();
this.player = null;
},
scaleModeChange(event) {
/**
* 视频缩放模式, 当视频分辨率比例与Canvas显示区域比例不同时,缩放效果不同:
* 0 视频画面完全填充canvas区域,画面会被拉伸 --- 默认值
* 1 视频画面做等比缩放后,对齐Canvas区域,画面不被拉伸,但有黑边
* 2 视频画面做等比缩放后,完全填充Canvas区域,画面不被拉伸,没有黑边,但画面显示不全
* 软解时有效
*/
player.setScaleMode(event.target.value);
}
},
mounted() {
NodePlayer.load(() => {
/**
* 是否打印debug信息
*/
// NodePlayer.debug(true);
player = new NodePlayer();
/**
* 自动测试浏览器是否支持MSE播放,如不支持,仍然使用软解码。
* 紧随 new 后调用
* 不调用则只使用软解
*/
//player.useMSE();
/**
* 传入 canvas视图的id,当使用mse时,自动转换为video标签
*/
player.setView("video1");
/**
* 是否开启屏幕常亮
* 在手机浏览器上,canvas标签渲染视频并不会像video标签那样保持屏幕常亮
* 如果需要该功能, 可以调用此方法, 会有少量cpu消耗, pc浏览器不会执行
*/
player.setKeepScreenOn();
/**
* 设置为等比缩放模式
*/
player.setScaleMode(1);
/**
* 设置最大缓冲时长,单位毫秒,只在软解时有效
*/
player.setBufferTime(1000);
player.on("start", () => {
console.log("player on start");
});
player.on("stop", () => {
console.log("player on stop");
});
player.on("error", e => {
console.log("player on error", e);
});
player.on("videoInfo", (w, h) => {
console.log("player on video info width=" + w + " height=" + h);
});
player.on("audioInfo", (r, c) => {
console.log("player on audio info samplerate=" + r + " channels=" + c);
});
player.on("stats", stats => {
// console.log("player on stats=", stats);
});
player.on("metadata", metadata => {
var m = NodePlayer.AMF.parseScriptData(
metadata.buffer,
0,
metadata.length
);
console.log(m);
});
});
}
mounted() {},
};
</script>
<style lang="stylus">
......@@ -197,7 +88,8 @@ export default {
height: 40px;
width: 100%;
background: rgba(255, 255, 255, 0.2);
display none
display: none;
.videostatus {
cursor: pointer;
color: #fff;
......@@ -205,18 +97,19 @@ export default {
line-height: 40px;
padding-left: 10px;
}
.full-icon{
float right
margin-right 20px
font-size 25px
.full-icon {
float: right;
margin-right: 20px;
font-size: 25px;
}
}
}
.ocxbox:hover {
.control{
// display block
cursor pointer
}
.ocxbox:hover {
.control {
// display block
cursor: pointer;
}
}
</style>
<template>
<div class="ocxbox">
<canvas id="video1" style="width:100%;height:100%;" class="fvideo"></canvas>
<div class="control" hidden>
<span :class="{'videostatus':true,'el-icon-video-play':videostatus,'el-icon-video-pause':!videostatus }" @click="controlvideo"></span>
<!-- <span :class="{'el-icon-full-screen':!furllstatus,'el-icon-circle-close':furllstatus,'videostatus':true, 'full-icon':true}" @click="fullvideo" id="full"></span> -->
</div>
</div>
</template>
<script>
var player;
export default {
data() {
return {
show: true,
videostatus:false,
furllstatus:false
};
},
computed: {},
methods: {
controlvideo() {
this.videostatus = !this.videostatus
if(!this.videostatus) {
this.startFunc()
} else {
this.stopFunc()
}
},
fullvideo(ev){
if(!this.furllstatus){
this.furllstatus = true;
this.fullel();
} else {
this.furllstatus = false;
this.exitFullscreen();
}
},
fullel(){
var ele = document.getElementById("full")
if (ele.requestFullscreen) {
ele.requestFullscreen();
} else if (ele.mozRequestFullScreen) {
ele.mozRequestFullScreen();
} else if (ele.webkitRequestFullScreen) {
ele.webkitRequestFullScreen();
}
},
exitFullscreen(){
var de = document
if (de.exitFullscreen) {
de.exitFullscreen();
} else if (de.mozCancelFullScreen) {
de.mozCancelFullScreen();
} else if (de.webkitCancelFullScreen) {
de.webkitCancelFullScreen();
}
},
startFunc(url) {
this.stopFunc()
/**
* 设置解密密码,必须是16字节
*/
player.setCryptoKey("");
/**
* 开始播放,参数为 http-flv或 websocket-flv 的url
*/
player.start(url);
},
stopFunc() {
/**
* 停止播放
*/
player.stop();
},
fullFunc() {
/**
* 全屏播放
*/
player.fullscreen();
},
volumeChange(event) {
/**
* 设置音量
* 0.0 ~~ 1.0
* 当为0.0时,完全静音, 最大1.0
*/
player.setVolume(event.target.value / 100.0);
},
bufferChange(event) {
player.setBufferTime(event.target.value);
},
scaleModeChange(event) {
/**
* 视频缩放模式, 当视频分辨率比例与Canvas显示区域比例不同时,缩放效果不同:
* 0 视频画面完全填充canvas区域,画面会被拉伸 --- 默认值
* 1 视频画面做等比缩放后,对齐Canvas区域,画面不被拉伸,但有黑边
* 2 视频画面做等比缩放后,完全填充Canvas区域,画面不被拉伸,没有黑边,但画面显示不全
* 软解时有效
*/
player.setScaleMode(event.target.value);
}
},
mounted() {
NodePlayer.load(() => {
/**
* 是否打印debug信息
*/
// NodePlayer.debug(true);
player = new NodePlayer();
/**
* 自动测试浏览器是否支持MSE播放,如不支持,仍然使用软解码。
* 紧随 new 后调用
* 不调用则只使用软解
*/
//player.useMSE();
/**
* 传入 canvas视图的id,当使用mse时,自动转换为video标签
*/
player.setView("video1");
/**
* 是否开启屏幕常亮
* 在手机浏览器上,canvas标签渲染视频并不会像video标签那样保持屏幕常亮
* 如果需要该功能, 可以调用此方法, 会有少量cpu消耗, pc浏览器不会执行
*/
player.setKeepScreenOn();
/**
* 设置为等比缩放模式
*/
player.setScaleMode(1);
/**
* 设置最大缓冲时长,单位毫秒,只在软解时有效
*/
player.setBufferTime(1000);
player.on("start", () => {
console.log("player on start");
});
player.on("stop", () => {
console.log("player on stop");
});
player.on("error", e => {
console.log("player on error", e);
});
player.on("videoInfo", (w, h) => {
console.log("player on video info width=" + w + " height=" + h);
});
player.on("audioInfo", (r, c) => {
console.log("player on audio info samplerate=" + r + " channels=" + c);
});
player.on("stats", stats => {
// console.log("player on stats=", stats);
});
player.on("metadata", metadata => {
var m = NodePlayer.AMF.parseScriptData(
metadata.buffer,
0,
metadata.length
);
console.log(m);
});
});
}
};
</script>
<style lang="stylus">
.ocxbox {
height: 100%;
position: relative;
.fvideo {
height: 100%;
width: 100%;
}
.control {
position: absolute;
bottom: 0;
height: 40px;
width: 100%;
background: rgba(255, 255, 255, 0.2);
display none
.videostatus {
cursor: pointer;
color: #fff;
font-size: 30px;
line-height: 40px;
padding-left: 10px;
}
.full-icon{
float right
margin-right 20px
font-size 25px
}
}
}
.ocxbox:hover {
.control{
// display block
cursor pointer
}
}
</style>
......@@ -76,7 +76,6 @@ export default {
methods: {
handleClick(tab, event) {},
dataInit(cid, type) {
debugger
this.$refs.allalarm.allAlarmData = [];
this.$refs.caralarm.carAlarmData = [];
this.$refs.illegalalarm.illAlarmData = [];
......
......@@ -202,6 +202,10 @@ export default {
this.steam(this.subtaskdata)
},9000)
}
if(this.subtaskdata.task_algo_type == '12') {
this.playurl = {rtsp_url:this.subtaskdata.rtsp_url};
this.$refs.videoplay.videoPlay()
}
this.$api.task.getPlayUrl(this.currentSubtaskId).then(res => {
this.playurl = res;
if (this.playurl.rtsp_url) {
......
......@@ -7,7 +7,8 @@
:before-close="beforeHideModal"
>
<div>
<TraficCanvas
<Behavior :bgUrl="bgUrl" v-if="type == '12'" ref="canvas" :configxml="configxml"></Behavior>
<TraficCanvas
:bgUrl="bgUrl"
v-if="type == '0' || type == '5' || type == '3'"
ref="canvas"
......@@ -47,13 +48,14 @@ import FlowCanvas from "./areaconfig/FlowCanvas";
import SafeCanvas from "./areaconfig/SafeCanvas";
import FaceCanvas from "./areaconfig/FaceCanvas";
import ComplexCanvas from "./areaconfig/ComplexCanvas";
import Behavior from "./areaconfig/Behavior";
import {roi} from "./areaconfig/roi_1"
export default {
data() {
return {
dialogVisible: false,
isShow: false,
type: "0",
type: "9",
btnIsactive: false,
showClose: false,
roiBody: {},
......@@ -61,6 +63,7 @@ export default {
taskData: "",
bgUrl: "",
baseUrl:"",
configxml:"",
fileList:[]
};
},
......@@ -69,7 +72,8 @@ export default {
SafeCanvas,
FlowCanvas,
FaceCanvas,
ComplexCanvas
ComplexCanvas,
Behavior
},
methods: {
showModal: function(data, mtaskdata) {
......@@ -110,10 +114,11 @@ export default {
.catch(err => {
console.log("区域设置截图返回异常:", err.message);
});
this.configxml = data.config;
setTimeout(() => {
_this.$refs.canvas.stageInit();
_this.$refs.canvas.stageInit(data.config);
if (data.rois) {
_this.$refs.canvas.configInit(data.rois[0].roi);
_this.$refs.canvas.configInit(data.rois[0].roi,data.config);
// _this.$refs.canvas.configInit(roi);
}
}, 300);
......@@ -179,7 +184,7 @@ export default {
console.log(error);
}
},
save: function() {
save: function(type) {
if (this.$refs.canvas.roadFlag === false) {
this.$alert("车道线有修改,请检查车道属性是否正确", "提示", {
confirmButtonText: "确定"
......@@ -189,6 +194,7 @@ export default {
return;
}
let XMLStr = this.$refs.canvas.save();
console.log("xxx",XMLStr);
if (this.type == "1" && (XMLStr === "dir" || XMLStr === "in")) {
this.$message({
type: "warning",
......@@ -196,6 +202,11 @@ export default {
});
return;
}
if(this.type == '12') {
let XMLStr = this.$refs.canvas.paramsData;
console.log("12",XMLStr)
this.$parent.submit(XMLStr, "config");
}
this.$parent.submit(XMLStr, "roi", this.taskData);
this.beforeHideModal();
}
......
<template>
<div class="modal-body b-box">
<div class="modal-left">
<div class="pic" id="pic">
<canvas id="main" width="700" height="500"></canvas>
</div>
</div>
<div class="modal-right">
<div class="be-header">
<el-radio-group v-model="checkval" size="mini">
<el-radio-button label="shanghai">行为事件</el-radio-button>
<el-radio-button label="北京" name="shangha" disabled
>交通事件</el-radio-button
>
<el-radio-button label="广州" name="shnghai" disabled
>安防事件</el-radio-button
>
</el-radio-group>
</div>
<div class="be-content">
<div class="typebox">
<div class="checkbox" v-for="(item, index) in basconfig" :key="index">
<div
:class="{ listbox: true, curlist: cindex == index }"
@click="seltype(item, index)"
>
<el-checkbox-group v-model="checkboxGroup1" class="checkgrop">
<el-checkbox :key="item.name" :label="item.name">{{
""
}}</el-checkbox>
</el-checkbox-group>
<span class="typetext">{{ item.name }}</span>
</div>
</div>
</div>
<div class="configbox">
<div class="areabox">
<div class="area-header">检测规则</div>
<div
:class="{ 'area-item': true, activeare: item.id == curuuid }"
v-for="(item, index) in groupList"
:key="index"
@click="changeKlass(item)"
>
区域{{ index + 1 }}
</div>
<div class="bottombtn">
<!-- <el-button @click="savechange" type="primary" size="mini" style="width:90px">保存</el-button> -->
<!-- <el-button
@click="save"
type="primary"
size="mini"
style="width: 90px"
>保存</el-button> -->
</div>
</div>
<div class="setbox">
<div
v-for="(val, key, index) in citem.config"
:key="index"
class="setboxitem"
>
<span class="configlabel">{{ key }}:</span>
<span class=""
><el-input v-model="citem.config[key]"></el-input
></span>
</div>
</div>
</div>
<div class="pusbox">
<div class="label">推送地址:</div>
<div>
<el-input
v-model="pushurl"
placeholder="推送地址"
width="100"
></el-input>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { fabric } from "fabric";
import { select } from "svg.js";
import { xml } from "./bog.js";
var canvas = null;
var drawingObject = null; //当前绘制对象
var mouseFrom = {},
mouseTo = {},
drawType = "",
canvasObjectIndex = 0,
textbox = null;
var drawWidth = 2; //笔触宽度
var color = "#E34F51"; //画笔颜色
var moveCount = 1; //绘制移动计数器
var doDrawing = false; // 绘制状态
var cvselect = false;
var curObjcet = null;
var cvunselect = true;
export default {
name: "zoneSetting",
props: ["bgUrl", "configxml"],
data() {
return {
tabPosition: "top",
checkval: "shanghai",
checkboxGroup1: ["人员脱岗"],
groupList: [],
curAlgoType: "xsdsfd",
basconfig: [],
baselist: {},
cindex: 0,
citem: null,
curuuid: null,
pushurl: "",
roiBody: {},
basedocument: null,
paramsData: "",
};
},
methods: {
/**
* 初始化区域
*/
configInit(basexml, confxml) {
drawType = "rectangle";
let obj = this.oParse.parseXML(basexml).roi;
for (key in obj) {
let klassarr = [];
if (obj[key].region_count > 0) {
let polygon = obj[key].polygon;
if (obj[key].region_count == 1) {
let points = polygon.point;
mouseFrom.x = points[0].x * 700;
mouseFrom.y = points[0].y * 500;
mouseTo.x = points[2].x * 700;
mouseTo.y = points[2].y * 500;
this.drawing("init");
klassarr.push(drawingObject);
} else {
for (let i = 0; i < polygon.length; i++) {
let points = polygon[i].point;
mouseFrom.x = points[0].x * 700;
mouseFrom.y = points[0].y * 500;
mouseTo.x = points[2].x * 700;
mouseTo.y = points[2].y * 500;
this.drawing("init");
klassarr.push(drawingObject);
}
}
}
obj[key].rois = klassarr;
for (let k = 0; k < this.basconfig.length; k++) {
if (this.basconfig[k].config.算法ID === key) {
this.basconfig[k].roi = klassarr;
// this.basconfig[k].config = confobj['root']
break;
}
}
}
this.basconfig[0].roi.map((ele) => {
this.fabricObjInit(ele);
});
},
/**
* 初始化区域(
* 误删为了兼容vion的区域设置
* 该区域设置转化为参数设置
*/
stageInit(data) {
console.log("config", data);
},
getObjects(klass) {
//获取所有的列表对象
var group = canvas.getObjects();
},
setAreaconfig() {
var group = canvas.getObjects();
this.groupList = group;
},
//设置活动对象
changeKlass(klass) {
canvas.setActiveObject(klass);
canvas.requestRenderAll();
},
updateGroup() {
var group = canvas.getObjects();
this.groupList = group;
},
/**
* tab切换保存之前绘制的数据
*/
changetype(data, index) {
var group = canvas.getObjects();
var confdata = this.basconfig[this.cindex];
confdata.roi = group;
canvas.clear();
console.log(this.basconfig);
},
/**
* 回显对象
*/
fabricObjInit(klass) {
canvas.add(klass);
},
/**
* 根据选择模型定位规则
*/
selectklass(klass) {
this.curuuid = klass.id;
},
/**
* 解构算法xml
*/
initConfig(config) {
for (let key in config) {
if (key === "root") {
this.initConfig(config["root"]);
} else if (key === "算法功能") {
this.initConfig(config[key]);
} else {
this.buildUserobj(config[key], key);
}
}
},
/**
* 构建需要的数据结构
*/
buildUserobj(obj, parentkey) {
let arr = [];
for (let key in obj) {
if (key !== "结果推送地址") {
let buildobj = {
pkey: parentkey,
id: key,
name: key,
roi: null,
config: obj[key],
};
arr.push(buildobj);
} else {
this.pushurl = obj[key];
}
}
this.basconfig = arr;
this.citem = arr[0];
console.log(this.citem);
console.log("baseconfgi", this.basconfig);
},
seltype(item, cindex) {
if (this.cindex == cindex) {
return false;
}
this.citem = item;
this.changetype(item);
this.cindex = cindex;
let rois = item.roi;
if (item.roi !== "" && item.roi !== null) {
this.groupList = rois;
for (let i = 0; i < rois.length; i++) {
this.fabricObjInit(rois[i]);
}
}
},
/**
* 修改配置文件
*/
savechange() {},
/**
* 构建存储用的json
*/
save() {
//博关算法监测区域
let confArr = [],
parentname;
this.basconfig.map((ele) => {
if (ele.config["算法ID"]) {
let idname = ele.config["算法ID"];
let ROI = {
idname: "",
};
console.log(this.buildRoI(ele));
this.roiBody[idname] = this.buildRoI(ele);
// confArr.push(this.buildRoI(ele));
}
//构建参数树
parentname = ele.pkey;
let chidkey = ele.name;
let childconfig = {};
childconfig[chidkey] = ele.config;
confArr.push(childconfig);
});
this.buildParam(parentname, confArr);
return this.oParse.writeXML({ roi: this.roiBody });
},
clear() {
canvas.clear();
},
/**
* 构建ROI
*/
buildRoI(klass) {
let bg_arr = [],
pol;
let idname = klass.config["算法ID"];
if (klass.roi != null && klass.roi != "") {
klass.roi.map((ele) => {
let lines = ele.aCoords;
let point = [
{
point_seq: "1",
x: (lines.tl.x / 700).toFixed(6),
y: (lines.tl.y / 500).toFixed(6),
},
{
point_seq: "2",
x: (lines.tr.x / 700).toFixed(6),
y: (lines.tr.y / 500).toFixed(6),
},
{
point_seq: "3",
x: (lines.br.x / 700).toFixed(6),
y: (lines.br.y / 500).toFixed(6),
},
{
point_seq: "4",
x: (lines.bl.x / 700).toFixed(6),
y: (lines.bl.y / 500).toFixed(6),
},
];
let obj = {
polygon_point_count: 4,
point: point,
};
bg_arr.push(obj);
});
pol = {
region_count: klass.roi.length,
polygon: bg_arr,
};
} else {
pol = {
region_count: 0,
};
}
return pol;
},
/**
* 构建参数树
*/
buildParam(parentname, confArr) {
let paramsconfig = {
root: {
算法功能: {},
},
};
let pobj = {
结果推送地址: this.pushurl,
};
confArr.map((ele) => {
for (key in ele) {
pobj[key] = ele[key];
}
});
paramsconfig.root.算法功能[parentname] = pobj;
this.paramsData = this.oParse.writeXML(paramsconfig);
},
drawing(type) {
var vthis = this;
if (drawingObject && type == "draw") {
canvas.remove(drawingObject);
}
var canvasObject = null;
switch (drawType) {
case "arrow": //箭头
canvasObject = new fabric.Path(
drawArrow(mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y, 30, 30),
{
stroke: color,
fill: "rgba(255,255,255,0)",
strokeWidth: drawWidth,
}
);
break;
case "line": //直线
canvasObject = new fabric.Line(
[mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y],
{
stroke: color,
strokeWidth: drawWidth,
}
);
break;
case "dottedline": //虚线
canvasObject = new fabric.Line(
[mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y],
{
strokeDashArray: [3, 1],
stroke: color,
strokeWidth: drawWidth,
}
);
break;
case "circle": //正圆
var left = mouseFrom.x,
top = mouseFrom.y;
var radius =
Math.sqrt(
(mouseTo.x - left) * (mouseTo.x - left) +
(mouseTo.y - top) * (mouseTo.y - top)
) / 2;
canvasObject = new fabric.Circle({
left: left,
top: top,
stroke: color,
fill: "rgba(255, 255, 255, 0)",
radius: radius,
strokeWidth: drawWidth,
});
break;
case "ellipse": //椭圆
// eslint-disable-next-line no-redeclare
var left = mouseFrom.x,
top = mouseFrom.y;
// eslint-disable-next-line no-redeclare
var radius =
Math.sqrt(
(mouseTo.x - left) * (mouseTo.x - left) +
(mouseTo.y - top) * (mouseTo.y - top)
) / 2;
canvasObject = new fabric.Ellipse({
left: left,
top: top,
stroke: color,
fill: "rgba(255, 255, 255, 0)",
originX: "center",
originY: "center",
rx: Math.abs(left - mouseTo.x),
ry: Math.abs(top - mouseTo.y),
strokeWidth: drawWidth,
});
break;
case "square": //TODO:正方形(后期完善)
break;
case "rectangle": //长方形
// eslint-disable-next-line no-redeclare
var left = mouseFrom.x,
top = mouseFrom.y;
canvasObject = new fabric.Rect({
left: left,
top: top,
width: mouseTo.x - left, //矩形的宽度
height: mouseTo.y - top, //矩形的高度
fill: "rgba(0,0,0,.3)", //填充的颜色
stroke: "orange", // 边框原色
strokeWidth: 1, // 边框大小
});
canvasObject.on("selected", function () {
cvselect = true;
cvunselect = true;
curObjcet = canvasObject;
vthis.selectklass(canvasObject);
});
canvasObject.on("deselected", function () {
vthis.setAreaconfig();
var group = canvas.getObjects();
var confdata = vthis.basconfig[vthis.cindex];
confdata.roi = group;
cvunselect = false;
});
break;
case "rightangle": //直角三角形
var path =
"M " +
mouseFrom.x +
" " +
mouseFrom.y +
" L " +
mouseFrom.x +
" " +
mouseTo.y +
" L " +
mouseTo.x +
" " +
mouseTo.y +
" z";
canvasObject = new fabric.Path(path, {
left: left,
top: top,
stroke: color,
strokeWidth: drawWidth,
fill: "rgba(255, 255, 255, 0)",
});
break;
case "equilateral": //等边三角形
var height = mouseTo.y - mouseFrom.y;
canvasObject = new fabric.Triangle({
top: mouseFrom.y,
left: mouseFrom.x,
width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)),
height: height,
stroke: color,
strokeWidth: drawWidth,
fill: "rgba(255,255,255,0)",
});
break;
case "isosceles":
break;
case "text":
textbox = new fabric.Textbox("", {
left: mouseFrom.x - 60,
top: mouseFrom.y - 20,
width: 150,
fontSize: 18,
borderColor: "#2c2c2c",
fill: color,
hasControls: false,
});
canvas.add(textbox);
textbox.enterEditing();
textbox.hiddenTextarea.focus();
break;
case "remove":
break;
default:
break;
}
// canvasObject.index = getCanvasObjectIndex();
if (canvasObject) {
canvasObject.id = vthis.uuid();
// console.log(canvasObject);
// canvasObject.index = getCanvasObjectIndex();
if (type !== "init") {
canvas.add(canvasObject); //.setActiveObject(canvasObject)
}
drawingObject = canvasObject;
vthis.updateGroup();
}
},
},
created() {
console.log("xxxx", this.configxml.xml);
this.basconfig = this.oParse.parseXML(this.configxml.xml);
this.initConfig(this.basconfig);
},
mounted() {
this.basedocument = $.parseXML(xml);
var vthis = this;
var deleteIcon =
"data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";
var img = document.createElement("img");
//设置图形显示拖拽点样式
fabric.Object.prototype.controls.deleteControl = new fabric.Control({
x: 0.5,
y: -0.5,
offsetY: -10,
offsetX: -30,
cursorStyle: "pointer",
mouseUpHandler: deleteObject,
render: renderIcon,
cornerSize: 16,
});
function deleteObject(eventData, transform) {
var target = transform.target;
var canvas = target.canvas;
cvselect = false;
canvas.remove(target);
canvas.requestRenderAll();
}
function renderIcon(ctx, left, top, styleOverride, fabricObject) {
var size = this.cornerSize;
ctx.save();
ctx.translate(left, top);
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
ctx.drawImage(img, -size / 2, -size / 2, size, size);
ctx.restore();
}
img.src = deleteIcon;
window.zoom = window.zoom ? window.zoom : 1;
canvas = new fabric.Canvas("main", {});
canvas.on("mouse:down", function (options) {
console.log(options);
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseFrom.x = xy.x;
mouseFrom.y = xy.y;
if (!cvselect) {
doDrawing = true;
} else {
if (!cvunselect) {
cvselect = false;
}
}
});
canvas.on("mouse:up", function (options) {
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseTo.x = xy.x;
mouseTo.y = xy.y;
// drawing();
drawingObject = null;
moveCount = 1;
doDrawing = false;
});
canvas.on("mouse:move", function (options) {
if (moveCount % 2 && !doDrawing) {
//减少绘制频率
return;
}
moveCount++;
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseTo.x = xy.x;
mouseTo.y = xy.y;
drawType = "rectangle";
vthis.drawing("draw");
});
function transformMouse(mouseX, mouseY) {
return { x: mouseX / window.zoom, y: mouseY / window.zoom };
}
},
};
</script>
<style scoped>
#main {
width: 700px;
height: 500px;
}
button {
cursor: pointer;
}
.modal-title {
float: left;
width: 93%;
overflow: hidden;
}
.modal-body {
height: 555px !important;
display: flex;
}
.modal-editbox {
position: relative;
float: right;
min-height: 450px;
width: 22%;
color: #fff;
}
.modal-editbox .modal-lb {
position: absolute;
bottom: 0;
width: 150px;
}
.modal-left {
position: relative;
text-align: center;
width: 700px;
}
.modal-right {
flex: 1;
height: 500px;
border: 1px solid #ccc;
margin-left: 20px;
}
.pic {
position: absolute;
top: 0;
left: 0;
border: 1px solid #ccc;
background: url("../../../../assets/img/home/bk.png") no-repeat;
background-size: 100% 100%;
}
.pic img {
width: 700px;
height: 500px;
margin: 0;
padding: 0;
}
.be-content {
margin: 15px 0 0 10px;
}
.be-header {
text-align: center;
margin: 10px 0;
}
.typebox {
max-height: 200px;
min-height: 100px;
overflow-y: auto;
display: flex;
flex-direction: row;
}
.configbox {
height: 230px;
margin-right: 10px;
display: flex;
flex-direction: row;
}
.areabox {
height: 230px;
width: 90px;
border: 1px solid #ccc;
border-radius: 2px;
position: relative;
}
.setbox {
flex: 1;
margin-left: 10px;
border: 1px solid #ccc;
border-radius: 3px;
}
.listbox {
width: 93px;
border: 1px solid #dcdfe6;
margin: 0 10px 10px 0;
height: 35px;
border-radius: 5px;
}
.checkgrop {
width: 20px;
margin: 10px 0 0 5px;
overflow: hidden;
}
.typetext {
margin: 8px 0 0 0;
}
.curlist {
border: 1px solid #2d8cf0;
}
.area-header {
text-align: center;
border-bottom: 1px solid #ccc;
}
.bottombtn {
position: absolute;
bottom: 0;
width: 90px;
text-align: center;
}
.configlabel {
width: 120px;
display: inline-block;
}
.setboxitem {
display: flex;
flex-direction: row;
margin: 10px 5px 0 0;
}
.area-item {
text-align: center;
border-bottom: 1px solid #dcdfe6;
}
.activeare {
text-align: center;
color: #2d8cf0;
}
</style>
<template>
<div class="modal-body b-box">
<div class="modal-left">
<div class="pic" id="pic">
<canvas id="main" width="700" height="500"></canvas>
</div>
</div>
<div class="modal-right">
<div class="be-header">
<el-radio-group v-model="checkval" size="mini">
<el-radio-button label="shanghai">行为事件</el-radio-button>
<el-radio-button label="北京" name="shangha" disabled
>交通事件</el-radio-button
>
<el-radio-button label="广州" name="shnghai" disabled
>安防事件</el-radio-button
>
</el-radio-group>
</div>
<div class="be-content">
<div class="typebox">
<div class="checkbox" v-for="(item, index) in basconfig" :key="index">
<div
:class="{ listbox: true, curlist: cindex == index }"
@click="seltype(item, index)"
>
<el-checkbox-group v-model="checkboxGroup1" class="checkgrop">
<el-checkbox :key="item.name" :label="item.name">{{
""
}}</el-checkbox>
</el-checkbox-group>
<span class="typetext">{{item.name}}</span>
</div>
</div>
</div>
<div class="configbox">
<div class="areabox">
<div class="area-header">检测规则</div>
<div
:class="{'area-item':true,'activeare':item.id==curuuid}"
v-for="(item, index) in groupList"
:key="index"
@click="changeKlass(item)"
>
区域{{ index + 1 }}
</div>
<div class="bottombtn">
<!-- <el-button @click="savechange" type="primary" size="mini" style="width:90px">保存</el-button> -->
<!-- <el-button
@click="save"
type="primary"
size="mini"
style="width: 90px"
>保存</el-button> -->
</div>
</div>
<div class="setbox">
<div
v-for="(val, key, index) in citem.config"
:key="index"
class="setboxitem"
>
<span class="configlabel">{{ key }}:</span>
<span class=""
><el-input v-model="citem.config[key]"></el-input
></span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { fabric } from "fabric";
import { select } from "svg.js";
import { xml } from "./bog.js";
var canvas = null;
export default {
name: "zoneSetting",
props: ["bgUrl"],
data() {
return {
tabPosition: "top",
checkval: "shanghai",
checkboxGroup1: ["人员脱岗"],
groupList: [],
curAlgoType: "xsdsfd",
basconfig: {},
baselist: {},
cindex: 0,
citem: null,
curuuid:null,
roiBody:{},
basedocument: null,
paramsData:"",
};
},
methods: {
/**
* 初始化区域
*/
configInit(xml){
},
getObjects(klass) {
//获取所有的列表对象
var group = canvas.getObjects();
},
setAreaconfig() {
var group = canvas.getObjects();
this.groupList = group;
},
//设置活动对象
changeKlass(klass) {
canvas.setActiveObject(klass);
canvas.requestRenderAll();
},
updateGroup() {
var group = canvas.getObjects();
this.groupList = group;
},
/**
* tab切换保存之前绘制的数据
*/
changetype(data, index) {
var group = canvas.getObjects();
var confdata = this.basconfig[this.cindex];
confdata.roi = group;
canvas.clear();
console.log(this.basconfig);
},
/**
* 回显对象
*/
fabricObjInit(klass) {
canvas.add(klass);
},
/**
* 根据选择模型定位规则
*/
selectklass(klass){
this.curuuid = klass.id;
},
/**
* 解构算法xml
*/
initConfig(config) {
for (let key in config) {
if (key === "root") {
this.initConfig(config["root"]);
} else if (key === "算法功能") {
this.initConfig(config[key]);
} else {
this.buildUserobj(config[key], key);
}
}
},
/**
* 构建需要的数据结构
*/
buildUserobj(obj, parentkey) {
let arr = [];
for (let key in obj) {
let buildobj = {
pkey: parentkey,
id: key,
name: key,
roi: null,
config: obj[key],
};
arr.push(buildobj);
}
this.basconfig = arr;
debugger;
this.citem = arr[0];
console.log(this.citem);
console.log("baseconfgi", this.basconfig);
},
seltype(item, cindex) {
if (this.cindex == cindex) {
return false;
}
this.citem = item;
this.changetype(item);
this.cindex = cindex;
let rois = item.roi;
if (item.roi !== "" && item.roi !== null) {
this.groupList = rois
for (let i = 0; i < rois.length; i++) {
this.fabricObjInit(rois[i]);
}
}
},
/**
* 修改配置文件
*/
savechange() {},
/**
* 构建存储用的json
*/
save() {
//博关算法监测区域
let confArr = [],
parentname;
this.basconfig.map((ele) => {
if (ele.config["算法ID"]) {
let idname = ele.config["算法ID"];
let ROI = {
idname: "",
};
console.log(this.buildRoI(ele))
this.roiBody[idname] = this.buildRoI(ele);
// confArr.push(this.buildRoI(ele));
}
//构建参数树
parentname = ele.pkey;
let chidkey = ele.name;
let childconfig = {};
childconfig[chidkey] = ele.config;
confArr.push(childconfig);
});
this.buildParam(parentname,confArr);
return this.oParse.writeXML({ roi: this.roiBody });
},
clear(){
canvas.clear();
},
/**
* 构建ROI
*/
buildRoI(klass){
let bg_arr = [],pol;
let idname = klass.config["算法ID"];
if(klass.roi != null && klass.roi != "" ) {
klass.roi.map(ele => {
let lines = ele.aCoords;
let point = [{
"point_seq":"1",
"x":(lines.tl.x/700).toFixed(6),
"y":(lines.tl.y/500).toFixed(6)
},{
"point_seq":"2",
"x":(lines.tr.x/700).toFixed(6),
"y":(lines.tr.y/500).toFixed(6)
},{
"point_seq":"3",
"x":(lines.br.x/700).toFixed(6),
"y":(lines.br.y/500).toFixed(6),
},{
"point_seq":"4",
"x":(lines.bl.x/700).toFixed(6),
"y":(lines.bl.y/500).toFixed(6),
}]
let obj = {
"polygon_point_count":4,
"point":point
}
bg_arr.push(obj)
});
pol = {
"region_count": klass.roi.length,
"polygon":bg_arr
}
} else {
pol = {
"region_count": 0,
}
}
return pol;
},
/**
* 构建参数树
*/
buildParam(parentname,confArr) {
let paramsconfig = {
root: {
算法功能: {},
},
};
let pobj = {
"结果推送地址":"http://192.168.9.25:8080/"
};
confArr.map((ele) => {
for (key in ele) {
pobj[key] = ele[key];
}
});
paramsconfig.root.算法功能[parentname] = pobj;
this.paramsData = this.oParse.writeXML(paramsconfig);
},
},
created() {
this.basconfig = this.oParse.parseXML(xml);
this.initConfig(this.basconfig);
},
mounted() {
this.basedocument = $.parseXML(xml);
var vthis = this;
var mouseFrom = {},
mouseTo = {},
drawType = "",
canvasObjectIndex = 0,
textbox = null;
var drawWidth = 2; //笔触宽度
var color = "#E34F51"; //画笔颜色
var drawingObject = null; //当前绘制对象
var moveCount = 1; //绘制移动计数器
var doDrawing = false; // 绘制状态
var cvselect = false;
var curObjcet = null;
var cvunselect = true;
var deleteIcon =
"data:image/svg+xml,%3C%3Fxml version='1.0' encoding='utf-8'%3F%3E%3C!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.1//EN' 'http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd'%3E%3Csvg version='1.1' id='Ebene_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='595.275px' height='595.275px' viewBox='200 215 230 470' xml:space='preserve'%3E%3Ccircle style='fill:%23F44336;' cx='299.76' cy='439.067' r='218.516'/%3E%3Cg%3E%3Crect x='267.162' y='307.978' transform='matrix(0.7071 -0.7071 0.7071 0.7071 -222.6202 340.6915)' style='fill:white;' width='65.545' height='262.18'/%3E%3Crect x='266.988' y='308.153' transform='matrix(0.7071 0.7071 -0.7071 0.7071 398.3889 -83.3116)' style='fill:white;' width='65.544' height='262.179'/%3E%3C/g%3E%3C/svg%3E";
var img = document.createElement("img");
//设置图形显示拖拽点样式
fabric.Object.prototype.controls.deleteControl = new fabric.Control({
x: 0.5,
y: -0.5,
offsetY: -10,
offsetX: -30,
cursorStyle: "pointer",
mouseUpHandler: deleteObject,
render: renderIcon,
cornerSize: 16,
});
function deleteObject(eventData, transform) {
var target = transform.target;
var canvas = target.canvas;
cvselect = false;
canvas.remove(target);
canvas.requestRenderAll();
}
function renderIcon(ctx, left, top, styleOverride, fabricObject) {
var size = this.cornerSize;
ctx.save();
ctx.translate(left, top);
ctx.rotate(fabric.util.degreesToRadians(fabricObject.angle));
ctx.drawImage(img, -size / 2, -size / 2, size, size);
ctx.restore();
}
img.src = deleteIcon;
window.zoom = window.zoom ? window.zoom : 1;
canvas = new fabric.Canvas("main", {});
canvas.on("mouse:down", function (options) {
console.log(options);
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseFrom.x = xy.x;
mouseFrom.y = xy.y;
if (!cvselect) {
doDrawing = true;
} else {
if (!cvunselect) {
cvselect = false;
}
}
});
canvas.on("mouse:up", function (options) {
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseTo.x = xy.x;
mouseTo.y = xy.y;
// drawing();
drawingObject = null;
moveCount = 1;
doDrawing = false;
});
canvas.on("mouse:move", function (options) {
if (moveCount % 2 && !doDrawing) {
//减少绘制频率
return;
}
moveCount++;
var xy = transformMouse(options.e.offsetX, options.e.offsetY);
mouseTo.x = xy.x;
mouseTo.y = xy.y;
drawType = "rectangle";
drawing();
});
function transformMouse(mouseX, mouseY) {
return { x: mouseX / window.zoom, y: mouseY / window.zoom };
}
function drawing() {
if (drawingObject) {
canvas.remove(drawingObject);
}
var canvasObject = null;
switch (drawType) {
case "arrow": //箭头
canvasObject = new fabric.Path(
drawArrow(mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y, 30, 30),
{
stroke: color,
fill: "rgba(255,255,255,0)",
strokeWidth: drawWidth,
}
);
break;
case "line": //直线
canvasObject = new fabric.Line(
[mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y],
{
stroke: color,
strokeWidth: drawWidth,
}
);
break;
case "dottedline": //虚线
canvasObject = new fabric.Line(
[mouseFrom.x, mouseFrom.y, mouseTo.x, mouseTo.y],
{
strokeDashArray: [3, 1],
stroke: color,
strokeWidth: drawWidth,
}
);
break;
case "circle": //正圆
var left = mouseFrom.x,
top = mouseFrom.y;
var radius =
Math.sqrt(
(mouseTo.x - left) * (mouseTo.x - left) +
(mouseTo.y - top) * (mouseTo.y - top)
) / 2;
canvasObject = new fabric.Circle({
left: left,
top: top,
stroke: color,
fill: "rgba(255, 255, 255, 0)",
radius: radius,
strokeWidth: drawWidth,
});
break;
case "ellipse": //椭圆
var left = mouseFrom.x,
top = mouseFrom.y;
var radius =
Math.sqrt(
(mouseTo.x - left) * (mouseTo.x - left) +
(mouseTo.y - top) * (mouseTo.y - top)
) / 2;
canvasObject = new fabric.Ellipse({
left: left,
top: top,
stroke: color,
fill: "rgba(255, 255, 255, 0)",
originX: "center",
originY: "center",
rx: Math.abs(left - mouseTo.x),
ry: Math.abs(top - mouseTo.y),
strokeWidth: drawWidth,
});
break;
case "square": //TODO:正方形(后期完善)
break;
case "rectangle": //长方形
var left = mouseFrom.x,
top = mouseFrom.y;
canvasObject = new fabric.Rect({
left: left,
top: top,
width: mouseTo.x - left, //矩形的宽度
height: mouseTo.y - top, //矩形的高度
fill: "rgba(0,0,0,.3)", //填充的颜色
stroke: "orange", // 边框原色
strokeWidth: 1, // 边框大小
});
canvasObject.on("selected", function () {
cvselect = true;
cvunselect = true;
curObjcet = canvasObject;
vthis.selectklass(canvasObject);
});
canvasObject.on("deselected", function () {
vthis.setAreaconfig();
var group = canvas.getObjects();
var confdata = vthis.basconfig[vthis.cindex];
confdata.roi = group;
cvunselect = false;
});
break;
case "rightangle": //直角三角形
var path =
"M " +
mouseFrom.x +
" " +
mouseFrom.y +
" L " +
mouseFrom.x +
" " +
mouseTo.y +
" L " +
mouseTo.x +
" " +
mouseTo.y +
" z";
canvasObject = new fabric.Path(path, {
left: left,
top: top,
stroke: color,
strokeWidth: drawWidth,
fill: "rgba(255, 255, 255, 0)",
});
break;
case "equilateral": //等边三角形
var height = mouseTo.y - mouseFrom.y;
canvasObject = new fabric.Triangle({
top: mouseFrom.y,
left: mouseFrom.x,
width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)),
height: height,
stroke: color,
strokeWidth: drawWidth,
fill: "rgba(255,255,255,0)",
});
break;
case "isosceles":
break;
case "text":
textbox = new fabric.Textbox("", {
left: mouseFrom.x - 60,
top: mouseFrom.y - 20,
width: 150,
fontSize: 18,
borderColor: "#2c2c2c",
fill: color,
hasControls: false,
});
canvas.add(textbox);
textbox.enterEditing();
textbox.hiddenTextarea.focus();
break;
case "remove":
break;
default:
break;
}
// canvasObject.index = getCanvasObjectIndex();
if (canvasObject) {
canvasObject.id = vthis.uuid();
console.log(canvasObject);
// canvasObject.index = getCanvasObjectIndex();
canvas.add(canvasObject); //.setActiveObject(canvasObject)
drawingObject = canvasObject;
vthis.updateGroup();
}
}
},
};
</script>
<style scoped>
#main {
width: 700px;
height: 500px;
}
button {
cursor: pointer;
}
.modal-title {
float: left;
width: 93%;
overflow: hidden;
}
.modal-body {
height: 555px !important;
display: flex;
}
.modal-editbox {
position: relative;
float: right;
min-height: 450px;
width: 22%;
color: #fff;
}
.modal-editbox .modal-lb {
position: absolute;
bottom: 0;
width: 150px;
}
.modal-left {
position: relative;
text-align: center;
width: 700px;
}
.modal-right {
flex: 1;
height: 500px;
border: 1px solid #ccc;
margin-left: 20px;
}
.pic {
position: absolute;
top: 0;
left: 0;
border: 1px solid #ccc;
background: url("../../../../assets/img/home/bk.png")no-repeat;
background-size:100% 100%;
}
.pic img {
width: 700px;
height: 500px;
margin: 0;
padding: 0;
}
.be-content {
margin: 15px 0 0 10px;
}
.be-header {
text-align: center;
margin: 10px 0;
}
.typebox {
max-height: 200px;
min-height: 100px;
overflow-y: auto;
display: flex;
flex-direction: row;
}
.configbox {
height: 230px;
margin-right: 10px;
display: flex;
flex-direction: row;
}
.areabox {
height: 230px;
width: 90px;
border: 1px solid #ccc;
border-radius: 2px;
position: relative;
}
.setbox {
flex: 1;
margin-left: 10px;
border: 1px solid #ccc;
border-radius: 3px;
}
.listbox {
width: 93px;
border: 1px solid #dcdfe6;
margin: 0 10px 10px 0;
height: 35px;
border-radius: 5px;
}
.checkgrop {
width: 20px;
margin: 10px 0 0 5px;
overflow: hidden;
}
.typetext {
margin: 8px 0 0 0;
}
.curlist {
border: 1px solid #2d8cf0;
}
.area-header {
text-align: center;
border-bottom: 1px solid #ccc;
}
.bottombtn {
position: absolute;
bottom: 0;
width: 90px;
text-align: center;
}
.configlabel {
width: 120px;
display: inline-block;
}
.setboxitem {
display: flex;
flex-direction: row;
margin: 10px 5px 0 0;
}
.area-item{
text-align: center;
border-bottom: 1px solid #dcdfe6;
}
.activeare{
text-align: center;
color: #2d8cf0;
}
</style>
<template>
<div class="modal-body">
<div class="modal-body safebox">
<div class="modal-lt">
<button v-for="(item,index) in typeData" :class="{'curmodal':index==cindex}" @click="changeLayer(index)" :key="index">{{item}}</button>
</div>
......@@ -13,8 +13,8 @@
</div>
</div>
<div class="modal-lb" id="edit_list" v-if="drawState!=-1">
<el-radio-group v-model="canvasState" @change='changeCanvasState' :disabled='needLine||needRect'>
<el-radio-button :label="1">添加</el-radio-button>
<el-radio-group size="mini" v-model="canvasState" @change='changeCanvasState' :disabled='needLine||needRect'>
<el-radio-button :label="1" >添加</el-radio-button>
<el-radio-button :label="0">编辑</el-radio-button>
</el-radio-group>
<div v-if="!canvasState">
......@@ -859,7 +859,9 @@
}
.modal-body {
/* height: 540px!important; */
height: 540px!important;
overflow: hidden;
margin-bottom: 10px;
}
.modal-lt {
width: 100%;
......@@ -873,7 +875,7 @@
background: #145B93!important
}
.modal-left {
float: left;
float: right;
min-height: 350px;
width: 15%;
color: #fff;
......@@ -883,6 +885,7 @@
position: relative;
float: left;
text-align: center;
margin-left:10px;
}
.modal-left button {
......
export const xml = `<?xml version="1.0" encoding="GBK"?><root><算法功能><行为分析_BG><人员脱岗><算法ID>RegionalInvasion</算法ID><告警门限值>60</告警门限值><告警间隔>5</告警间隔></人员脱岗><人员入侵><算法ID>AbsentDetection</算法ID><方向>1</方向></人员入侵><物品遗留><算法ID>GoodsMovedDeteion</算法ID><灵敏度>60</灵敏度><上报频率>3</上报频率><背景刷新时间>5</背景刷新时间></物品遗留></行为分析_BG></算法功能></root>`
\ No newline at end of file
class draw{
constructor(cav){
this.cav = cav;
}
}
\ No newline at end of file
<template>
<div>
<el-dialog
title="区域设置"
:visible.sync="dialogVisible"
width="1100px"
:before-close="beforeHideModal"
>
<div>
<TraficCanvas
:bgUrl="bgUrl"
v-if="type == '0' || type == '5' || type == '3'"
ref="canvas"
></TraficCanvas>
<FlowCanvas :bgUrl="bgUrl" v-if="type == '1'" ref="canvas"></FlowCanvas>
<SafeCanvas :bgUrl="bgUrl" v-if="type == '2'" ref="canvas"></SafeCanvas>
<FaceCanvas :bgUrl="bgUrl" v-if="type == '4'" ref="canvas"></FaceCanvas>
<ComplexCanvas
:bgUrl="bgUrl"
v-if="type == '7'"
ref="canvas"
></ComplexCanvas>
</div>
<div>
<el-button type="primary" style="float:left; margin-right:10px" @click="down">下载<i class="el-icon-download el-icon--right"></i></el-button>
<el-upload
class="upload-demo"
action=""
:auto-upload="false"
:show-file-list="false"
:on-change="handleChange"
:file-list="fileList">
<el-button type="primary">上传<i class="el-icon-upload el-icon--right"></i></el-button>
<span slot="tip" class="el-upload__tip upinfo"> 手动上传场景图片</span>
</el-upload>
</div>
<span slot="footer" class="dialog-footer">
<el-button @click="beforeHideModal">取 消</el-button>
<el-button type="primary" @click="save">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
import TraficCanvas from "./areaconfig/TraficCanvas";
import FlowCanvas from "./areaconfig/FlowCanvas";
import SafeCanvas from "./areaconfig/SafeCanvas";
import FaceCanvas from "./areaconfig/FaceCanvas";
import ComplexCanvas from "./areaconfig/ComplexCanvas";
import {roi} from "./areaconfig/roi_1"
export default {
data() {
return {
dialogVisible: false,
isShow: false,
type: "0",
btnIsactive: false,
showClose: false,
roiBody: {},
XMLStr: "",
taskData: "",
bgUrl: "",
baseUrl:"",
fileList:[]
};
},
components: {
TraficCanvas,
SafeCanvas,
FlowCanvas,
FaceCanvas,
ComplexCanvas
},
methods: {
showModal: function(data, mtaskdata) {
var _this = this;
this.$store.commit("setocxstate", 0);
this.taskData = mtaskdata;
this.dialogVisible = true;
this.type = data.algo_type;
// this.type = 2;
this.bgUrl = "";
//获取视频截图
this.$api.task
.cutpic(
mtaskdata.vchan.vdev_unid,
mtaskdata.vchan.vchan_refid,
mtaskdata.subtask_id
)
.then(data => {
if (!data.ecode) {
this.bgUrl = "data:image/png;base64," + data.pic_base64;
this.baseUrl = "data:image/png;base64," + data.pic_base64;
setTimeout(() => {
let img = document.getElementById("pic").childNodes[0];
let canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 500;
try {
canvas.getContext("2d").drawImage(img, 0, 0, 800, 500);
_this.bgUrl = canvas.toDataURL("image/webp");
} catch (error) {
console.log(error);
}
}, 500);
} else {
alert("区域设置截图失败!" + data.enote);
}
})
.catch(err => {
console.log("区域设置截图返回异常:", err.message);
});
setTimeout(() => {
_this.$refs.canvas.stageInit();
if (data.rois) {
_this.$refs.canvas.configInit(data.rois[0].roi);
// _this.$refs.canvas.configInit(roi);
}
}, 300);
},
handleChange(file, fileLis){
this.bgUrl = URL.createObjectURL(file.raw);
setTimeout(() => {
let img = document.getElementById("pic").childNodes[0];
let canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 500;
try {
canvas.getContext("2d").drawImage(img, 0, 0, 800, 500);
_this.bgUrl = canvas.toDataURL("image/webp");
} catch (error) {
console.log(error);
}
}, 500);
},
down(){
this.downloadurl(this.baseUrl,'scenes_pic')
},
downloadurl(content, fileName) { //下载base64图片
var base64ToBlob = function(code) {
let parts = code.split(';base64,');
let contentType = parts[0].split(':')[1];
let raw = window.atob(parts[1]);
let rawLength = raw.length;
let uInt8Array = new Uint8Array(rawLength);
for(let i = 0; i < rawLength; ++i) {
uInt8Array[i] = raw.charCodeAt(i);
}
return new Blob([uInt8Array], {
type: contentType
});
};
let aLink = document.createElement('a');
let blob = base64ToBlob(content); //new Blob([content]);
let evt = document.createEvent("HTMLEvents");
evt.initEvent("click", true, true); //initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
aLink.download = fileName;
aLink.href = URL.createObjectURL(blob);
aLink.click();
},
beforeHideModal: function() {
this.$store.commit("setocxstate", 1);
this.dialogVisible = false;
this.$refs.canvas.clear();
this.$refs.canvas.cindex = 0;
this.bgUrl = "";
},
getType: function() {
if (this.$parent.subTaskInfo) {
this.type = this.$parent.subTaskInfo.task_algo_type;
} else {
this.type = this.$parent.$parent.subTaskInfo.task_algo_type;
}
this.XMLStr = "";
this.btnIsactive = true;
try {
this.EditList(1);
} catch (error) {
console.log(error);
}
},
save: function() {
if (this.$refs.canvas.roadFlag === false) {
this.$alert("车道线有修改,请检查车道属性是否正确", "提示", {
confirmButtonText: "确定"
});
//xieminghui
// this.$refs.canvas.roadFlag = "confirm";
return;
}
let XMLStr = this.$refs.canvas.save();
if (this.type == "1" && (XMLStr === "dir" || XMLStr === "in")) {
this.$message({
type: "warning",
message: "请检查配置是否正确"
});
return;
}
this.$parent.submit(XMLStr, "roi", this.taskData);
this.beforeHideModal();
}
}
};
</script>
<style lang="stylus" scoped></style>
......@@ -41,7 +41,9 @@
<el-option value="" label="--"></el-option>
<el-option value="0" label="交通"></el-option>
<el-option value="1" label="客流"></el-option>
<el-option value="2" label="安防"></el-option>
<el-option value="2" label="行为分析"></el-option>
<el-option value="12" label="行为分析_BG"></el-option>
<el-option value="3" label="违停"></el-option>
<el-option value="5" label="交通行人"></el-option>
</el-select>
......
......@@ -56,7 +56,7 @@
<el-option value="" label="全部"></el-option>
<el-option value="0" label="交通"></el-option>
<el-option value="1" label="客流"></el-option>
<el-option value="2" label="行为分析"></el-option>
<el-option value="12" label="行为分析"></el-option>
<el-option value="7" label="综合流量"></el-option>
<!-- <el-option value="4" label='人脸'></el-option> -->
</el-select>
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!