徐景良 2 weeks ago
commit 6ad5b44343

@ -42,6 +42,14 @@
<script type="text/javascript" src="./public/monitor/monitorLC/imouPlayer.js"></script>
<!-- 引入青犀插件内容 -->
<script type="text/javascript" src="./public/monitor/monitorQX/EasyPlayer-element.min.js"></script>
<!-- 引入大华算法 -->
<link rel="stylesheet" href="./public/smartJs/css/layui.css">
<link rel="stylesheet" href="./public/smartJs/theme.css">
<link rel="stylesheet" href="./public/smartJs/smart-style.css">
<script src="./public/smartJs/runtime.js"></script>
<script src="./public/smartJs/layui.js"></script>
<script src="./public/smartJs/xm-select.js"></script>
<script src="./public/smartJs/smart.js"></script>
</head>

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #eee;border-left-width:6px;background-color:#FAFAFA;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:40px;line-height:40px;border-bottom:1px solid #eee}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 10px;border-left:1px solid #e2e2e2;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view .layui-code-ol li:first-child{padding-top:10px}.layui-code-view .layui-code-ol li:last-child{padding-bottom:10px}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none}.layui-code-demo .layui-code{visibility:visible!important;margin:-15px;border-top:none;border-right:none;border-bottom:none}.layui-code-demo .layui-tab-content{padding:15px;border-top:none}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 299 KiB

Binary file not shown.

Binary file not shown.

@ -0,0 +1,87 @@
/*!
* Very simple jQuery Color Picker
* https://github.com/tkrotoff/jquery-simplecolorpicker
*
* Copyright (C) 2012-2013 Tanguy Krotoff <tkrotoff@gmail.com>
*
* Licensed under the MIT license
*/
/**
* Inspired by Bootstrap Twitter.
* See https://github.com/twbs/bootstrap/blob/master/less/navbar.less
* See https://github.com/twbs/bootstrap/blob/master/less/dropdowns.less
*/
.simplecolorpicker.picker {
position: absolute;
top: 100%;
left: 0;
z-index: 1051; /* Above Bootstrap modal (@zindex-modal = 1050) */
display: none;
float: left;
min-width: 160px;
max-width: 283px; /* @popover-max-width = 276px + 7 */
padding: 5px 0 0 5px;
margin: 2px 0 0;
list-style: none;
background-color: #fff; /* @dropdown-bg */
border: 1px solid #ccc; /* @dropdown-fallback-border */
border: 1px solid rgba(0, 0, 0, .15); /* @dropdown-border */
-webkit-border-radius: 4px; /* @border-radius-base */
-moz-border-radius: 4px;
border-radius: 4px;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-moz-box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
box-shadow: 0 6px 12px rgba(0, 0, 0, .175);
-webkit-background-clip: padding-box;
-moz-background-clip: padding;
background-clip: padding-box;
}
.simplecolorpicker.inline {
display: inline-block;
padding: 6px 0;
}
.simplecolorpicker span {
margin: 0 5px 5px 0;
}
.simplecolorpicker.icon,
.simplecolorpicker span.color {
display: inline-block;
cursor: pointer;
border: 1px solid transparent;
}
.simplecolorpicker.icon:after,
.simplecolorpicker span.color:after {
content: '\00a0\00a0\00a0\00a0'; /* Spaces */
}
.simplecolorpicker span.color[data-disabled]:hover {
cursor: not-allowed;
border: 1px solid transparent;
}
.simplecolorpicker span.color:hover,
.simplecolorpicker span.color[data-selected],
.simplecolorpicker span.color[data-selected]:hover {
border: 1px solid #222; /* @gray-dark */
}
.simplecolorpicker span.color[data-selected]:after {
color: #fff;
}
/* Vertical separator, replaces optgroup. */
.simplecolorpicker span.vr {
border-left: 1px solid #222; /* @gray-dark */
}

@ -0,0 +1,235 @@
/*!
* Very simple jQuery Color Picker
* https://github.com/tkrotoff/jquery-simplecolorpicker
*
* Copyright (C) 2012-2013 Tanguy Krotoff <tkrotoff@gmail.com>
*
* Licensed under the MIT license
*/
(function($) {
'use strict';
/**
* Constructor.
*/
var SimpleColorPicker = function(select, options) {
this.init('simplecolorpicker', select, options);
};
/**
* SimpleColorPicker class.
*/
SimpleColorPicker.prototype = {
constructor: SimpleColorPicker,
init: function(type, select, options) {
var self = this;
self.type = type;
self.$select = $(select);
self.$select.hide();
self.options = $.extend({}, $.fn.simplecolorpicker.defaults, options);
self.$colorList = null;
if (self.options.picker === true) {
var selectText = self.$select.find('> option:selected').text();
self.$icon = $('<span class="simplecolorpicker icon"'
+ ' title="' + selectText + '"'
+ ' style="background-color: ' + self.$select.val() + ';"'
+ ' role="button" tabindex="0">'
+ '</span>').insertAfter(self.$select);
self.$icon.on('click.' + self.type, $.proxy(self.showPicker, self));
self.$picker = $('<span class="simplecolorpicker picker ' + self.options.theme + '"></span>').appendTo(document.body);
self.$colorList = self.$picker;
// Hide picker when clicking outside
$(document).on('mousedown.' + self.type, $.proxy(self.hidePicker, self));
self.$picker.on('mousedown.' + self.type, $.proxy(self.mousedown, self));
} else {
self.$inline = $('<span class="simplecolorpicker inline ' + self.options.theme + '"></span>').insertAfter(self.$select);
self.$colorList = self.$inline;
}
// Build the list of colors
// <span class="color selected" title="Green" style="background-color: #7bd148;" role="button"></span>
self.$select.find('> option').each(function() {
var $option = $(this);
var color = $option.val();
var isSelected = $option.is(':selected');
var isDisabled = $option.is(':disabled');
var selected = '';
if (isSelected === true) {
selected = ' data-selected';
}
var disabled = '';
if (isDisabled === true) {
disabled = ' data-disabled';
}
var title = '';
if (isDisabled === false) {
title = ' title="' + $option.text() + '"';
}
var role = '';
if (isDisabled === false) {
role = ' role="button" tabindex="0"';
}
var $colorSpan = $('<span class="color"'
+ title
+ ' style="background-color: ' + color + ';"'
+ ' data-color="' + color + '"'
+ selected
+ disabled
+ role + '>'
+ '</span>');
self.$colorList.append($colorSpan);
$colorSpan.on('click.' + self.type, $.proxy(self.colorSpanClicked, self));
var $next = $option.next();
if ($next.is('optgroup') === true) {
// Vertical break, like hr
self.$colorList.append('<span class="vr"></span>');
}
});
},
/**
* Changes the selected color.
*
* @param color the hexadecimal color to select, ex: '#fbd75b'
*/
selectColor: function(color) {
var self = this;
var $colorSpan = self.$colorList.find('> span.color').filter(function() {
return $(this).data('color').toLowerCase() === color.toLowerCase();
});
if ($colorSpan.length > 0) {
self.selectColorSpan($colorSpan);
} else {
console.error("The given color '" + color + "' could not be found");
}
},
showPicker: function() {
var pos = this.$icon.offset();
this.$picker.css({
// Remove some pixels to align the picker icon with the icons inside the dropdown
left: pos.left - 6,
top: pos.top + this.$icon.outerHeight()
});
this.$picker.show(this.options.pickerDelay);
},
hidePicker: function() {
this.$picker.hide(this.options.pickerDelay);
},
/**
* Selects the given span inside $colorList.
*
* The given span becomes the selected one.
* It also changes the HTML select value, this will emit the 'change' event.
*/
selectColorSpan: function($colorSpan) {
var color = $colorSpan.data('color');
var title = $colorSpan.prop('title');
// Mark this span as the selected one
$colorSpan.siblings().removeAttr('data-selected');
$colorSpan.attr('data-selected', '');
if (this.options.picker === true) {
this.$icon.css('background-color', color);
this.$icon.prop('title', title);
this.hidePicker();
}
// Change HTML select value
this.$select.val(color);
},
/**
* The user clicked on a color inside $colorList.
*/
colorSpanClicked: function(e) {
// When a color is clicked, make it the new selected one (unless disabled)
if ($(e.target).is('[data-disabled]') === false) {
this.selectColorSpan($(e.target));
this.$select.trigger('change');
}
},
/**
* Prevents the mousedown event from "eating" the click event.
*/
mousedown: function(e) {
e.stopPropagation();
e.preventDefault();
},
destroy: function() {
if (this.options.picker === true) {
this.$icon.off('.' + this.type);
this.$icon.remove();
$(document).off('.' + this.type);
}
this.$colorList.off('.' + this.type);
this.$colorList.remove();
this.$select.removeData(this.type);
this.$select.show();
}
};
/**
* Plugin definition.
* How to use: $('#id').simplecolorpicker()
*/
$.fn.simplecolorpicker = function(option) {
var args = $.makeArray(arguments);
args.shift();
// For HTML element passed to the plugin
return this.each(function() {
var $this = $(this),
data = $this.data('simplecolorpicker'),
options = typeof option === 'object' && option;
if (data === undefined) {
$this.data('simplecolorpicker', (data = new SimpleColorPicker(this, options)));
}
if (typeof option === 'string') {
data[option].apply(data, args);
}
});
};
/**
* Default options.
*/
$.fn.simplecolorpicker.defaults = {
// No theme by default
theme: '',
// Show the picker or make it inline
picker: false,
// Animation delay in milliseconds
pickerDelay: 0
};
})(jQuery);

File diff suppressed because one or more lines are too long

@ -0,0 +1,57 @@
{
"name": "@sdd-web/smart-js-stable",
"version": "2.3.0",
"description": "中心智能配置智能算法版本解释器",
"main": "dist/smart.js",
"scripts": {
"start": "webpack-dev-server --mode development --config webpack.dev.config.js",
"build:umd": "webpack --mode production --config webpack.umd.config.js",
"build": "webpack --mode production --config webpack.prod.config.js"
},
"repository": {
"type": "git",
"url": "git@yfgitlab.dahuatech.com:sdd-web/npm/Smart-js.git"
},
"author": "232104",
"license": "ISC",
"browserslist": [
"chrome 38"
],
"devDependencies": {
"@babel/plugin-proposal-decorators": "^7.17.8",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-modules-umd": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/preset-es2015": "^7.0.0-beta.53",
"@babel/preset-react": "^7.16.7",
"@svgr/webpack": "^2.4.1",
"babel-loader": "^8.2.4",
"babel-plugin-import": "^1.13.5",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^5.0.3",
"css-loader": "^6.7.1",
"html-webpack-plugin": "^5.5.0",
"less": "^3.11.1",
"less-loader": "^4.1.0",
"mini-css-extract-plugin": "^2.6.0",
"optimize-css-assets-webpack-plugin": "^6.0.1",
"postcss-loader": "^7.0.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^1.1.0",
"webpack": "^5.70.0",
"webpack-cli": "^4.9.2",
"webpack-dev-server": "^4.8.0"
},
"dependencies": {
"@babel/core": "^7.17.8",
"@babel/polyfill": "^7.12.1",
"@sdd-web/h5-player": "^3.1.38",
"antd": "^3.19.1",
"jquery": "^3.6.0",
"layui": "^2.6.8",
"react": "^16.6.3",
"react-color": "^2.19.3",
"react-dom": "^16.6.3"
}
}

@ -0,0 +1,11 @@
(function(){
String.prototype.startsWith = String.prototype.startsWith || function (str) {
var reg = new RegExp("^" + str);
return reg.test(this);
}
String.prototype.endsWith = String.prototype.endsWith || function (str) {
var reg = new RegExp(str + "$");
return reg.test(this);
}
}())

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

@ -0,0 +1,46 @@
/*swtich背景色*/
.layui-form-onswitch{
background-color: #1E9FFF;
border: #1E9FFF;
}
/*选择框背景色*/
.layui-form-select dl dd.layui-this {
background-color: #1E9FFF;
}
/*tab的字体和边框颜色*/
.layui-tab-brief>.layui-tab-title .layui-this {
color:#1E9FFF;
}
/*tab的边框颜色*/
.layui-tab-brief>.layui-tab-more li.layui-this:after, .layui-tab-brief>.layui-tab-title .layui-this:after {
border-bottom-color: #1E9FFF;
}
/*checkbox底色*/
.layui-form-checked[lay-skin=primary] i {
border-color:#1E9FFF !important;;
background-color:#1E9FFF
}
.layui-form-checkbox[lay-skin=primary]:hover i {
border-color:#1E9FFF;
}
/*表格hover聚焦底色*/
.layui-table-highlight {
background-color:#E6F7FF
}
.layui-table tbody tr:hover {
background-color:#E6F7FF
}
.layui-table-edit {
border-color:#40A9FF;
}
/*输入框颜色*/
.layui-input:focus, .layui-textarea:focus,.layui-input:hover {
border-color: #40A9FF !important;
border-radius: 4px;
}
xm-select:active,xm-select:hover {
border-color: #40A9FF !important;
border-radius: 4px;
}

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

@ -0,0 +1,30 @@
import { defHttp } from '@/utils/http/axios';
enum Api {
GetsupportList = '/api/DaHuaAi/GetsupportList',
Getconfig = '/api/DaHuaAi/Getconfig',
CreateTasks = '/api/DaHuaAi/CreateTasks',
}
export function getsupportList(params) {
return defHttp.post({
url: Api.GetsupportList + '?page=' + params.page + '&limit=' + params.limit,
});
}
export function getconfig(params) {
return defHttp.post({
url:
Api.Getconfig +
'?version=' +
params.version +
'&functionType=' +
params.functionType +
'&algorithmCode=' +
params.algorithmCode,
});
}
export function createTasks(params) {
return defHttp.post({ url: Api.CreateTasks, params });
}

@ -10,11 +10,16 @@
<a-button @click="uavLive"></a-button>
<a-button @click="takePhoto"></a-button>
<div id="live-div"> </div>
<div style="margin: 20px 0 0 30px">大华算法实例</div>
<div class="common_div">
<div class="view" id="video" ref="videoRef"></div>
<div class="config" id="config"></div>
</div>
</div>
</template>
<script setup lang="ts">
import LiveStreamPlugin from '@/plugin/video/index';
import { onMounted } from 'vue';
import { onMounted, ref } from 'vue';
const liveStreamPlugin = new LiveStreamPlugin();
const starAirpot = () => {
@ -48,7 +53,356 @@
console.log(res);
});
};
const videoRef = ref<HTMLDivElement | null>(null);
const demo = ref();
let videoWidth = ref(0); // video
const renderData = ref([
{
tab: '全局配置',
data: [
{
profile: {
configName: 'CrossRegionDetection',
name: '规则举例',
transferType: '1',
items: {
'Config-App': {
type: 'object',
name: '应用配置',
items: {
Config: {
type: 'object',
name: '规则配置',
items: {
DetectRegion: {
type: 'polygon',
name: '检测区域',
max: 20,
withCross: true,
},
MinDetectRegion: {
type: 'rectangle',
name: '最小检测区',
withCross: true,
},
Fence: {
type: 'parallelline',
name: '平行线',
withCross: true,
},
DetectLine: {
type: 'line',
name: '警戒线',
withCross: true,
},
DetectPolyLine: {
type: 'polyline',
max: 5,
name: '警戒折线',
withCross: true,
},
ReportInterval: {
type: 'int',
name: '重复报警时间',
default: 5,
range: {
min: 1,
max: 300,
},
},
BaseLevel: {
type: 'float',
name: '拼接线水位值',
default: 2.0,
range: {
min: 0,
max: 299.0,
},
},
MovedCarFlag: {
type: 'bool',
name: '静止目标过滤',
default: true,
},
Type: {
type: 'string',
name: '规则类型',
default: 'CrossRegionDetection',
},
ProtectiveSuit: {
type: 'object',
name: '防护服检测',
items: {
Enable: {
type: 'bool',
name: '使能',
default: true,
},
},
},
Action: {
type: 'EnumArray',
name: '检测动作',
spec: {
type: 'string',
},
max: 2,
default: ['Inside'],
option: [
{
value: 'Inside',
name: '区域内报警',
},
{
value: 'Cross',
name: '穿越区域',
},
],
},
Direction: {
type: 'enum',
name: '检测方向',
spec: {
type: 'string',
},
default: 'Both',
option: [
{
value: 'Enter',
name: '进入',
},
{
value: 'Leave',
name: '离开',
},
{
value: 'Both',
name: '双向',
},
],
},
},
},
},
},
'Config-Alg': {},
},
},
VideoAnalyseGlobal: {},
},
],
},
{
tab: '规则配置',
data: [
{
profile: {
configName: 'CrossRegionDetection',
name: '规则举例',
transferType: '1',
items: {
'Config-App': {
type: 'object',
name: '应用配置',
items: {
Config: {
type: 'object',
name: '规则配置',
items: {
DetectRegion: {
type: 'polygon',
name: '检测区域',
max: 20,
withCross: true,
},
MinDetectRegion: {
type: 'rectangle',
name: '最小检测区',
withCross: true,
},
Fence: {
type: 'parallelline',
name: '平行线',
withCross: true,
},
DetectLine: {
type: 'line',
name: '警戒线',
withCross: true,
},
DetectPolyLine: {
type: 'polyline',
max: 5,
name: '警戒折线',
withCross: true,
},
ReportInterval: {
type: 'int',
name: '重复报警时间',
default: 5,
range: {
min: 1,
max: 300,
},
},
BaseLevel: {
type: 'float',
name: '拼接线水位值',
default: 2.0,
range: {
min: 0,
max: 299.0,
},
},
MovedCarFlag: {
type: 'bool',
name: '静止目标过滤',
default: true,
},
Type: {
type: 'string',
name: '规则类型',
default: 'CrossRegionDetection',
},
ProtectiveSuit: {
type: 'object',
name: '防护服检测',
items: {
Enable: {
type: 'bool',
name: '使能',
default: true,
},
},
},
Action: {
type: 'EnumArray',
name: '检测动作',
spec: {
type: 'string',
},
max: 2,
default: ['Inside'],
option: [
{
value: 'Inside',
name: '区域内报警',
},
{
value: 'Cross',
name: '穿越区域',
},
],
},
Direction: {
type: 'enum',
name: '检测方向',
spec: {
type: 'string',
},
default: 'Both',
option: [
{
value: 'Enter',
name: '进入',
},
{
value: 'Leave',
name: '离开',
},
{
value: 'Both',
name: '双向',
},
],
},
},
},
},
},
'Config-Alg': {},
},
},
RuleObj: {},
},
],
},
]);
//
const videoDescribe = ref({
renderData: renderData.value,
extendsData: [],
mediaType: 'video', // video--image-- 使video 使imageimagUrl
videoOptions: {
wsURL: 'ws://172.26.3.60:80/rtspoverwebsocket', // webSocket
rtspURL:
'rtsp://admin:luxiaole2021@172.26.3.60:80/cam/realmonitor?channel=1&subtype=0&proto=Private3', // RTSP
username: 'admin', //
password: 'luxiaole2021', //
},
version: '1.0',
});
//
const imageDescribe = ref({
renderData: renderData.value,
extendsData: [],
mediaType: 'image', // video--image-- 使video 使imageimagUrl
imagUrl: './test.png', // url base64
// imagUrl: 'http://175.27.168.120:6013/test/4b90d8ca-390e-4320-a29b-0a879733f36d/69c91c81-5267-45f9-b8c2-fb77808c14fe/DJI_202508151432_002_69c91c81-5267-45f9-b8c2-fb77808c14fe/DJI_20250815143510_0035_V.jpeg',
version: '1.0',
});
const demoInit = () => {
console.log(videoRef.value);
videoWidth.value = videoRef.value.offsetWidth; // video
demo.value = new SmartJS({
options: {
configId: 'config', // configid
videoId: 'video', // videoid
mediaType: 'image', // video--image-- 使video 使imageimagUrl
containerStyle: {
// config100%
height: '580px',
},
videoStyle: {
// video
height: '635px',
width: `${videoWidth.value}px`,
},
lang: 'zh', // zh: en: zh-HK:
},
/*设置变化时对外的回调函数*/
callback: function (json) {
// json
// 使VideoAnalyseGlobalVideoAnalyseModuleRuleObj
// console.log(JSON.stringify(json, undefined, 2));
},
callMethods: {
uploadPicture: (imageBase64) => {
console.log('imageBase64', imageBase64);
let url = 'http://172.23.222.103/XXXXX';
return Promise.resolve(url);
},
getPicUrl: (url) => {
console.log('url', url);
let webUrl = 'http://172.23.222.103/XXXXX';
return Promise.resolve(webUrl);
},
},
});
};
/* 校验是否必填函数 */
function startCheck() {
console.log('check', demo.checkValue());
const { checkResult, errorConfig } = demo.checkValue();
if (!checkResult) {
alert(`${errorConfig}未设置值,请检查`);
}
}
onMounted(async () => {
demoInit();
// demo.render(videoDescribe.value);//
demo.value.render(imageDescribe.value); //
const token =
'API32_HENJOZMPBYKEXNVLFMY3Y5W5SQ.1751622229582.fmCjIucQYyq4YZe4CnSStN/rHcwjZTxUsDuXeXJfrYn0bwoaV1/IW8mcFwtLw8JHjowvMJrmPyy/QZAhssxQCQ==';
const status = await liveStreamPlugin.initSDK(token);
@ -58,3 +412,26 @@
}
});
</script>
<style lang="scss" scoped>
.common_div {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
height: 695px;
}
.view {
width: 61%;
height: 640px;
}
.config {
border: #e2e2e2 solid 1px;
height: 640px;
width: 34.5%;
}
.check {
position: fixed;
bottom: 200px;
right: 200px;
}
</style>

@ -0,0 +1,189 @@
<template>
<div>
<div v-for="item in list" :key="item.algorithmCode">
<a-button @click="getConfigData(item)">
{{ item.algorithmName }}
</a-button>
</div>
<div style="margin: 20px 0 0 30px">大华算法实例</div>
<a-button class="check" @click="startCheck()"></a-button>
<div class="common_div">
<div class="view" id="video" ref="videoRef"></div>
<div class="config" id="config"></div>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import { getsupportList, getconfig, createTasks } from '@/api/workmanagement/dahua';
import { buildGUID, uuid } from '@/utils/uuid';
const list = ref([]);
const selectItem = ref({});
const getList = () => {
getsupportList({
page: 1,
limit: 10,
}).then((res) => {
const data = JSON.parse(res);
list.value = data.data.results;
});
};
const videoRef = ref<HTMLDivElement | null>(null);
const demo = ref();
let videoWidth = ref(0); // video
const renderData = ref([
{ tab: '全局配置', data: [] },
{ tab: '模块配置', data: [] },
{ tab: '规则配置', data: [] },
]);
//
const videoDescribe = ref({
renderData: renderData.value,
extendsData: [],
mediaType: 'video', // video--image-- 使video 使imageimagUrl
videoOptions: {
wsURL: 'ws://172.26.3.60:80/rtspoverwebsocket', // webSocket
rtspURL: 'rtsp://box.wisestcity.com:9554/live/test', // RTSP
username: 'admin', //
password: 'luxiaole2021', //
},
version: '1.0',
});
//
const imageDescribe = ref({
renderData: renderData.value,
extendsData: [],
mediaType: 'image', // video--image-- 使video 使imageimagUrl
imagUrl: './test.png', // url base64
// imagUrl: 'http://175.27.168.120:6013/test/4b90d8ca-390e-4320-a29b-0a879733f36d/69c91c81-5267-45f9-b8c2-fb77808c14fe/DJI_202508151432_002_69c91c81-5267-45f9-b8c2-fb77808c14fe/DJI_20250815143510_0035_V.jpeg',
version: '1.0',
});
const demoInit = () => {
console.log(videoRef.value);
videoWidth.value = videoRef.value.offsetWidth; // video
demo.value = new SmartJS({
options: {
configId: 'config', // configid
videoId: 'video', // videoid
mediaType: 'image', // video--image-- 使video 使imageimagUrl
containerStyle: {
// config100%
height: '580px',
},
videoStyle: {
// video
height: '635px',
width: `${videoWidth.value}px`,
},
lang: 'zh', // zh: en: zh-HK:
},
/*设置变化时对外的回调函数*/
callback: function (json) {
// json
// 使VideoAnalyseGlobalVideoAnalyseModuleRuleObj
// console.log(JSON.stringify(json, undefined, 2));
},
callMethods: {
uploadPicture: (imageBase64) => {
console.log('imageBase64', imageBase64);
let url = 'http://172.23.222.103/XXXXX';
return Promise.resolve(url);
},
getPicUrl: (url) => {
console.log('url', url);
let webUrl = 'http://172.23.222.103/XXXXX';
return Promise.resolve(webUrl);
},
},
});
};
/* 校验是否必填函数 */
function startCheck() {
//
console.log('check', demo.value.checkValue());
const { checkResult, errorConfig } = demo.value.checkValue();
if (!checkResult) {
alert(`${errorConfig}未设置值,请检查`);
}
const querys = {
channelId: buildGUID(),
analysisType: 0,
url: 'rtsp://box.wisestcity.com:9554/live/test',
//
config: JSON.stringify(demo.value.getValue()),
//
algorithms: [
{
name: selectItem.value.algorithmName,
edition: selectItem.value.version,
algorithmClass: selectItem.value.algorithmClass,
rule: selectItem.value.rule,
ruleType: selectItem.value.ruleType,
},
],
};
console.log('querys', querys);
}
const getConfigData = (item) => {
selectItem.value = item;
getconfig({
version: item.version,
functionType: item.functionType,
algorithmCode: item.algorithmCode,
}).then((res) => {
const data = JSON.parse(res);
console.log('data', data);
data.data.forEach((element) => {
if (element.isdType === 'global') {
const obj = JSON.parse(element.isdConfig);
renderData.value[0].data = [
{
profile: obj,
},
];
} else if (element.isdType === 'module') {
const obj = JSON.parse(element.isdConfig);
renderData.value[1].data = [
{
profile: obj,
},
];
} else if (element.isdType === 'rule') {
const obj = JSON.parse(element.isdConfig);
renderData.value[2].data = [
{
profile: obj,
},
];
}
});
demoInit();
demo.value.render(imageDescribe.value); //
});
};
onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
.common_div {
width: 100%;
padding: 20px;
display: flex;
justify-content: space-between;
height: 695px;
}
.view {
width: 61%;
height: 640px;
}
.config {
border: #e2e2e2 solid 1px;
height: 640px;
width: 34.5%;
}
</style>

@ -251,7 +251,7 @@
<style lang="less" scoped>
.airport-information {
position: absolute;
top: 360px;
top: 380px;
left: 0;
width: 260px;
padding: 10px;

@ -0,0 +1,5 @@
export { default as SelectComponent } from './src/SelectComponent.vue';
export { default as StatisticsComponent } from './src/StatisticsComponent.vue';
export { default as VideoStreamComponent } from './src/VideoStreamComponent.vue';
export { default as Map } from '../workplan/components/map.vue';

@ -0,0 +1,72 @@
<template>
<div class="inspection-container">
<div class="inspection-header">
<SelectComponent />
<div class="inspection-header-desc">
<div class="inspection-header-desc-item">
<!-- <a-badge status="success" text="Success" /> -->
<a-badge status="error" />
状态<span>未连接</span>
</div>
<div class="inspection-header-desc-item"> FPS:<span>123</span> </div>
<div class="inspection-header-desc-item"> 总帧数:<span>123</span> </div>
<div class="inspection-header-desc-item"> 监测目标数:<span>123</span> </div>
</div>
</div>
<div class="inspection-content">
<div class="inspection-content-left">
<StatisticsComponent />
</div>
<div class="inspection-content-right">
<VideoStreamComponent />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { SelectComponent, StatisticsComponent, VideoStreamComponent } from './index';
</script>
<style lang="scss" scoped>
.inspection-container {
height: 100%;
width: 100%;
background: #0d2136;
overflow: hidden;
.inspection-header {
margin: 10px;
height: 60px;
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #25436c 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
border: 1px solid rgba(38, 67, 111, 1);
backdrop-filter: blur(3.62969752520624px);
display: flex;
align-items: center;
justify-content: space-between;
.inspection-header-desc {
color: #fff;
display: flex;
align-items: center;
margin-right: 10px;
.inspection-header-desc-item {
width: 132px;
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border: 1px solid #0377f6;
padding: 8px 0 8px 10px;
span {
font-weight: 500;
}
}
.inspection-header-desc-item:first-child {
border-radius: 20px 0px 0px 20px;
}
}
}
.inspection-content {
display: flex;
}
.inspection-content-left {
width: 69%;
}
}
</style>

@ -0,0 +1,185 @@
<template>
<div class="flightoperation-top">
<div class="select-item">
<img src="@/assets/images/flightoperation/project.png" alt="" />
<a-select
ref="select"
v-model:value="selectVal.project"
style="width: 120px"
:options="optionsArr.projectOptions"
placeholder="项目选择"
@change="handlePojectChange"
/>
</div>
<div class="select-item">
<img src="@/assets/images/flightoperation/airport.png" alt="" />
<a-select
ref="select"
v-model:value="selectVal.airport"
style="width: 120px"
:options="optionsArr.airportOptions"
placeholder="机场选择"
@change="handleAirPortChange"
/>
</div>
<div class="select-item">
<img src="@/assets/images/flightoperation/equipment.png" alt="" />
<a-select
ref="select"
v-model:value="selectVal.equipment"
style="width: 120px"
:options="optionsArr.equipmentOptions"
placeholder="飞行器选择"
@change="handleChange"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, onMounted } from 'vue';
import { GetWorkspaceList, GetWorkSpaceById, GetUavPageByDocksn } from '@/api/demo/projecthome';
import { airPortStore } from '@/store/modules/airport';
const airPortStoreVal = airPortStore();
const emits = defineEmits(['selectChange']);
const selectVal = reactive({
project: null,
equipment: null,
airport: null,
gateway: null,
});
const optionsArr = reactive({
projectOptions: [],
equipmentOptions: [],
airportOptions: [],
});
const handleChange = () => {
airPortStoreVal.setAirPort('sn', selectVal.airport);
airPortStoreVal.setUAV('sn', selectVal.equipment);
airPortStoreVal.setGateway(selectVal.gateway);
emits('selectChange', selectVal);
};
//
const getProjectList = async () => {
GetWorkspaceList().then((res) => {
if (res.length > 0) {
optionsArr.projectOptions = res.map((item) => {
return {
label: item.WorkspaceName,
value: item.Id,
};
});
if (sessionStorage.getItem('homeToFlightId')) {
selectVal.project = sessionStorage.getItem('homeToFlightId');
sessionStorage.removeItem('homeToFlightId');
} else {
selectVal.project = optionsArr.projectOptions[0].value;
}
getAirPort(selectVal.project);
} else {
optionsArr.projectOptions = [];
selectVal.project = null;
getAirPort(selectVal.project);
}
});
};
const handlePojectChange = (val) => {
getAirPort(val);
};
//
const getAirPort = (id) => {
let params = {
id: id,
};
GetWorkSpaceById(params).then((res) => {
if (res.lasaDronePort.length > 0) {
optionsArr.airportOptions = res.lasaDronePort.map((item) => {
return {
label: item.name,
value: item.sn,
};
});
selectVal.airport = optionsArr.airportOptions[0].value;
getUAV(selectVal.airport);
} else {
optionsArr.airportOptions = [];
selectVal.airport = null;
optionsArr.equipmentOptions = [];
selectVal.equipment = null;
}
});
};
const handleAirPortChange = (val) => {
getUAV(val);
};
//
const getUAV = (sn) => {
let params = {
sn: sn,
page: 1,
limit: 99,
};
GetUavPageByDocksn(params).then((res) => {
if (res.items.length > 0) {
optionsArr.equipmentOptions = res.items.map((item) => {
return {
label: item.name,
value: item.sn,
gateway: item.gateway,
};
});
selectVal.equipment = optionsArr.equipmentOptions[0].value;
selectVal.gateway = optionsArr.equipmentOptions[0].gateway;
handleChange();
} else {
optionsArr.equipmentOptions = [];
selectVal.equipment = null;
}
});
};
onMounted(() => {
getProjectList();
});
</script>
<style lang="less" scoped>
.flightoperation-top {
display: flex;
}
.select-item {
width: 160px;
height: 38px;
margin-left: 10px;
background: #3a57e8;
border-radius: 4px;
display: flex;
align-items: center;
cursor: pointer;
::v-deep .ant-select-selector {
background: #3a57e8;
border: none;
color: #fff;
.ant-select-selection-placeholder {
color: #fff;
}
}
::v-deep .ant-select-arrow {
color: #fff;
}
img {
width: 20px;
margin-left: 10px;
}
}
.select-item:nth-child(2) {
background: #08b1ba;
::v-deep .ant-select-selector {
background: #08b1ba;
}
}
.select-item:nth-child(3) {
background: #1aa053;
::v-deep .ant-select-selector {
background: #1aa053;
}
}
</style>

@ -0,0 +1,117 @@
<template>
<div class="statistics-container">
<div class="statistics-header">
<div id="main"> </div>
</div>
<div class="map-container">
<div class="map-container-content">
<Map />
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { onMounted } from 'vue';
import * as echarts from 'echarts';
import { Map } from '../index';
const initChart = () => {
var chartDom = document.getElementById('main');
var myChart = echarts.init(chartDom);
var option;
let date = [];
let data = [Math.random() * 300];
for (let i = 1; i < 40; i++) {
date.push(i);
data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));
}
option = {
tooltip: {
trigger: 'axis',
position: function (pt) {
return [pt[0], '10%'];
},
},
legend: {
top: '10',
right: '20',
textStyle: {
color: '#fff',
},
},
title: {
left: '10',
top: '10',
text: '目标检测统计',
textStyle: {
color: '#fff',
fontsize: '12',
},
},
xAxis: {
type: 'category',
boundaryGap: false,
data: date,
},
yAxis: {
type: 'value',
boundaryGap: [0, '100%'],
},
series: [
{
name: '监测目标数量',
type: 'line',
symbol: 'none',
sampling: 'lttb',
itemStyle: {
color: 'rgb(255, 172, 80)',
},
areaStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 0,
color: 'rgb(255, 172, 80, 0.8)',
},
{
offset: 1,
color: 'rgb(255, 172, 80,0.2)',
},
]),
},
data: data,
},
],
};
option && myChart.setOption(option);
};
onMounted(() => {
initChart();
});
</script>
<style lang="scss" scoped>
.statistics-container {
margin-left: 10px;
.statistics-header {
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #182f4e 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 10px;
backdrop-filter: blur(3.62969752520624px);
#main {
height: 400px;
}
}
}
::v-deep canvas {
border-radius: 10px;
}
.map-container {
height: 380px;
}
.map-container-content {
margin-top: 10px;
height: 100%;
}
</style>

@ -0,0 +1,93 @@
<template>
<div class="video-stream-container">
<div class="original-video">
<div class="title">
<VideoCameraOutlined />
原始视频流
</div>
<div class="player">
<video
id="player-container-original-live"
width="480"
height="340"
preload="auto"
playsinline
webkit-playsinline
>
</video>
</div>
</div>
<div class="testing-video">
<div class="title">
<VideoCameraOutlined />
检测后视频流
</div>
<div class="player">
<video
id="player-container-testing-live"
width="480"
height="340"
preload="auto"
playsinline
webkit-playsinline
>
</video>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import TCPlayer from 'tcplayer.js';
import 'tcplayer.js/dist/tcplayer.min.css'; //
import { airPortStore } from '@/store/modules/airport';
import { ref } from 'vue';
import { VideoCameraOutlined } from '@ant-design/icons-vue';
const airPortStoreVal = airPortStore();
const live_info = airPortStoreVal.getLiveInfo;
let player;
const liveCode = ref('7');
const playVideo = () => {
player = TCPlayer('player-container-original-live', {
sources: [
{
src: live_info.url + liveCode.value + '.flv', //
},
],
licenseUrl: live_info.url + liveCode.value + '.flv', // license license licenseUrl
});
};
</script>
<style lang="scss" scoped>
.video-stream-container {
width: 500px;
margin-left: 20px;
.original-video {
height: 380px;
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #182f4e 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 6px;
backdrop-filter: blur(3.62969752520624px);
}
.testing-video {
margin-top: 10px;
height: 380px;
background: linear-gradient(180deg, rgba(13, 25, 45, 0.87) 0%, #182f4e 100%);
box-shadow: 0px 10px 30px 0px rgba(0, 0, 6, 0.15);
border-radius: 6px;
backdrop-filter: blur(3.62969752520624px);
}
.title {
color: #fff;
padding: 10px 0;
margin: 0 20px;
border-bottom: 1px solid #4e5778;
}
.player{
video{
margin-left: 10px;
}
}
}
</style>
Loading…
Cancel
Save