底部导航默认选中项,案件详情多图片处理

main
徐景良 2025-04-24 09:20:42 +08:00
commit 19b2109c57
62 changed files with 3073 additions and 1479 deletions

View File

@ -16,7 +16,7 @@ VITE_GLOB_INFO_IMAGE_URL=http://120.222.154.48:6050
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_APP_TITLE = 林业防火平台
VITE_GLOB_APP_TITLE = 费县智慧林业防火平台
VITE_GLOB_APP_LOGO = /logo.png

View File

@ -12,19 +12,19 @@ VITE_BUILD_COMPRESS = 'none'
# Basic interface address SPA
# 天空地项目
VITE_GLOB_API_URL=http://120.222.154.7:6050
VITE_GLOB_API_URL=http://192.168.10.163:9620
VITE_GLOB_INFO_IMAGE_URL=http://120.222.154.48:6050
VITE_GLOB_INFO_IMAGE_URL=http://192.168.10.163:9620
# File upload address optional
# It can be forwarded by nginx or write the actual address directly
VITE_GLOB_UPLOAD_URL=http://120.222.154.7:6050
VITE_GLOB_UPLOAD_URL=http://192.168.10.163:9620
# Interface prefix
VITE_GLOB_API_URL_PREFIX=
VITE_GLOB_APP_TITLE = 林业防火平台
VITE_GLOB_APP_TITLE = 费县智慧林业防火平台
VITE_GLOB_APP_LOGO = /logo.png

View File

@ -18,6 +18,10 @@
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/flv.min.1.6.3.js"></script>
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/libs/dash.all.min.4.4.1.js"></script>
<script src="https://web.sdk.qcloud.com/player/tcplayer/release/v4.6.0/tcplayer.v4.6.0.min.js"></script>
<!-- 引入海康插件内容 -->
<script type="text/javascript" src="./public/monitor/hk/jquery-1.12.4.min.js"></script>
<script type="text/javascript" src="./public/monitor/hk/jsencrypt.min.js"></script>
<script type="text/javascript" src="./public/monitor/hk/jsWebControl-1.0.0.min.js"></script>
<style>
.mars3d-template-content{

View File

@ -118,6 +118,7 @@
"iconify-icon": "^1.0.8",
"js-base64": "3.7.7",
"js-md5": "^0.8.3",
"jsencrypt": "^3.3.2",
"jszip": "^3.10.1",
"keymaster": "^1.6.2",
"lodash-es": "^4.17.21",

View File

@ -1,145 +0,0 @@
.flex{
display: flex;
}
.flex-1{
flex: 1;
}
.wrap{
flex-wrap: wrap;
}
.nowrap{
flex-wrap: nowrap;
white-space: nowrap;
}
.row{
flex-direction: row;
}
.column{
flex-direction: column;
}
.hidden{
overflow: hidden;
}
.auto{
overflow: auto;
}
.ai-c{
align-items: center;
}
.ai-e{
align-items: end;
}
.jc-se{
justify-content: space-evenly;
}
.jc-sa{
justify-content: space-around;
}
.jc-sb{
justify-content: space-between;
}
.jc-c{
justify-content: center;
}
.jc-e{
justify-content: flex-end;
}
.mt-1{
margin-top: 10px;
}
.mt-2{
margin-top: 20px;
}
.mt-3{
margin-top: 30px;
}
.ml-1{
margin-left: 10px;
}
.ml-2{
margin-left: 20px;
}
.ml-3{
margin-left: 30px;
}
.mb-1{
margin-bottom: 10px;
}
.mb-2{
margin-bottom: 20px;
}
.mb-3{
margin-bottom: 30px;
}
.mr-1{
margin-right: 10px;
}
.mr-2{
margin-right: 20px;
}
.mr-3{
margin-right: 30px;
}
.ta-c{
text-align: center;
}
.ta-l{
text-align: left;
}
.cursor{
cursor: pointer;
}
.pos-r{
position: relative;
}
.pos-a{
position: absolute;
}
.pos-f{
position: fixed;
}
.max-w{
width: 100%;
}
.max-h{
height: 100%;
}
.fz-12{
font-size: 12px;
}
.fz-14{
font-size: 14px;
}
.fz-16{
font-size: 16px;
}
.fz-18{
font-size: 18px;
}
.fz-20{
font-size: 20px;
}
.fz-22{
font-size: 22px;
}
.fz-24{
font-size: 24px;
}
.fz-26{
font-size: 26px;
}
.fz-28{
font-size: 28px;
}
.fc-w{
color: white;
}
.fc-b{
color: black;
}
.fc-r{
color: red;
}
.fw-b{
font-weight: bold;
}

View File

@ -1,359 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>preview_demo</title>
</head>
<style>
html, body {
padding: 0;
margin: 0;
}
.camera-box{
width: 1200px;
height: 700px;
border-radius: 5px;
position: relative;
z-index:100000000000000000000000000000000!important;
position: fixed;
left: 50%;
top: 50%;
z-index: 9999;
transform: translate(-50%,-50%);
padding:0px;
}
.playWnd {
width: 1200px; /*播放容器的宽和高设定*/
height: 700px;
}
</style>
<body>
<div class="camera-box">
<!-- 视口区域 -->
<div class="camera-body">
<div id="playWnd" class="playWnd"></div>
</div>
</div>
</body>
<!--三个必要的js文件引入-->
<script src="jquery-1.12.4.min.js"></script>
<script src="jsencrypt.min.js"></script> <!-- 用于RSA加密 -->
<script src="jsWebControl-1.0.0.min.js"></script> <!-- 用于前端与插件交互 -->
<script type="text/javascript">
let carmerCard = "";
// 窗口加载结束事件
window.onload = () => {
// 子页面接收消息
window.addEventListener('message', function (e) {
if (e.data) {
carmerCard = e.data[1]
$("#carmerName").text(e.data[0]) // 设备名称
$("#carmerCard").text(e.data[1]) // 设备编号
$("#carmerAppKey").text(e.data[2])// appkey
$("#carmerIp").text(e.data[3]) // 设备ip
$("#carmerPort").text(e.data[4]) // 网络端口
$("#appSecret").text(e.data[5]) // 秘钥
}
}, false)
// 创建视频播放插件
initPlugin();
}
// 关闭按钮 调用父页面的关闭函数
$("#closeBtn").click(function(){
window.parent.postMessage(
{
cmd: 'close'
}
)
})
//声明公用变量
var initCount = 0;
var pubKey = '';
// 创建播放器方法实例
function initPlugin () {
oWebControl = new WebControl({
szPluginContainer: "playWnd", // 指定容器id
iServicePortStart: 15900, // 指定起止端口号,建议使用该值
iServicePortEnd: 15909,
szClassId:"23BF3B0A-2C56-4D97-9C03-0CB103AA8F11", // 用于IE10使用ActiveX的clsid
cbConnectSuccess: function () { // 创建WebControl实例成功后的回调函数
oWebControl.JS_StartService("window", { // WebControl实例创建成功后需要启动VideoPluginPlugin.exe服务
dllPath: "./VideoPluginConnect.dll" // 值"./VideoPluginConnect.dll"写死
}).then(function () { // 启动插件服务成功
oWebControl.JS_SetWindowControlCallback({ // 设置消息回调
cbIntegrationCallBack: cbIntegrationCallBack
});
oWebControl.JS_CreateWnd("playWnd", 1200, 700).then(function () { //JS_CreateWnd创建视频播放窗口宽高可设定
init(); // 创建播放实例成功后初始化
});
}, function () { // 创建播放实例失败回调
console.log("创建播放实例失败!!!");
});
},
cbConnectError: function () { // 创建WebControl实例失败
oWebControl = null;
$("#playWnd").html("插件未启动,正在尝试启动,请稍候...");
WebControl.JS_WakeUp("VideoWebPlugin://"); // 程序未启动时执行error函数采用wakeup来启动程序
initCount ++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000)
} else {
$("#playWnd").html("插件启动失败,请检查插件是否安装!");
}
},
cbConnectClose: function (bNormalClose) {
// 异常断开bNormalClose = false
// JS_Disconnect正常断开bNormalClose = true
oWebControl = null;
}
});
}
// 设置窗口控制回调
function setCallbacks() {
oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: cbIntegrationCallBack
});
}
// 推送消息
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
//初始化播放内容
function init()
{
getPubKey(function () {
////////////////////////////////// 请自行修改以下变量值 ////////////////////////////////////
// var appkey = "21274765"; //综合安防管理平台提供的appkey必填
// var ip = "223.99.16.253"; //综合安防管理平台IP地址必填
// var port = 1443; //综合安防管理平台端口若启用HTTPS协议默认443
var appkey = "23604396"; //综合安防管理平台提供的appkey必填
var ip = "221.2.83.54"; //综合安防管理平台IP地址必填
var port = 1443;
var appSecret = "NZJ8L3bxCOOV6rtTFjsx";
var secret = setEncrypt(appSecret); //综合安防管理平台提供的secret必填
let cameraCount = carmerCard.split(",").length;
let layerOut = "1x1";
if(cameraCount<=1){
layerOut = "1x1";
}else if(cameraCount>1 && cameraCount<=4){
layerOut = "2x2";
}else if(cameraCount>4 && cameraCount<=9){
layerOut = "3x3";
}else if(cameraCount>9 && cameraCount<=16){
layerOut = "4x4";
}else if(cameraCount>16 && cameraCount<=25){
layerOut = "5x5";
}
var playMode = 0; //初始播放模式0-预览1-回放
var snapDir = "D:\\SnapDir"; //抓图存储路径
var videoDir = "D:\\VideoDir"; //紧急录像或录像剪辑存储路径
var layout = layerOut; //playMode指定模式的布局 默认1*1
var enableHTTPS = 1; //是否启用HTTPS协议与综合安防管理平台交互这里总是填1
var encryptedFields = 'secret'; //加密字段默认加密领域为secret
var showToolbar = 1; //是否显示工具栏0-不显示非0-显示
var showSmart = 1; //是否显示智能信息如配置移动侦测后画面上的线框0-不显示非0-显示
var buttonIDs = "0,16,256,257,258,259,260,512,513,514,515,516,517,768,769"; //自定义工具条按钮
////////////////////////////////// 请自行修改以上变量值 ////////////////////////////////////
oWebControl.JS_RequestInterface({
funcName: "init",
argument: JSON.stringify({
appkey: appkey, //API网关提供的appkey
secret: secret, //API网关提供的secret
ip: ip, //API网关IP地址
playMode: playMode, //播放模式(决定显示预览还是回放界面)
port: port, //端口
snapDir: snapDir, //抓图存储路径
videoDir: videoDir, //紧急录像或录像剪辑存储路径
layout: layout, //布局
enableHTTPS: enableHTTPS, //是否启用HTTPS协议
encryptedFields: encryptedFields, //加密字段
showToolbar: showToolbar, //是否显示工具栏
showSmart: showSmart, //是否显示智能信息
buttonIDs: buttonIDs //自定义工具条按钮
})
}).then(function (oData) {
oWebControl.JS_Resize(1200, 700); // 初始化后resize一次规避firefox下首次显示窗口后插件窗口未与DIV窗口重合问题
setWndCover();
});
var cameraIndexCode = carmerCard; //获取输入的监控点编号值,必填
var streamMode = 0; //主子码流标识0-主码流1-子码流
var transMode = 1; //传输协议0-UDP1-TCP
var gpuMode = 0; //是否启用GPU硬解0-不启用1-启用
var wndId = -1; //播放窗口序号在2x2以上布局下可指定播放窗口
// 封装传入需要播放的监控信息
let monitors = {list:[]};
var cameraIndexCodes = cameraIndexCode.split(",")
cameraIndexCodes.forEach((item,index)=>{
let obj = {
cameraIndexCode:item, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId:index+1 //可指定播放窗口
}
monitors.list.push(obj);
})
// 开始预览多个视频
oWebControl.JS_RequestInterface({
funcName: "startMultiPreviewByCameraIndexCode",
argument: JSON.stringify(monitors)
})
});
}
//获取公钥
function getPubKey (callback) {
oWebControl.JS_RequestInterface({
funcName: "getRSAPubKey",
argument: JSON.stringify({
keyLength: 1024
})
}).then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback()
}
})
}
//RSA加密
function setEncrypt (value) {
var encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
// 监听resize事件使插件窗口尺寸跟随DIV窗口变化
$(window).resize(function (event) {
console.log(event);
if (oWebControl != null) {
oWebControl.JS_Resize(1200, 700);
setWndCover();
}
});
// 监听滚动条scroll事件使插件窗口跟随浏览器滚动而移动
$(window).scroll(function () {
if (oWebControl != null) {
oWebControl.JS_Resize(360, 230);
setWndCover();
}
});
// 设置窗口裁剪当因滚动条滚动导致窗口需要被遮住的情况下需要JS_CuttingPartWindow部分窗口
function setWndCover() {
var iWidth = $(window).width();
var iHeight = $(window).height();
var oDivRect = $("#playWnd").get(0).getBoundingClientRect();
var iCoverLeft = (oDivRect.left < 0) ? Math.abs(oDivRect.left): 0;
var iCoverTop = (oDivRect.top < 0) ? Math.abs(oDivRect.top): 0;
var iCoverRight = (oDivRect.right - iWidth > 0) ? Math.round(oDivRect.right - iWidth) : 0;
var iCoverBottom = (oDivRect.bottom - iHeight > 0) ? Math.round(oDivRect.bottom - iHeight) : 0;
iCoverLeft = (iCoverLeft > 360) ? 360 : iCoverLeft;
iCoverTop = (iCoverTop > 230) ? 230 : iCoverTop;
iCoverRight = (iCoverRight > 360) ? 360 : iCoverRight;
iCoverBottom = (iCoverBottom > 230) ? 230 : iCoverBottom;
oWebControl.JS_RepairPartWindow(0, 0, 1001, 230); // 多1个像素点防止还原后边界缺失一个像素条
if (iCoverLeft != 0) {
oWebControl.JS_CuttingPartWindow(0, 0, iCoverLeft, 230);
}
if (iCoverTop != 0) {
oWebControl.JS_CuttingPartWindow(0, 0, 1001, iCoverTop); // 多剪掉一个像素条,防止出现剪掉一部分窗口后出现一个像素条
}
if (iCoverRight != 0) {
oWebControl.JS_CuttingPartWindow(360 - iCoverRight, 0, iCoverRight, 230);
}
if (iCoverBottom != 0) {
oWebControl.JS_CuttingPartWindow(0, 230 - iCoverBottom, 360, iCoverBottom);
}
}
//视频预览功能
$("#startPreview").click(function () {
var cameraIndexCode = cameraIndexCode; //获取输入的监控点编号值,必填
var streamMode = 0; //主子码流标识0-主码流1-子码流
var transMode = 1; //传输协议0-UDP1-TCP
var gpuMode = 0; //是否启用GPU硬解0-不启用1-启用
var wndId = -1; //播放窗口序号在2x2以上布局下可指定播放窗口
cameraIndexCode = cameraIndexCode.replace(/(^\s*)/g, "");
cameraIndexCode = cameraIndexCode.replace(/(\s*$)/g, "");
oWebControl.JS_RequestInterface({
funcName: "startPreview",
argument: JSON.stringify({
cameraIndexCode:cameraIndexCode, //监控点编号
streamMode: streamMode, //主子码流标识
transMode: transMode, //传输协议
gpuMode: gpuMode, //是否开启GPU硬解
wndId:wndId //可指定播放窗口
})
})
});
//停止全部预览
$("#stopAllPreview").click(function () {
oWebControl.JS_RequestInterface({
funcName: "stopAllPreview"
});
});
// 标签关闭
$(window).unload(function () {
if (oWebControl != null){
oWebControl.JS_HideWnd(); // 先让窗口隐藏,规避可能的插件窗口滞后于浏览器消失问题
oWebControl.JS_Disconnect().then(function(){ // 断开与插件服务连接成功
},
function() { // 断开与插件服务连接失败
});
}
});
</script>
<!--
-->
</html>

View File

@ -1,6 +1,10 @@
import { defHttp } from '@/utils/http/axios';
import { TableDataByTableNameParams, TempeleteByTableNameParams } from './model/index';
import {
TableDataByTableNameParams,
TempeleteByTableNameParams,
UploadSldStyleParams,
} from './model/index';
enum Api {
// 获取列表数据
@ -9,6 +13,8 @@ enum Api {
TempeleteByTableName = '/api/Layer/TempeleteByTableName',
// 更新单条数据
UpdateTableData = '/api/Layer/UpdateTableData',
// 上传样式
UploadSldStyle = '/api/Layer/UploadSldStyle',
}
/**
* @description:
@ -27,11 +33,20 @@ export function updateTableData(params: any) {
});
}
/**
* @description:
* @description:
*/
export function tempeleteByTableName(params: TempeleteByTableNameParams) {
return defHttp.post({
return defHttp.get({
url: Api.TempeleteByTableName,
params,
});
}
/**
* @description:
*/
export function uploadSldStyle(params: UploadSldStyleParams) {
return defHttp.get({
url: Api.UploadSldStyle,
params,
});
}

View File

@ -30,4 +30,11 @@ export interface TableDataByTableNameParams {
}
export interface TempeleteByTableNameParams {
tablename: string;
type: number;
}
export interface UploadSldStyleParams {
filepath: string;
tablename: string;
styleName: string;
}

View File

@ -80,16 +80,25 @@ export const eventCommonHandler = (
for (let k = 0; k < elementList[j].elementId.length; k++) {
//获取位置
const arr = queryFun(componentList, elementList[j].elementId[k]);
console.log(arr);
// console.log(arr);
if (arr.length > 1) {
obj = componentList[arr[0]].groupList[arr[1]];
obj.status.hide = false;
console.log(obj);
// console.log(obj);
// chartEditStore.updateComponentList(arr[0], obj, arr[1]);
} else if (arr.length == 1) {
obj = componentList[arr[0]];
obj.status.hide = false;
console.log(obj);
// console.log(obj);
// 海康视频组件单独处理
if(obj.isGroup && obj.groupList.some((li) => li.key == 'ZhiGan_ModalVideo')) {
obj.groupList.forEach((g) => {
if(g.key == 'ZhiGan_ModalVideo'){
g.status.hide = false;
}
});
}
// chartEditStore.updateComponentList(arr[0], obj);
}
// if (componentList[i].id == elementList[j].elementId[k]) {
@ -103,7 +112,7 @@ export const eventCommonHandler = (
// 隐藏
for (let k = 0; k < elementList[j].elementId.length; k++) {
//获取位置
const arr = queryFun(componentList, elementList[j].elementId[k]);
const arr = queryFun(componentList, elementList[j].elementId[k]);
if (arr.length > 1) {
obj = componentList[arr[0]].groupList[arr[1]];
obj.status.hide = true;
@ -111,6 +120,15 @@ export const eventCommonHandler = (
} else if (arr.length == 1) {
obj = componentList[arr[0]];
obj.status.hide = true;
// 海康视频组件单独处理
if(obj.isGroup && obj.groupList.some((li) => li.key == 'ZhiGan_ModalVideo')) {
obj.groupList.forEach((g) => {
if(g.key == 'ZhiGan_ModalVideo'){
g.status.hide = true;
}
});
}
// chartEditStore.updateComponentList(arr[0], obj);
}
// if (componentList[i].id == elementList[j].elementId[k]) {
@ -178,8 +196,17 @@ export const eventCommonHandler = (
} = elementList[j].callBackRequest;
// 处理头部
let headers: RequestParamsObjType = Object.fromEntries(requestParams.Header.map(item => [item.key, item.value]));
// headers['X-Token'] = localStorage.getItem('X-Token');
let headers: RequestParamsObjType = Object.fromEntries(requestParams.Header.map(item => [item.key.toLowerCase(), item.value]));
if(!headers['x-token']){
headers['x-token'] = localStorage.getItem('X-Token');
}
// 清除掉空项
for (const key in headers) {
if (key === "") {
delete headers[key];
}
}
// params 参数
let params: RequestParamsObjType = Object.fromEntries(requestParams.Params.map(item => [item.key, item.value]));
@ -200,7 +227,6 @@ export const eventCommonHandler = (
console.log(error);
window['$message'].error('URL地址格式有误');
}
}
}
}

View File

@ -5,7 +5,7 @@ import { Titles01Config } from './index'
import cloneDeep from 'lodash/cloneDeep'
export const option = {
borderTitle: '费县林业防火平台',
borderTitle: '费县智慧林业防火平台',
borderTitleWidth: 1920,
borderTitleHeight: 98,
borderTitleSize: 18,

View File

@ -9,7 +9,6 @@ const INPUT_TIP_URL = "https://restapi.amap.com/v3/assistant/inputtips";
const RE_GEO_URL = "https://restapi.amap.com/v3/geocode/regeo";
const GD_KEY = "6af6a87038f44c8c793aa70331f2b7ca";
// const GD_KEY = "8599882c8059403539cd882a8a6e64d0";
// 起点、沿途、不包含的沿途、终点,光点的颜色
export const wayColorList = {

View File

@ -2,7 +2,7 @@
<CollapseItem name="默认方法设置" :expanded="true">
<n-space>
<n-switch v-model:value="optionData.dataStyle.defaultCloseModal" size="small" />
<n-text>默认点击隐藏火情详情弹窗及其所在分组的内容</n-text>
<n-text>默认点击隐藏弹窗及其所在分组的内容</n-text>
</n-space>
</CollapseItem>
<CollapseItem name="按钮设置" :expanded="true">

View File

@ -733,9 +733,10 @@
pitch: -51.9,
});
}
let endCoor = [118.031528, 35.431473];
//
async function roamLocation(startCoor) {
let endCoor = [118.031528, 35.431473];
let params: any = {
startlng: parseFloat(startCoor[0]),
startlat: parseFloat(startCoor[1]),
@ -758,6 +759,8 @@
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
//
endCoor = [data.lng, data.lat];
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql, { Id: data.id });
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {

View File

@ -20,6 +20,68 @@ export default class Config extends PublicConfigClass implements CreateComponent
public attr = { ...chartInitConfig, w: 121, h: 44, zIndex: 5 }
public chartConfig = cloneDeep(ZhiGan_ModalButtonConfig)
public option = cloneDeep(option)
public request = { ...requestSqlConfig, requestSQLContent: { sql: 'UPDATE fm_fireclueinfo SET "Status" = #{Status} WHERE "Id" = #{Id}' }}
public filter = "return res.result;"
public events = getDeafultEvents();
// public request = { ...requestSqlConfig, requestSQLContent: { sql: 'UPDATE fm_fireclueinfo SET "Status" = #{Status} WHERE "Id" = #{Id}' }}
// public filter = "return res.result;"
}
function getDeafultEvents() {
return {
"baseEvent": {
"click": null,
"dblclick": null,
"mouseenter": null,
"mouseleave": null
},
"advancedEvents": {
"vnodeMounted": null,
"vnodeBeforeMount": null
},
"interactEvents": [],
"interactConfigEvents": [
{
"type": "click",
"movementList": [
{
"movement": "callBackRequest",
"elementId": "",
"callBackRequest": {
"requestUrl": "http://192.168.10.163:9620",
"requestApi": "/api/FireManagement/UpdatFireStateById",
"requestContentType": "",
"requestDataType": 0,
"requestHttpType": "post",
"requestParams": {
"Body": {
"form-data": {},
"x-www-form-urlencoded": {},
"json": "",
"xml": ""
},
"Header": [
{
"key": "",
"value": "",
"error": false
}
],
"Params": [
{
"key": "id",
"value": "{id}",
"error": false
},
{
"key": "state",
"value": "1",
"error": false
}
]
}
}
}
]
}
]
};
}

View File

@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { computed, PropType, toRefs, watch, reactive, ref,onMounted } from 'vue';
import { computed, PropType, toRefs, watch, reactive, ref, onMounted } from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { icon } from '@/plugins';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
@ -16,7 +16,7 @@
import Button from './svg/button.vue';
import { EventBus } from '@/utils/eventBus';
import { replaceSqlParams } from '@/utils/sqlHandler';
const chartEditStore = useChartEditStore();
const props = defineProps({
@ -34,9 +34,9 @@
});
const primary_id = ref(null);
//
const clickBtn = (val) => {
//
eventHandlerHook(
chartEditStore.getComponentList,
@ -45,38 +45,37 @@
val,
);
props.chartConfig?.events?.interactConfigEvents[0]?.movementList?.forEach((item,index)=>{
if(item?.movement == "callBackRequest"){
item.callBackRequest.requestParams.Header = {};
let params = {};
item.callBackRequest.requestParams.Params?.forEach((param,idx)=>{
params[param.key] = param.value
})
params['id'] = primary_id.value;
item.callBackRequest.requestParams.Params = params;
props.chartConfig.request = item.callBackRequest;
props.chartConfig.request.requestDataType = 1;
props.chartConfig.request.requestUrl = item.callBackRequest.requestApi;
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
console.log("resData",resData);
});
}
})
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any) => {
// console.log('resData', resData);
});
};
onMounted(()=>{
onMounted(() => {
// let sql = props.chartConfig.request?.requestSQLContent?.sql;
//
EventBus.on(props.chartConfig.id+'dataupdate', (data) => {
console.log("props.chartConfig.request",props.chartConfig);
primary_id.value = data.id;
});
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
const keys = Object.keys(data);
})
let interactConfigEvents = props.chartConfig.events.interactConfigEvents;
interactConfigEvents.forEach((item, index) => {
item?.movementList.forEach((m, mindex) => {
if (m.movement == 'callBackRequest') {
let Params = m.callBackRequest.requestParams.Params;
Params.forEach((p, pindex) => {
if (keys.includes(p.key)) {
props.chartConfig.events.interactConfigEvents[index].movementList[
mindex
].callBackRequest.requestParams.Params[pindex].value = data[p.key];
}
});
}
});
});
// props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql,{Status:3,Id:data.id});
// props.chartConfig.request.requestParams.Params.id = data.id;
});
});
</script>
<style lang="scss" scoped>

View File

@ -114,7 +114,7 @@
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql, { Id: data.id });
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
option.dataset = resData;
});
});
});

View File

@ -46,6 +46,14 @@
chartEditStore.getComponentList.forEach((element) => {
if (element.isGroup && element?.groupList?.some((li) => li.key == 'ZhiGan_ModalFrame')) {
element.status.hide = true;
//
if (element?.groupList?.some((li) => li.key == 'ZhiGan_ModalVideo')) {
element.groupList.forEach((g) => {
if (g.key == 'ZhiGan_ModalVideo') {
g.status.hide = true;
}
});
}
} else if (element.key == 'ZhiGan_ModalFrame') {
element.status.hide = true;
option.status.hide = true;

View File

@ -62,12 +62,14 @@ export const option = {
videoBorderWidth: 2,
videoBorderColor: '#008000',
videoPadding: 4,
videoTitleFontSize: 12,
videoTitleFontColor: '#ffffff',
},
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = ZhiGan_ModalTimeLineConfig.key
public attr = { ...chartInitConfig, w: 250, h: 450, zIndex: 5 }
public attr = { ...chartInitConfig, w: 350, h: 540, zIndex: 5 }
public chartConfig = cloneDeep(ZhiGan_ModalTimeLineConfig)
public option = cloneDeep(option)
public request = { ...requestSqlConfig, requestSQLContent: { sql: 'select "Title" AS "title","Content" ,"CreateTime" AS "time" from fm_fireclueinfolog where "Fireclueid" = #{Id}' }, }

View File

@ -288,6 +288,20 @@
:options="textAlignOptions"
/>
</SettingItem>
<SettingItem name="视频字体标题颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.videoTitleFontColor"
></n-color-picker>
</SettingItem>
<SettingItem name="视频字体标题大小">
<n-input-number
v-model:value="optionData.dataStyle.videoTitleFontSize"
size="small"
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="视频宽度">
<n-input-number
v-model:value="optionData.dataStyle.videoWidth"

View File

@ -6,7 +6,18 @@
"content": "临沂市山东省辖地级市位于山东省东南部地跨北纬34°2236°13东经117°24119°11之间属温带季风气候四季分明雨热同季地势自北而南有沂山、蒙山、尼山3条主要山脉延伸控制着沂沭河上游及其支流的流向向南构成的扇状临郯苍平原是山东三平原之一。",
"time": "2025-02-11 01:27:14",
"imageurl": [ "/src/assets/images/chart/zhigan/component/ModalCarouselPng01.png", "/src/assets/images/chart/zhigan/component/ModalCarouselPng02.png" ],
"videourl": [ "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv", "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"]
"videos": [
{
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
}
]
},
{
"title":"临沂市",
@ -14,7 +25,11 @@
"content": "",
"time": "2025-02-11 01:27:15",
"imageurl": "/src/assets/images/chart/zhigan/component/ModalCarouselPng03.png",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videos": {
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
}
},
{
"title":"临沂市",

View File

@ -112,94 +112,76 @@
<!-- 视频 -->
<!-- 数组 -->
<div
v-if="Array.isArray(item.videourl) && option.dataStyle.showVideo"
v-if="Array.isArray(item.videos) && option.dataStyle.showVideo"
class="timeLineVideoDivs"
>
<div class="timeLineVideoDiv" v-for="(url, urlindex) in item.videourl" :key="url">
<!-- 编辑状态 -->
<video
v-if="isEdit"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
<div
class="timeLineVideoDiv"
v-for="(videoItem, videoIndex) in item.videos"
:key="videoIndex"
>
<div class="timeLineVideoDivTitle">{{ videoItem.title }}</div>
<n-image
v-if="isEdit || !videoItem.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
src="/src/assets/videos/earth.mp4"
></video>
<!-- 其他情况 -->
<video
v-else
:id="
'ZhiGan_ModalTimeLine' +
item.title +
'-' +
index +
'-' +
urlindex +
'-' +
option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<PlayVideo
v-if="!isEdit && videoItem.videourl && !videoItem.manufacturer"
:videourl="videoItem.videourl"
:index="index + '-' + videoIndex"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
></video>
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
<MulHKmonitor
v-if="!isEdit && videoItem.videourl && videoItem.manufacturer == '海康'"
:index="index + '-' + videoIndex"
:serialNumberValue="videoItem.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:timestamp="option.dataStyle.timestamp"
/>
</div>
</div>
<!-- 单个 -->
<div
v-if="typeof item.videourl === 'string' && option.dataStyle.showVideo"
v-if="!Array.isArray(item.videos) && item.videos && option.dataStyle.showVideo"
class="timeLineVideoDivs"
>
<div class="timeLineVideoDiv">
<!-- 编辑状态 -->
<video
v-if="isEdit"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
<div class="timeLineVideoDivTitle">{{ item.videos.title }}</div>
<n-image
v-if="isEdit || !item.videos.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
src="/src/assets/videos/earth.mp4"
></video>
<!-- 其他情况 -->
<video
v-else
:id="
'ZhiGan_ModalTimeLine' +
item.title +
'-' +
index +
'-' +
option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<PlayVideo
v-if="!isEdit && item.videos.videourl && !item.videos.manufacturer"
:videourl="item.videos.videourl"
:index="index + '-0'"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
></video>
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
<MulHKmonitor
v-if="!isEdit && item.videos.videourl && item.videos.manufacturer == '海康'"
:index="index + '-' + videoIndex"
:serialNumberValue="item.videos.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:timestamp="option.dataStyle.timestamp"
/>
</div>
</div>
</template>
@ -218,6 +200,7 @@
import { replaceSqlParams } from '@/utils/sqlHandler';
import Title from './svg/title.vue';
import dayjs from 'dayjs';
import { MulHKmonitor, PlayVideo } from './video/index';
const props = defineProps({
chartConfig: {
@ -241,77 +224,16 @@
() => option.status.hide,
() => {
if (!option.status.hide) {
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
}
},
);
//
let players: any = [];
function handlerPlayVideo() {
if (!option.status.hide) {
option.dataset.forEach((element, index) => {
//
if (Array.isArray(element.videourl)) {
element.videourl.forEach((url, urlindex) => {
if (players[index * 100 + urlindex]) {
players[index * 100 + urlindex].src(url);
} else {
players[index * 100 + urlindex] = TCPlayer(
'ZhiGan_ModalTimeLine' +
element.title +
'-' +
index +
'-' +
urlindex +
'-' +
option.dataStyle.timestamp,
{},
);
players[index * 100 + urlindex].src(url);
}
});
}
//
if (typeof element.videourl === 'string') {
if (players[index * 100]) {
players[index * 100].src(element.videourl);
} else {
players[index * 100] = TCPlayer(
'ZhiGan_ModalTimeLine' +
element.title +
'-' +
index +
'-' +
option.dataStyle.timestamp,
{},
);
players[index * 100].src(element.videourl);
}
}
});
}
}
//
onMounted(() => {
// id
if (!option.dataStyle.timestamp) {
option.dataStyle.timestamp = dayjs().unix();
}
option.dataset.forEach((element) => {
let player: any = null;
players.push(player);
});
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
@ -320,23 +242,10 @@
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
handlerPlayVideo();
});
});
});
//
onBeforeUnmount(() => {
if (players) {
players.forEach((player) => {
if (player) {
player.dispose();
player = null;
}
});
}
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
@ -399,11 +308,17 @@
border: v-bind('`${option.dataStyle.videoBorderWidth}px`') solid
v-bind('`${option.dataStyle.videoBorderColor}`');
padding: v-bind('`${option.dataStyle.videoPadding}px`');
}
video {
display: block;
object-fit: v-bind('option.dataStyle.videoFit');
position: relative;
.timeLineVideoDivTitle {
position: absolute;
z-index: 10;
top: 5px;
left: 5px;
font-size: v-bind('`${option.dataStyle.videoTitleFontSize}px`');
color: v-bind('`${option.dataStyle.videoTitleFontColor}`');
}
}
::v-deep .n-timeline-item-timeline__line {
@ -413,8 +328,4 @@
::v-deep .n-timeline-item-timeline {
margin-left: v-bind('`${option.dataStyle.timelineMarginLeft}px`') !important;
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
}
</style>

View File

@ -0,0 +1,7 @@
import MulHKmonitor from './mulHKmonitor.vue';
import PlayVideo from './playVideo.vue';
export {
MulHKmonitor,
PlayVideo,
};

View File

@ -0,0 +1,338 @@
<template>
<div :id="'camera-box-' + props.index" class="camera-box">
<!-- 视口区域 -->
<div :id="'playWnd-' + props.index + '-' + props.timestamp" class="playWnd"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch, ref, nextTick } from 'vue';
import { JSEncrypt } from 'jsencrypt';
const props = defineProps(['serialNumberValue', 'index', 'width', 'height', 'timestamp']);
//
let initCount = 0;
let pubKey = '';
let oWebControl: any = null;
//
const initPlugin = () => {
oWebControl = new window.WebControl({
szPluginContainer: 'playWnd-' + props.index + '-' + props.timestamp, // id
iServicePortStart: 15900, // 使
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // IE10使ActiveXclsid
cbConnectSuccess: function () {
// WebControl
oWebControl
.JS_StartService('window', {
// WebControlVideoPluginPlugin.exe
dllPath: './VideoPluginConnect.dll', // "./VideoPluginConnect.dll"
})
.then(
function () {
//
oWebControl.JS_SetWindowControlCallback({
//
cbIntegrationCallBack: cbIntegrationCallBack,
});
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl
.JS_CreateWnd('playWnd-' + props.index + '-' + props.timestamp, width, height)
.then(function () {
init(); //
});
},
function () {
//
console.log('创建播放实例失败!!!');
},
);
},
cbConnectError: function () {
// WebControl
oWebControl = null;
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件未启动,正在尝试启动,请稍候...';
}
window.WebControl.JS_WakeUp('VideoWebPlugin://'); // errorwakeup
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件启动失败,请检查插件是否安装!';
}
}
},
cbConnectClose: function (bNormalClose) {
// bNormalClose = false
// JS_DisconnectbNormalClose = true
oWebControl = null;
},
});
};
//
function init() {
getPubKey(function () {
let appkey = '23604396'; //appkey
let ip = '221.2.83.54'; //IP
let port = 1443;
let appSecret = 'NZJ8L3bxCOOV6rtTFjsx';
let secret = setEncrypt(appSecret); //secret
let layerOut = '1x1';
let playMode = 0; //0-1-
let snapDir = 'D:\\SnapDir'; //
let videoDir = 'D:\\VideoDir'; //
let layout = layerOut; //playMode 1*1
let enableHTTPS = 1; //HTTPS1
let encryptedFields = 'secret'; //secret
let showToolbar = 0; //0-0-
let showSmart = 1; //线0-0-
let buttonIDs = '0'; //
oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //APIappkey
secret: secret, //APIsecret
ip: ip, //APIIP
playMode: playMode, //
port: port, //
snapDir: snapDir, //
videoDir: videoDir, //
layout: layout, //
enableHTTPS: enableHTTPS, //HTTPS
encryptedFields: encryptedFields, //
showToolbar: showToolbar, //
showSmart: showSmart, //
buttonIDs: buttonIDs, //
}),
})
.then(function (oData) {
//
reSizeVideo();
// -
oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: function (oData) {
// oData web
if (oData.responseMsg.type == '7') {
setFullScreen();
}
},
});
});
//
oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: {
cameraIndexCode: props.serialNumberValue,
streamMode: 0,
transMode: 1,
gpuMode: 0,
wndId: 1,
},
});
});
}
//
function closeHkVideo() {
if (oWebControl != null) {
//
oWebControl.JS_HideWnd();
//
oWebControl.JS_RequestInterface({ funcName: 'destroyWnd' });
//
oWebControl.JS_Disconnect();
}
}
//
function reSizeVideo() {
if (oWebControl != null) {
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl.JS_Resize(width, height); // resizefirefoxDIV
}
}
//
function setFullScreen() {
oWebControl.JS_RequestInterface({
funcName: 'setFullScreen',
});
}
watch(
() => props.serialNumberValue,
() => {
//
init();
},
);
watch(
() => props.width,
() => {
nextTick(() => {
//
reSizeVideo();
});
},
);
//
function getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// RSA
function setEncrypt(value) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
//
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
onMounted(() => {
//
initPlugin();
//
const elements = document.querySelectorAll('.ZhiGan_ModalTimeLine');
if (elements.length > 0) {
// scroll
elements.forEach((element) => {
element.addEventListener('scroll', reSizeVideo);
});
}
});
onUnmounted(() => {
//
closeHkVideo();
//
const elements = document.querySelectorAll('.ZhiGan_ModalTimeLine');
if (elements.length > 0) {
// scroll
elements.forEach((element) => {
element.removeEventListener('scroll', reSizeVideo);
});
}
});
defineExpose({
initPlugin,
init,
closeHkVideo,
});
</script>
<style scoped>
.camera-box-0 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-1 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-2 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-3 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.playWnd {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<div>
<video
:id="'ZhiGan_ModalTimeLine' + props.index + props.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="props.videoLoop"
:muted="props.videoMuted"
:style="{
width: props.width + 'px',
height: props.height + 'px',
}"
/>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps([
'videourl',
'index',
'width',
'height',
'timestamp',
'videoLoop',
'videoMuted',
'videoFit',
]);
watch(
() => props.videourl,
() => {
handlerPlayVideo();
},
);
watch(
() => props.width,
() => {
handlerPlayVideo();
},
);
//
let player: any = null;
function handlerPlayVideo() {
nextTick(function () {
if (player) {
player.src(props.videourl);
} else {
player = TCPlayer('ZhiGan_ModalTimeLine' + props.index + props.timestamp, {});
player.src(props.videourl);
}
});
}
function closePlayerVideo() {
if (player) {
player.dispose();
player = null;
}
}
onMounted(() => {
handlerPlayVideo();
});
onUnmounted(() => {
closePlayerVideo();
});
defineExpose({
handlerPlayVideo,
closePlayerVideo,
});
</script>
<style lang="scss" scoped>
video {
display: block;
object-fit: v-bind('props.videoFit');
}
::v-deep .vjs-live-display {
width: 40px !important;
}
::v-deep .vjs-button {
width: 20px !important;
}
</style>

View File

@ -23,8 +23,11 @@ export const option = {
padding: 4,
serialNumberValue: '',
titleFontSize: 12,
selectPlacement: 'left',
titleFontSize: 15,
titleFontColor: '#ffffff',
titleBackgroud: '#3d3d3d',
modalTitleHeight: 30,
}
}
@ -33,6 +36,6 @@ export default class Config extends PublicConfigClass implements CreateComponent
public attr = { ...chartInitConfig, w: 320, h: 220, zIndex: -1 }
public chartConfig = cloneDeep(ZhiGan_ModalVideoConfig)
public option = cloneDeep(option)
public request = { ...requestSqlConfig, requestSQLContent: { sql: 'SELECT "Id", "Name", "SerialNumber"\r\nFROM fm_camera\r\nWHERE ST_DWithin(\r\n ST_GeographyFromText(\'POINT(\' || \r\n (SELECT \"Lng\" FROM fm_fireclueinfo WHERE "Id" = #{Id}) || \' \' || \r\n (SELECT \"Lat\" FROM fm_fireclueinfo WHERE "Id" = #{Id}) || \r\n \')\'),\r\n ST_GeographyFromText(\'POINT(\' || \"Lng\" || \' \' || \"Lat\" || \')\'),\r\n 1000\r\n) = true' }, }
public request = { ...requestSqlConfig, requestSQLContent: { sql: 'SELECT "Id", "Name", "SerialNumber", "Manufacturer"\r\nFROM fm_camera\r\nWHERE ST_DWithin(\r\n ST_GeographyFromText(\'POINT(\' || \r\n (SELECT \"Lng\" FROM fm_fireclueinfo WHERE "Id" = #{Id}) || \' \' || \r\n (SELECT \"Lat\" FROM fm_fireclueinfo WHERE "Id" = #{Id}) || \r\n \')\'),\r\n ST_GeographyFromText(\'POINT(\' || \"Lng\" || \' \' || \"Lat\" || \')\'),\r\n 1000\r\n) = true' }, }
public filter = "return res.result;"
}

View File

@ -1,7 +1,7 @@
<template>
<CollapseItem name="数据设置" :expanded="true">
<n-tag type="primary">编辑页面修改视频数据配置后请在预览页面查看效果</n-tag>
<SettingItemBox name="默认路径" :alone="true">
<SettingItemBox name="默认视频" :alone="true">
<n-select
v-model:value="optionData.dataStyle.serialNumberValue"
:options="option.dataset"
@ -10,6 +10,52 @@
placeholder="请选择默认视频"
/>
</SettingItemBox>
<SettingItemBox name="视频选择框方向" :alone="true">
<n-select
v-model:value="optionData.dataStyle.selectPlacement"
:options="[
{
label: '左侧',
value: 'left',
},
{
label: '右侧',
value: 'right',
},
]"
placeholder="视频选择框方向"
/>
</SettingItemBox>
<SettingItemBox :alone="false">
<SettingItem name="标题背景颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.titleBackgroud"
></n-color-picker>
</SettingItem>
<SettingItem name="标题高度">
<n-input-number
v-model:value="optionData.dataStyle.modalTitleHeight"
size="small"
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="标题字体大小">
<n-input-number
v-model:value="optionData.dataStyle.titleFontSize"
size="small"
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="标题字体颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.titleFontColor"
></n-color-picker>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="视频设置">
<SettingItem>
@ -57,24 +103,10 @@
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="标题字体大小">
<n-input-number
v-model:value="optionData.dataStyle.titleFontSize"
size="small"
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="标题字体颜色">
<n-color-picker
size="small"
:modes="['rgb']"
v-model:value="optionData.dataStyle.titleFontColor"
></n-color-picker>
</SettingItem>
<SettingItem name="背景颜色">
<n-color-picker
size="small"
:modes="['rgb']"
:modes="['hex']"
v-model:value="optionData.dataStyle.backgroud"
></n-color-picker>
</SettingItem>

View File

@ -3,42 +3,56 @@
{
"id": 418015298064389,
"name": "XZD148青山裕南山",
"serialNumber": "13b23c9b878143bc99269898964af54f"
"serialNumber": "13b23c9b878143bc99269898964af54f",
"manufacturer": "海康"
},
{
"id": 418015349661701,
"name": "XZD153狼窝沟西南",
"serialNumber": "74b95e6575d741489b9a9061bb646467"
"serialNumber": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
},
{
"id": 418015349899269,
"name": "XZD152青山裕水库东",
"serialNumber": "ecdb49050c57452dbae7ec6f03e82667"
"serialNumber": "ecdb49050c57452dbae7ec6f03e82667",
"manufacturer": "海康"
},
{
"id": 418015350452229,
"name": "XZD147大古台南山",
"serialNumber": "edd84ccac34441c48c6a7bf030f9c13f"
"serialNumber": "edd84ccac34441c48c6a7bf030f9c13f",
"manufacturer": "海康"
},
{
"id": 418015351681029,
"name": "XZD151青山裕水库西",
"serialNumber": "c10f9faea87d4f659e2bc01de24e29a9"
"serialNumber": "c10f9faea87d4f659e2bc01de24e29a9",
"manufacturer": "海康"
},
{
"id": 418015351836677,
"name": "XZD149青山裕北山",
"serialNumber": "909e98d192f649fea4c5269f5f7832e1"
"serialNumber": "909e98d192f649fea4c5269f5f7832e1",
"manufacturer": "海康"
},
{
"id": 418015351025669,
"name": "XZD150青山裕山里人家西北",
"serialNumber": "b56f09f8c64249379e42481c7b173dce"
"serialNumber": "b56f09f8c64249379e42481c7b173dce",
"manufacturer": "海康"
},
{
"id": 490483936976901,
"name": "XZD155突围路广场",
"serialNumber": "a8010ac49baa4b81a569ba24dc95a4e7"
"serialNumber": "a8010ac49baa4b81a569ba24dc95a4e7",
"manufacturer": "海康"
},
{
"id": 490483936976911,
"name": "playerVideo",
"serialNumber": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
}
]
}

View File

@ -1,132 +0,0 @@
<template>
<div class="box-container">
<iframe
id="iframe"
ref="fIframe"
scrolling="no"
frameborder="0"
width="100%"
height="100%"
src="/public/monitor/mulIndex.html"
>
</iframe>
</div>
</template>
<script>
export default {
name: 'monitorbox',
props: ['deviceId', 'channelId'],
data() {
return {
list: [],
monitorPlayer: null,
};
},
mounted() {
let arr = [
this.deviceId,
this.deviceId,
'23604396',
'221.2.83.54',
1443,
'NZJ8L3bxCOOV6rtTFjsx',
];
let _this = this;
this.$refs.fIframe.onload = function () {
_this.$refs.fIframe.contentWindow.postMessage(arr);
};
window.addEventListener('message', (e) => {
this.$emit('closeMonitor');
});
},
};
</script>
<style scoped>
.box-container {
width: 100vw;
height: 100vh;
}
.table-header {
width: calc(100% - 10px);
height: 25px;
color: #fff;
text-align: center;
}
.table-header div {
float: left;
width: 25%;
border-bottom: 1px dashed #00fff0;
padding-bottom: 8px;
}
.table-body {
width: 100%;
height: calc(100% - 40px);
overflow-y: auto;
}
.table-body .item {
width: 100%;
height: 36px;
background: #00ffee2f;
font-size: 12px;
text-align: center;
line-height: 36px;
cursor: pointer;
}
.table-body .item:nth-child(2n) {
background: #00ffee50;
}
.table-body .item div {
float: left;
width: 25%;
color: #eee;
overflow: hidden;
height: 36px;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
border: 0;
}
::-webkit-scrollbar {
height: 10px;
width: 10px;
background: transparent;
border-radius: 5px;
}
::-webkit-scrollbar-thumb {
padding-top: 100px;
-webkit-box-shadow:
inset 1px 1px 0 rgba(0, 0, 0, 0.1),
inset -1px -1px 0 rgba(0, 0, 0, 0.07);
background-color: #797979;
min-height: 28px;
border-radius: 4px;
background-clip: padding-box;
}
::-webkit-scrollbar-track,
::-webkit-scrollbar-thumb {
border: 0;
}
::-webkit-scrollbar-thumb:hover {
-webkit-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25);
background-color: rgba(0, 0, 0, 0.4);
}
::-webkit-scrollbar-thumb:active {
-webkit-box-shadow: inset 1px 1px 3px rgba(0, 0, 0, 0.35);
background-color: rgba(0, 0, 0, 0.5);
}
</style>

View File

@ -1,51 +1,73 @@
<template>
<div class="ZhiGan_ModalVideo">
<div class="modalVideoTitle">
<n-select
v-model:value="option.dataStyle.serialNumberValue"
:options="option.dataset"
label-field="name"
value-field="serialNumber"
placeholder="请选择查看的视频"
<div class="modalTitle">
<n-tooltip trigger="hover" :placement="option.dataStyle.selectPlacement || 'left'">
<template #trigger>
<n-button>
<span
calss="modalTitle_name"
:style="{
color: option.dataStyle.titleFontColor,
fontSize: option.dataStyle.titleFontSize + 'px',
}"
>
{{ titleName }}
</span>
</n-button>
</template>
<n-select
v-model:value="option.dataStyle.serialNumberValue"
:options="option.dataset"
label-field="name"
value-field="serialNumber"
placeholder="请选择查看的视频"
/>
</n-tooltip>
</div>
<div class="modalVideo">
<!-- 编辑状态 -->
<!-- 无视频url的情况 -->
<n-image
v-if="isEdit"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - option.dataStyle.modalTitleHeight - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<MulHKmonitor
ref="MulHKmonitorRef"
v-if="!isEdit && manufacturer == '海康'"
:serialNumberValue="option.dataStyle.serialNumberValue"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - option.dataStyle.modalTitleHeight - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:timestamp="option.dataStyle.timestamp"
/>
<PlayerVideo
v-if="!isEdit && !manufacturer"
:serialNumberValue="option.dataStyle.serialNumberValue"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - option.dataStyle.modalTitleHeight - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
</div>
<!-- 编辑状态 -->
<!-- 无视频url的情况 -->
<n-image
v-if="isEdit || !option.dataStyle.serialNumberValue"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<!-- 其他情况 -->
<video
v-else-if="
option.dataStyle.serialNumberValue.includes('https://') ||
option.dataStyle.serialNumberValue.includes('http://')
"
:id="'ZhiGan_ModalVideo' + option.dataStyle.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
/>
<MulHKmonitor
v-else
:serialNumberValue="option.dataStyle.serialNumberValue"
:width="`${w - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
:height="`${h - 2 * option.dataStyle.padding - 2 * option.dataStyle.borderWidth}`"
/>
</div>
</template>
<script setup lang="ts">
import { PropType, toRefs, reactive, ref, onMounted, onBeforeUnmount, watch } from 'vue';
import {
PropType,
toRefs,
reactive,
ref,
onMounted,
onBeforeUnmount,
watch,
computed,
nextTick,
} from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { icon } from '@/plugins';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
@ -53,7 +75,7 @@
import { EventBus } from '@/utils/eventBus';
import { replaceSqlParams } from '@/utils/sqlHandler';
import dayjs from 'dayjs';
import MulHKmonitor from './hk/mulHKmonitor.vue';
import { MulHKmonitor, PlayVideo } from './video/index';
const props = defineProps({
chartConfig: {
@ -62,61 +84,52 @@
},
});
console.log(document.location);
const { w, h } = toRefs(props.chartConfig.attr);
const chartEditStore = useChartEditStore();
const option = reactive({
dataset: props.chartConfig.option.dataset,
dataStyle: props.chartConfig.option.dataStyle,
status: props.chartConfig.status,
});
//
const MulHKmonitorRef = ref();
//
const isEdit = window.location.href.includes('/chart/home/');
//
const titleName = ref('');
const manufacturer = ref('');
//
watch(
() => option.status.hide,
() => {
if (!option.status.hide && !isEdit) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
},
);
//
watch(
() => option.dataStyle.serialNumberValue,
() => {
if (option.dataStyle.serialNumberValue) {
handlerPlayVideo();
} else {
if (player) {
player.dispose();
player = null;
(newValue) => {
if (!isEdit) {
if (!newValue) {
let data = getDataBySerialNumberValue(option.dataStyle.serialNumberValue);
if (data.manufacturer == '海康') {
MulHKmonitorRef.value.initPlugin();
}
}
}
},
);
//
let player: any = null;
function handlerPlayVideo() {
if (
!option.status.hide &&
!isEdit &&
(option.dataStyle.serialNumberValue.includes('https://') ||
option.dataStyle.serialNumberValue.includes('http://'))
) {
if (player) {
player.src(option.dataStyle.serialNumberValue);
} else {
player = TCPlayer('ZhiGan_ModalVideo' + option.dataStyle.timestamp, {});
player.src(option.dataStyle.serialNumberValue);
}
}
//
watch(
() => option.dataStyle.serialNumberValue,
(newValue) => {
titleName.value = getDataBySerialNumberValue(newValue).name;
manufacturer.value = getDataBySerialNumberValue(newValue).manufacturer;
},
);
//
function getDataBySerialNumberValue(value) {
return option.dataset.find((item) => item.serialNumber === value);
}
//
@ -125,12 +138,15 @@
if (!option.dataStyle.timestamp) {
option.dataStyle.timestamp = dayjs().unix();
}
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
if (!option.dataStyle.serialNumberValue) {
option.dataStyle.serialNumberValue = option.dataset[0].serialNumber;
}
titleName.value = getDataBySerialNumberValue(option.dataStyle.serialNumberValue).name;
manufacturer.value = getDataBySerialNumberValue(
option.dataStyle.serialNumberValue,
).manufacturer;
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
@ -138,23 +154,15 @@
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
handlerPlayVideo();
});
});
});
//
onBeforeUnmount(() => {
if (player) {
player.dispose();
player = null;
}
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
handlerPlayVideo();
if (resData) {
option.dataset = resData;
}
});
</script>
@ -176,19 +184,40 @@
scrollbar-width: none;
-ms-overflow-style: none;
}
.modalTitle {
position: relative;
width: 100%;
height: v-bind('`${option.dataStyle.modalTitleHeight}px`');
background: v-bind('`${option.dataStyle.titleBackgroud}`');
display: inline-flex;
align-items: center;
justify-content: left;
.modalTitle_name {
padding-left: 10px;
width: 100%;
height: v-bind('`${option.dataStyle.modalTitleHeight}px`');
font-size: v-bind('`${option.dataStyle.titleFontSize}px`');
color: v-bind('`${option.dataStyle.titleFontColor}`');
}
}
.modalVideo {
width: 100%;
height: v-bind('`${h - option.dataStyle.modalTitleHeight}px`');
}
::v-deep .n-button--medium-type {
width: 100% !important;
}
video {
display: block;
object-fit: v-bind('option.dataStyle.videoFit');
}
.modalVideoTitle {
position: absolute;
width: 90%;
top: 5%;
left: 5%;
z-index: 1;
}
::v-deep .n-base-selection {
--n-border: 0px solid #ffffff00 !important;
background: #ffffff00 !important;
@ -201,8 +230,15 @@
}
::v-deep .n-base-selection-input {
background: #ffffff00 !important;
font-size: v-bind('`${ option.dataStyle.titleFontSize }px`') !important;
color: v-bind('`${option.dataStyle.titleFontColor}`') !important;
width: 230px !important;
}
::v-deep .n-base-selection-input__content {
font-size: v-bind('`${ option.dataStyle.titleFontSize }px`') !important;
color: v-bind('`${option.dataStyle.titleFontColor}`') !important;
}
::v-deep .n-base-select-option-show--checkmark {
font-family:
PingFangSC,
PingFang SC;
@ -213,6 +249,13 @@
font-style: normal;
}
::v-deep .n-button--medium-type {
--n-border: 1px solid #ffffff00 !important;
--n-border-hover: 1px solid #ffffff00 !important;
--n-border-disabled: 1px solid #ffffff00 !important;
--n-border-pressed: 1px solid #ffffff00 !important;
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
}

View File

@ -0,0 +1,7 @@
import MulHKmonitor from './mulHKmonitor.vue';
import PlayVideo from './playVideo.vue';
export {
MulHKmonitor,
PlayVideo,
};

View File

@ -0,0 +1,246 @@
<template>
<div id="camera-box" class="camera-box">
<!-- 视口区域 -->
<div :id="'playWnd' + props.timestamp" class="playWnd"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch, defineProps, defineExpose, ref, computed } from 'vue';
import { JSEncrypt } from 'jsencrypt';
const props = defineProps(['serialNumberValue', 'width', 'height', 'timestamp']);
//
let initCount = 0;
let pubKey = '';
let oWebControl: any = null;
//
const initPlugin = () => {
oWebControl = new window.WebControl({
szPluginContainer: 'playWnd' + props.timestamp, // id
iServicePortStart: 15900, // 使
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // IE10使ActiveXclsid
cbConnectSuccess: function () {
// WebControl
oWebControl
.JS_StartService('window', {
// WebControlVideoPluginPlugin.exe
dllPath: './VideoPluginConnect.dll', // "./VideoPluginConnect.dll"
})
.then(
function () {
//
oWebControl.JS_SetWindowControlCallback({
//
cbIntegrationCallBack: cbIntegrationCallBack,
});
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box');
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl
.JS_CreateWnd('playWnd' + props.timestamp, width, height)
.then(function () {
init(); //
});
},
function () {
//
console.log('创建播放实例失败!!!');
},
);
},
cbConnectError: function () {
// WebControl
oWebControl = null;
let d = document.getElementById('playWnd' + props.timestamp);
if (d) {
d.innerHTML = '插件未启动,正在尝试启动,请稍候...';
}
window.WebControl.JS_WakeUp('VideoWebPlugin://'); // errorwakeup
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
let d = document.getElementById('playWnd' + props.timestamp);
if (d) {
d.innerHTML = '插件启动失败,请检查插件是否安装!';
}
}
},
cbConnectClose: function (bNormalClose) {
// bNormalClose = false
// JS_DisconnectbNormalClose = true
oWebControl = null;
},
});
};
//
function init() {
getPubKey(function () {
let appkey = '23604396'; //appkey
let ip = '221.2.83.54'; //IP
let port = 1443;
let appSecret = 'NZJ8L3bxCOOV6rtTFjsx';
let secret = setEncrypt(appSecret); //secret
let layerOut = '1x1';
let playMode = 0; //0-1-
let snapDir = 'D:\\SnapDir'; //
let videoDir = 'D:\\VideoDir'; //
let layout = layerOut; //playMode 1*1
let enableHTTPS = 1; //HTTPS1
let encryptedFields = 'secret'; //secret
let showToolbar = 1; //0-0-
let showSmart = 1; //线0-0-
let buttonIDs = ''; //
oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //APIappkey
secret: secret, //APIsecret
ip: ip, //APIIP
playMode: playMode, //
port: port, //
snapDir: snapDir, //
videoDir: videoDir, //
layout: layout, //
enableHTTPS: enableHTTPS, //HTTPS
encryptedFields: encryptedFields, //
showToolbar: showToolbar, //
showSmart: showSmart, //
buttonIDs: buttonIDs, //
}),
})
.then(function (oData) {
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box');
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl.JS_Resize(width, height); // resizefirefoxDIV
});
//
oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: {
cameraIndexCode: props.serialNumberValue,
streamMode: 0,
transMode: 1,
gpuMode: 0,
wndId: 1,
},
});
});
}
//
function closeHkVideo() {
if (oWebControl != null) {
//
oWebControl.JS_HideWnd();
//
oWebControl.JS_RequestInterface({ funcName: 'destroyWnd' });
//
oWebControl.JS_Disconnect();
}
}
watch(
() => props.serialNumberValue,
() => {
init();
},
);
//
function getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// RSA
function setEncrypt(value) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
//
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
onMounted(() => {
initPlugin();
});
onUnmounted(() => {
closeHkVideo();
});
defineExpose({
initPlugin,
init,
closeHkVideo,
});
</script>
<style scoped>
.camera-box {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-50%, -40%);
padding: 0px;
}
.playWnd {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
}
</style>

View File

@ -0,0 +1,77 @@
<template>
<video
:id="'ZhiGan_ModalVideo' + props.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="props.videoLoop"
:muted="props.videoMuted"
:width="props.width"
:height="props.height"
/>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
const props = defineProps([
'serialNumberValue',
'width',
'height',
'timestamp',
'videoLoop',
'videoMuted',
'videoFit',
]);
//
let player: any = null;
function handlerPlayVideo() {
setTimeout(function () {
if (player) {
player.src(props.serialNumberValue);
} else {
player = TCPlayer('ZhiGan_ModalVideo' + props.timestamp, {});
player.src(props.serialNumberValue);
}
}, 1000);
}
function closePlayerVideo() {
if (player) {
player.dispose();
player = null;
}
}
watch(
() => props.serialNumberValue,
() => {
handlerPlayVideo();
},
);
onMounted(() => {
handlerPlayVideo();
});
onUnmounted(() => {
closePlayerVideo();
});
defineExpose({
handlerPlayVideo,
closePlayerVideo,
});
</script>
<style lang="scss" scoped>
video {
display: block;
object-fit: v-bind('props.videoFit');
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
}
</style>

View File

@ -3,109 +3,93 @@
{
"label": "费县林业防火监控列表",
"value": [
{
"id": 418015298064389,
"title": "XZD148青山裕南山",
"videourl": "13b23c9b878143bc99269898964af54f",
"manufacturer": "海康"
},
{
"id": 418015349661701,
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
},
{
"id": 418015349899269,
"title": "XZD152青山裕水库东",
"videourl": "ecdb49050c57452dbae7ec6f03e82667",
"manufacturer": "海康"
},
{
"id": 418015350452229,
"title": "XZD147大古台南山",
"videourl": "edd84ccac34441c48c6a7bf030f9c13f",
"manufacturer": "海康"
},
{
"id": 418015351681029,
"title": "XZD151青山裕水库西",
"videourl": "c10f9faea87d4f659e2bc01de24e29a9",
"manufacturer": "海康"
},
{
"id": 418015351836677,
"title": "XZD149青山裕北山",
"videourl": "909e98d192f649fea4c5269f5f7832e1",
"manufacturer": "海康"
},
{
"id": 418015351025669,
"title": "XZD150青山裕山里人家西北",
"videourl": "b56f09f8c64249379e42481c7b173dce",
"manufacturer": "海康"
},
{
"id": 490483936976901,
"title": "XZD155突围路广场",
"videourl": "a8010ac49baa4b81a569ba24dc95a4e7",
"manufacturer": "海康"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县东蒙镇沂蒙抽水蓄能业营地",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县冯庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县冻蒙镇沂蒙抽水蓄能业营地",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇沂蒙抽水蓄能业营地",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县薛庄镇火山后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
},
{
"title":"费县东蒙镇天蒙景区二村东边南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
}
]
}

View File

@ -1,7 +1,7 @@
<template>
<div class="ZhiGan_SheXiangTouModal">
<div class="modalCloseloseButton">
<CloseButton :dataStyle="option.dataStyle" @click="option.status.hide = true" />
<CloseButton :dataStyle="option.dataStyle" @click="hideModal" />
</div>
<div class="modalTitleName">
<span>摄像头监控列表</span>
@ -42,10 +42,6 @@
value-field="label"
/>
</div>
<!-- <div class="leftDivTitleSpan">费县林业防火监控列表</div>
<div class="leftDivSelect">
<LeftTitleIcon2 :dataStyle="option.dataStyle" />
</div> -->
</div>
<div class="leftDivSearch">
<n-input-group>
@ -104,26 +100,24 @@
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<!-- 其他情况 -->
<video
v-else
:id="
'ZhiGan_SheXiangTouModal' +
videoItem.title +
videoIndex +
option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="option.dataStyle.videoloop"
:muted="option.dataStyle.videomuted"
:style="{
width: videoWidthNoPadding + 'px',
height: videoHeightNoPadding + 'px',
}"
<MulHKmonitor
v-if="!isEdit && videoItem.videourl && videoItem.manufacturer == '海康'"
:index="videoIndex"
:serialNumberValue="videoItem.videourl"
:width="videoWidthNoPadding"
:height="videoHeightNoPadding"
:timestamp="option.dataStyle.timestamp"
/>
<PlayVideo
v-if="!isEdit && videoItem.videourl && !videoItem.manufacturer"
:videourl="videoItem.videourl"
:index="videoIndex"
:width="videoWidthNoPadding"
:height="videoHeightNoPadding"
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
</div>
</div>
@ -152,12 +146,15 @@
import dayjs from 'dayjs';
import { EventBus } from '@/utils/eventBus';
import { replaceSqlParams } from '@/utils/sqlHandler';
import CloseButton from './svg/closeButton.vue';
import TypeButton from './svg/typeButton.vue';
import LeftTitleIcon1 from './svg/leftTitleIcon1.vue';
import LeftTitleIcon2 from './svg/leftTitleIcon2.vue';
import ListVideoNameIcon from './svg/listVideoNameIcon.vue';
import CloseVideoIcon from './svg/closeVideoIcon.vue';
import {
CloseButton,
TypeButton,
LeftTitleIcon1,
LeftTitleIcon2,
ListVideoNameIcon,
CloseVideoIcon,
} from './svg/index';
import { MulHKmonitor, PlayVideo } from './video/index';
const { createMessage } = useMessage();
@ -177,6 +174,9 @@
status: props.chartConfig.status,
});
//
const isEdit = window.location.href.includes('/chart/home/');
//
const selectLabel = ref(option.dataset[0].label);
//
@ -194,9 +194,6 @@
}
}
//
const isEdit = window.location.href.includes('/chart/home/');
//
const videoWidthNoPadding = ref(
option.dataStyle.videoWidth - (20 / Math.sqrt(parseInt(option.dataStyle.nowType))) * 2,
@ -253,16 +250,7 @@
option.dataStyle.proportion = 100;
let temp = cloneDeep(option.videoList);
option.videoList = [temp[0]];
closeThisVideo(1);
closeThisVideo(2);
closeThisVideo(3);
if (oldValue == '9') {
closeThisVideo(4);
closeThisVideo(5);
closeThisVideo(6);
closeThisVideo(7);
closeThisVideo(8);
}
}
@ -277,11 +265,6 @@
if (oldValue == '9') {
let temp = cloneDeep(option.videoList);
option.videoList = [temp[0], temp[1], temp[2], temp[3]];
closeThisVideo(4);
closeThisVideo(5);
closeThisVideo(6);
closeThisVideo(7);
closeThisVideo(8);
}
}
@ -314,6 +297,12 @@
}
}
//
function hideModal() {
option.videoList = [{}];
option.status.hide = true;
}
//
function clickListVideo(item) {
//
@ -328,7 +317,6 @@
//
if (changeThisFlag.value) {
option.videoList[cloneDeep(changeThisNum.value)] = item;
playVideo(cloneDeep(changeThisNum.value), item);
changeThisNum.value = 9;
changeThisFlag.value = false;
return;
@ -340,46 +328,23 @@
option.videoList.forEach((li, index) => {
if (!li.videourl && flag) {
option.videoList[index] = item;
playVideo(index, item);
flag = false;
}
});
//
if (flag) {
option.videoList[num] = item;
playVideo(num, item);
num++;
}
if (num == option.videoList.length) {
num = 0;
}
}
//
let players: any = [];
//
function playVideo(index, element) {
setTimeout(() => {
if (players[index]) {
players[index].src(element.videourl);
} else {
players[index] = TCPlayer(
'ZhiGan_SheXiangTouModal' + element.title + index + +option.dataStyle.timestamp,
{},
);
players[index].src(element.videourl);
}
}, 500);
}
//
function closeThisVideo(index) {
if (index < option.videoList.length) {
option.videoList[index] = {};
}
if (players[index]) {
players[index].dispose();
players[index] = null;
}
}
//
@ -389,30 +354,6 @@
option.dataStyle.timestamp = dayjs().unix();
}
//
let player: any = null;
players.push(player);
players.push(player);
players.push(player);
players.push(player);
players.push(player);
players.push(player);
players.push(player);
players.push(player);
players.push(player);
//
if (
!window.location.href.includes('/chart/home/') &&
!option.status.hide &&
props.chartConfig.option.videoList.length > 0
) {
props.chartConfig.option.videoList.forEach((element: any, index) => {
if (parseInt(option.dataStyle.nowType) > index) {
playVideo(index, element);
}
});
}
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
@ -424,18 +365,6 @@
});
});
//
onBeforeUnmount(() => {
if (players) {
players.forEach((player) => {
if (player) {
player.dispose();
player = null;
}
});
}
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
@ -717,15 +646,6 @@
}
}
video {
display: block;
object-fit: v-bind('option.dataStyle.videofit');
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
}
::v-deep .search-input {
background-image: url('./svg/searchInput.svg') !important;
background-size: 100% 100% !important;

View File

@ -0,0 +1,15 @@
import CloseButton from './closeButton.vue';
import TypeButton from './typeButton.vue';
import LeftTitleIcon1 from './leftTitleIcon1.vue';
import LeftTitleIcon2 from './leftTitleIcon2.vue';
import ListVideoNameIcon from './listVideoNameIcon.vue';
import CloseVideoIcon from './closeVideoIcon.vue';
export {
CloseButton,
TypeButton,
LeftTitleIcon1,
LeftTitleIcon2,
ListVideoNameIcon,
CloseVideoIcon,
};

View File

@ -0,0 +1,7 @@
import MulHKmonitor from './mulHKmonitor.vue';
import PlayVideo from './playVideo.vue';
export {
MulHKmonitor,
PlayVideo,
};

View File

@ -0,0 +1,301 @@
<template>
<div :id="'camera-box-' + props.index" class="camera-box">
<!-- 视口区域 -->
<div :id="'playWnd-' + props.index + '-' + props.timestamp" class="playWnd"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch, ref, nextTick } from 'vue';
import { JSEncrypt } from 'jsencrypt';
const props = defineProps(['serialNumberValue', 'index', 'width', 'height', 'timestamp']);
//
let initCount = 0;
let pubKey = '';
let oWebControl: any = null;
//
const initPlugin = () => {
oWebControl = new window.WebControl({
szPluginContainer: 'playWnd-' + props.index + '-' + props.timestamp, // id
iServicePortStart: 15900, // 使
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // IE10使ActiveXclsid
cbConnectSuccess: function () {
// WebControl
oWebControl
.JS_StartService('window', {
// WebControlVideoPluginPlugin.exe
dllPath: './VideoPluginConnect.dll', // "./VideoPluginConnect.dll"
})
.then(
function () {
//
oWebControl.JS_SetWindowControlCallback({
//
cbIntegrationCallBack: cbIntegrationCallBack,
});
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl
.JS_CreateWnd('playWnd-' + props.index + '-' + props.timestamp, width, height)
.then(function () {
init(); //
});
},
function () {
//
console.log('创建播放实例失败!!!');
},
);
},
cbConnectError: function () {
// WebControl
oWebControl = null;
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件未启动,正在尝试启动,请稍候...';
}
window.WebControl.JS_WakeUp('VideoWebPlugin://'); // errorwakeup
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件启动失败,请检查插件是否安装!';
}
}
},
cbConnectClose: function (bNormalClose) {
// bNormalClose = false
// JS_DisconnectbNormalClose = true
oWebControl = null;
},
});
};
//
function init() {
getPubKey(function () {
let appkey = '23604396'; //appkey
let ip = '221.2.83.54'; //IP
let port = 1443;
let appSecret = 'NZJ8L3bxCOOV6rtTFjsx';
let secret = setEncrypt(appSecret); //secret
let layerOut = '1x1';
let playMode = 0; //0-1-
let snapDir = 'D:\\SnapDir'; //
let videoDir = 'D:\\VideoDir'; //
let layout = layerOut; //playMode 1*1
let enableHTTPS = 1; //HTTPS1
let encryptedFields = 'secret'; //secret
let showToolbar = 1; //0-0-
let showSmart = 1; //线0-0-
let buttonIDs = '0,16'; //
oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //APIappkey
secret: secret, //APIsecret
ip: ip, //APIIP
playMode: playMode, //
port: port, //
snapDir: snapDir, //
videoDir: videoDir, //
layout: layout, //
enableHTTPS: enableHTTPS, //HTTPS
encryptedFields: encryptedFields, //
showToolbar: showToolbar, //
showSmart: showSmart, //
buttonIDs: buttonIDs, //
}),
})
.then(function (oData) {
//
reSizeVideo();
});
//
oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: {
cameraIndexCode: props.serialNumberValue,
streamMode: 0,
transMode: 1,
gpuMode: 0,
wndId: 1,
},
});
});
}
//
function closeHkVideo() {
if (oWebControl != null) {
//
oWebControl.JS_HideWnd();
//
oWebControl.JS_RequestInterface({ funcName: 'destroyWnd' });
//
oWebControl.JS_Disconnect();
}
}
//
function reSizeVideo() {
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl.JS_Resize(width, height); // resizefirefoxDIV
}
watch(
() => props.serialNumberValue,
() => {
init();
},
);
watch(
() => props.width,
() => {
nextTick(() => {
reSizeVideo();
});
},
);
//
function getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// RSA
function setEncrypt(value) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
//
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
onMounted(() => {
initPlugin();
});
onUnmounted(() => {
closeHkVideo();
});
defineExpose({
initPlugin,
init,
closeHkVideo,
});
</script>
<style scoped>
.camera-box-0 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-1 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-2 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-3 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.playWnd {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<div>
<video
:id="'ZhiGan_SheXiangTouModal' + props.index + props.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="props.videoLoop"
:muted="props.videoMuted"
:style="{
width: props.width + 'px',
height: props.height + 'px',
}"
/>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps([
'videourl',
'index',
'width',
'height',
'timestamp',
'videoLoop',
'videoMuted',
'videoFit',
]);
watch(
() => props.videourl,
() => {
handlerPlayVideo();
},
);
watch(
() => props.width,
() => {
handlerPlayVideo();
},
);
//
let player: any = null;
function handlerPlayVideo() {
nextTick(function () {
if (player) {
player.src(props.videourl);
} else {
player = TCPlayer('ZhiGan_SheXiangTouModal' + props.index + props.timestamp, {});
player.src(props.videourl);
}
});
}
function closePlayerVideo() {
if (player) {
player.dispose();
player = null;
}
}
onMounted(() => {
handlerPlayVideo();
});
onUnmounted(() => {
closePlayerVideo();
});
defineExpose({
handlerPlayVideo,
closePlayerVideo,
});
</script>
<style lang="scss" scoped>
video {
display: block;
object-fit: v-bind('props.videoFit');
}
::v-deep .vjs-live-display {
width: 40px !important;
}
::v-deep .vjs-button {
width: 20px !important;
}
</style>

View File

@ -21,6 +21,10 @@ export const option = {
titleWidth: 181,
titleHeight: 30,
buttonColor1: '#008000',
buttonColor2: '#7D8492',
buttonSize: 24,
videoloop: false, // 视频-循环播放
videomuted: true, // 视频-静音
videofit: 'fill', // 视频-适应方式
@ -45,8 +49,8 @@ export const option = {
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = ZhiGan_WuRenJiShiShiHuaMianConfig.key
public attr = { ...chartInitConfig, w: 400, h: 343, zIndex: -1 }
public request = { ...requestSqlConfig, requestSQLContent: { sql: 'select * from zg_wurenjishishihuamian' }, }
public attr = { ...chartInitConfig, w: 400, h: 353, zIndex: -1 }
// public request = { ...requestSqlConfig, requestSQLContent: { sql: 'select * from zg_wurenjishishihuamian' }, }
public filter = "return res.result;"
public chartConfig = cloneDeep(ZhiGan_WuRenJiShiShiHuaMianConfig)
public option = cloneDeep(option)

View File

@ -4,7 +4,7 @@
<SettingItem name="背景颜色">
<n-color-picker
size="small"
:modes="['rgb']"
:modes="['hex']"
v-model:value="optionData.dataStyle.backgroud"
></n-color-picker>
</SettingItem>
@ -26,6 +26,31 @@
</SettingItem>
</SettingItemBox>
<SettingItemBox name="切换按钮设置">
<SettingItem name="切换按钮颜色1">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.buttonColor1"
></n-color-picker>
</SettingItem>
<SettingItem name="切换按钮颜色2">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.buttonColor2"
></n-color-picker>
</SettingItem>
<SettingItem name="切换按钮大小">
<n-input-number
v-model:value="optionData.dataStyle.buttonSize"
min="0"
type="text"
size="small"
/>
</SettingItem>
</SettingItemBox>
<SettingItemBox name="标题设置">
<SettingItem name="是否显示标题栏">
<n-space>
@ -35,7 +60,7 @@
<SettingItem name="标题字体颜色">
<n-color-picker
size="small"
:modes="['rgb']"
:modes="['hex']"
v-model:value="optionData.dataStyle.titleColor"
></n-color-picker>
</SettingItem>
@ -72,7 +97,7 @@
<SettingItem name="视频类型">
<n-select v-model:value="optionData.dataStyle.videofit" size="small" :options="fitList" />
</SettingItem>
<SettingItem name="视频宽度">
<!-- <SettingItem name="视频宽度">
<n-input-number
v-model:value="optionData.dataStyle.videowidth"
min="0"
@ -87,7 +112,7 @@
type="text"
size="small"
/>
</SettingItem>
</SettingItem> -->
</SettingItemBox>
<SettingItemBox name="边框设置">

View File

@ -1,28 +1,54 @@
{
"source": [
{
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
},
{
"title": "XZD152青山裕水库东",
"videourl": "ecdb49050c57452dbae7ec6f03e82667",
"manufacturer": "海康"
},
{
"title": "XZD147大古台南山",
"videourl": "edd84ccac34441c48c6a7bf030f9c13f",
"manufacturer": "海康"
},
{
"title": "XZD151青山裕水库西",
"videourl": "c10f9faea87d4f659e2bc01de24e29a9",
"manufacturer": "海康"
},
{
"title":"DJA-72无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"DJ-057无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"DJA-20无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"DJA-035无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"DJA-11无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
},
{
"title":"DJ-021无人机监控画面",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
}
]
}

View File

@ -1,38 +1,81 @@
<template>
<div class="ZhiGan_WuRenJiShiShiHuaMian">
<!-- 按钮栏 -->
<div class="arrow-button">
<n-button quaternary @click="previousPage">
<template #icon>
<n-icon :size="option.dataStyle.buttonSize">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24"
height="24"
viewBox="0 0 24 24"
>
<g fill="none">
<path
d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10s10-4.477 10-10S17.523 2 12 2zm.28 14.53a.75.75 0 0 1-.976.073l-.085-.072l-4-4.001a.75.75 0 0 1-.073-.977l.073-.084l4.001-4a.75.75 0 0 1 1.133.977l-.072.084l-2.722 2.72h6.691a.75.75 0 0 1 .744.649L17 12a.75.75 0 0 1-.648.743l-.102.007H9.56l2.72 2.72a.75.75 0 0 1 .073.977l-.073.084z"
:fill="page > 1 ? option.dataStyle.buttonColor1 : option.dataStyle.buttonColor2"
></path>
</g>
</svg>
</n-icon>
</template>
</n-button>
<n-button quaternary @click="nextPage">
<template #icon>
<n-icon :size="option.dataStyle.buttonSize">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24"
height="24"
viewBox="0 0 24 24"
>
<g fill="none">
<path
d="M12.001 2c5.523 0 10 4.477 10 10s-4.477 10-10 10s-10-4.477-10-10s4.477-10 10-10zm.78 5.469l-.084-.073a.75.75 0 0 0-.882-.007l-.094.08l-.073.084a.75.75 0 0 0-.007.883l.08.094l2.72 2.72H7.75l-.103.006a.75.75 0 0 0-.64.642L7 11.999l.007.102a.75.75 0 0 0 .642.641l.101.007h6.69l-2.72 2.72l-.073.085a.75.75 0 0 0 1.05 1.05l.084-.073l4.001-4l.073-.085a.75.75 0 0 0 .007-.882l-.08-.094l-4-4.001l-.085-.073l.084.073z"
:fill="
page != sumPage ? option.dataStyle.buttonColor1 : option.dataStyle.buttonColor2
"
></path>
</g>
</svg>
</n-icon>
</template>
</n-button>
</div>
<div class="list">
<div v-for="(item, index) in option.dataset" :key="item.title">
<div v-for="(item, index) in filterVideoData" :key="item.title + index">
<div class="item">
<!-- 编辑状态 -->
<div class="videoDiv">
<video
<n-image
v-if="isEdit"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="option.dataStyle.videoloop"
:muted="option.dataStyle.videomuted"
:width="`${option.dataStyle.videowidth - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
:height="`${option.dataStyle.videoheight - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
src="/src/assets/videos/earth.mp4"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<!-- 其他情况 -->
<video
v-else
:id="
'ZhiGan_WuRenJiShiShiHuaMian' + item.title + item.index + option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="option.dataStyle.videoloop"
:muted="option.dataStyle.videomuted"
<MulHKmonitor
v-if="!isEdit && item.manufacturer == '海康'"
:index="index"
:serialNumberValue="item.videourl"
:width="`${option.dataStyle.videowidth - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
:height="`${option.dataStyle.videoheight - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
:timestamp="option.dataStyle.timestamp"
/>
<PlayVideo
v-if="!isEdit && !item.manufacturer"
:videourl="item.videourl"
:index="index"
:width="`${option.dataStyle.videowidth - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
:height="`${option.dataStyle.videoheight - 2 * option.dataStyle.borderWidth - 2 * option.dataStyle.padding}`"
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
</div>
<Title
@ -48,15 +91,26 @@
</template>
<script setup lang="ts">
import { PropType, toRefs, watch, reactive, ref, onMounted, onBeforeUnmount } from 'vue';
import {
PropType,
toRefs,
watch,
reactive,
ref,
onMounted,
onBeforeUnmount,
computed,
} from 'vue';
import { CreateComponentType } from '@/packages/index.d';
import { icon } from '@/plugins';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';
import { useChartDataFetch } from '@/hooks';
import { EventBus } from '@/utils/eventBus';
import { replaceSqlParams } from '@/utils/sqlHandler';
import { LeftOutlined, RightOutlined } from '@ant-design/icons-vue';
import dayjs from 'dayjs';
import Title from './svg/title.vue';
import { MulHKmonitor, PlayVideo } from './video/index';
const props = defineProps({
chartConfig: {
@ -73,6 +127,85 @@
status: props.chartConfig.status,
});
//
const isEdit = window.location.href.includes('/chart/home/');
let sumPage = Math.ceil(option.dataset.length / 4);
const page = ref(1);
const filterVideoData = computed(() => {
let result = option.dataset.slice(0 + (page.value - 1) * 4, 4 + (page.value - 1) * 4);
return result;
});
//
function previousPage() {
if (page.value > 1) {
page.value -= 1;
}
}
//
function nextPage() {
if (page.value != sumPage) {
page.value += 1;
}
}
watch(
() => option.status.hide,
() => {
if (!option.status.hide) {
}
},
);
//
onMounted(() => {
// id
if (!option.dataStyle.timestamp) {
option.dataStyle.timestamp = dayjs().unix();
}
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql, { Id: data.id });
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
});
});
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
});
watch(
() => w.value,
() => {
option.dataStyle.videowidth =
(w.value -
option.dataStyle.borderWidth * 4 -
option.dataStyle.padding * 4 -
option.dataStyle.marginleft) /
2;
},
);
watch(
() => h.value,
() => {
option.dataStyle.videoheight =
(h.value -
option.dataStyle.borderWidth * 4 -
option.dataStyle.padding * 4 -
option.dataStyle.margintop * 2 -
option.dataStyle.titleHeight * 2 -
option.dataStyle.titleMarginTop * 2 -
10) /
2;
},
);
watch(
() => option.dataStyle.videowidth,
() => {
@ -88,94 +221,12 @@
() => option.dataStyle.showTitle,
() => {
if (option.dataStyle.showTitle) {
h.value = (h.value / 278) * 343;
h.value = (h.value / 278) * 353;
} else {
h.value = (h.value / 343) * 278;
h.value = (h.value / 353) * 278;
}
},
);
//
const isEdit = window.location.href.includes('/chart/home/');
watch(
() => option.status.hide,
() => {
if (!option.status.hide) {
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
}
},
);
//
let players: any = [];
function handlerPlayVideo() {
if (!option.status.hide) {
option.dataset.forEach((element, index) => {
if (players[index]) {
players[index].src(element.videourl);
} else {
players[index] = TCPlayer(
'ZhiGan_WuRenJiShiShiHuaMian' +
element.title +
element.index +
option.dataStyle.timestamp,
{},
);
players[index].src(element.videourl);
}
});
}
}
//
onMounted(() => {
// id
if (!option.dataStyle.timestamp) {
option.dataStyle.timestamp = dayjs().unix();
}
option.dataset.forEach((element) => {
let player: any = null;
players.push(player);
});
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
EventBus.on(props.chartConfig.id + 'dataupdate', (data) => {
props.chartConfig.request.requestSQLContent.sql = replaceSqlParams(sql, { Id: data.id });
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
handlerPlayVideo();
});
});
});
//
onBeforeUnmount(() => {
if (players) {
players.forEach((player) => {
if (player) {
player.dispose();
player = null;
}
});
}
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
});
</script>
<style lang="scss" scoped>
@ -184,12 +235,18 @@
background: v-bind('`${option.dataStyle.backgroud}`');
width: v-bind('`${w}px`');
height: v-bind('`${h}px`');
position: relative;
//
-webkit-user-select: none; /* Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE/Edge */
user-select: none;
}
.ZhiGan_WuRenJiShiShiHuaMian::-webkit-scrollbar {
display: none;
}
.ZhiGan_WuRenJiShiShiHuaMian {
scrollbar-width: none;
-ms-overflow-style: none;
@ -200,8 +257,9 @@
flex-wrap: wrap;
gap: 10px;
width: 100%;
margin-top: v-bind('`${option.dataStyle.margintop}px`');
margin-top: v-bind('`${option.dataStyle.margintop + 15}px`');
margin-left: v-bind('`${option.dataStyle.marginleft}px`');
margin-right: v-bind('`${option.dataStyle.marginleft}px`');
}
.item {
@ -216,16 +274,15 @@
padding: v-bind('`${option.dataStyle.padding}px`');
}
video {
display: block;
object-fit: v-bind('option.dataStyle.videofit');
}
.title {
margin-top: v-bind('`${option.dataStyle.titleMarginTop}px`');
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
.arrow-button {
display: flex;
position: absolute;
height: 15px;
top: 0px;
right: 0px;
}
</style>

View File

@ -0,0 +1,7 @@
import MulHKmonitor from './mulHKmonitor.vue';
import PlayVideo from './playVideo.vue';
export {
MulHKmonitor,
PlayVideo,
};

View File

@ -0,0 +1,297 @@
<template>
<div :id="'camera-box-' + props.index" class="camera-box">
<!-- 视口区域 -->
<div :id="'playWnd-' + props.index + '-' + props.timestamp" class="playWnd"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch, defineProps, defineExpose, ref, computed } from 'vue';
import { JSEncrypt } from 'jsencrypt';
const props = defineProps(['serialNumberValue', 'index', 'width', 'height', 'timestamp']);
//
let initCount = 0;
let pubKey = '';
let oWebControl: any = null;
//
const initPlugin = () => {
oWebControl = new window.WebControl({
szPluginContainer: 'playWnd-' + props.index + '-' + props.timestamp, // id
iServicePortStart: 15900, // 使
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // IE10使ActiveXclsid
cbConnectSuccess: function () {
// WebControl
oWebControl
.JS_StartService('window', {
// WebControlVideoPluginPlugin.exe
dllPath: './VideoPluginConnect.dll', // "./VideoPluginConnect.dll"
})
.then(
function () {
//
oWebControl.JS_SetWindowControlCallback({
//
cbIntegrationCallBack: cbIntegrationCallBack,
});
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl
.JS_CreateWnd('playWnd-' + props.index + '-' + props.timestamp, width, height)
.then(function () {
init(); //
});
},
function () {
//
console.log('创建播放实例失败!!!');
},
);
},
cbConnectError: function () {
// WebControl
oWebControl = null;
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件未启动,正在尝试启动,请稍候...';
}
window.WebControl.JS_WakeUp('VideoWebPlugin://'); // errorwakeup
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件启动失败,请检查插件是否安装!';
}
}
},
cbConnectClose: function (bNormalClose) {
// bNormalClose = false
// JS_DisconnectbNormalClose = true
oWebControl = null;
},
});
};
//
function init() {
getPubKey(function () {
let appkey = '23604396'; //appkey
let ip = '221.2.83.54'; //IP
let port = 1443;
let appSecret = 'NZJ8L3bxCOOV6rtTFjsx';
let secret = setEncrypt(appSecret); //secret
let layerOut = '1x1';
let playMode = 0; //0-1-
let snapDir = 'D:\\SnapDir'; //
let videoDir = 'D:\\VideoDir'; //
let layout = layerOut; //playMode 1*1
let enableHTTPS = 1; //HTTPS1
let encryptedFields = 'secret'; //secret
let showToolbar = 0; //0-0-
let showSmart = 1; //线0-0-
let buttonIDs = ''; //
oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //APIappkey
secret: secret, //APIsecret
ip: ip, //APIIP
playMode: playMode, //
port: port, //
snapDir: snapDir, //
videoDir: videoDir, //
layout: layout, //
enableHTTPS: enableHTTPS, //HTTPS
encryptedFields: encryptedFields, //
showToolbar: showToolbar, //
showSmart: showSmart, //
buttonIDs: buttonIDs, //
}),
})
.then(function (oData) {
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl.JS_Resize(width, height); // resizefirefoxDIV
oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: function (oData) {
// oData web
// -
if (oData.responseMsg.type == '7') {
setFullScreen();
}
},
});
});
//
oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: {
cameraIndexCode: props.serialNumberValue,
streamMode: 0,
transMode: 1,
gpuMode: 0,
wndId: 1,
},
});
});
}
//
function closeHkVideo() {
if (oWebControl != null) {
//
oWebControl.JS_HideWnd();
//
oWebControl.JS_RequestInterface({ funcName: 'destroyWnd' });
//
oWebControl.JS_Disconnect();
}
}
//
function getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// RSA
function setEncrypt(value) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
//
function setFullScreen() {
oWebControl.JS_RequestInterface({
funcName: 'setFullScreen',
});
}
//
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
onMounted(() => {
initPlugin();
});
onUnmounted(() => {
closeHkVideo();
});
defineExpose({
initPlugin,
init,
closeHkVideo,
});
</script>
<style scoped>
.camera-box-0 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-1 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-2 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-3 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.playWnd {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
}
</style>

View File

@ -0,0 +1,85 @@
<template>
<div>
<video
:id="'ZhiGan_WuRenJiShiShiHuaMian' + props.index + props.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="props.videoLoop"
:muted="props.videoMuted"
:width="props.width"
:height="props.height"
/>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps([
'videourl',
'index',
'width',
'height',
'timestamp',
'videoLoop',
'videoMuted',
'videoFit',
]);
//
let player: any = null;
watch(
() => props.videourl,
() => {
handlerPlayVideo();
},
);
function handlerPlayVideo() {
nextTick(function () {
if (player) {
player.src(props.videourl);
} else {
player = TCPlayer('ZhiGan_WuRenJiShiShiHuaMian' + props.index + props.timestamp, {});
player.src(props.videourl);
}
});
}
function closePlayerVideo() {
if (player) {
player.dispose();
player = null;
}
}
onMounted(() => {
handlerPlayVideo();
});
onUnmounted(() => {
closePlayerVideo();
});
defineExpose({
handlerPlayVideo,
closePlayerVideo,
});
</script>
<style lang="scss" scoped>
video {
display: block;
object-fit: v-bind('props.videoFit');
}
::v-deep .vjs-live-display {
width: 40px !important;
}
::v-deep .vjs-button {
width: 20px !important;
}
</style>

View File

@ -2,7 +2,7 @@
<CollapseItem name="默认方法设置" :expanded="true">
<n-space>
<n-switch v-model:value="optionData.dataStyle.defaultCloseModal" size="small" />
<n-text>默认点击隐藏火情详情弹窗及其所在分组的内容</n-text>
<n-text>默认点击隐藏弹窗及其所在分组的内容</n-text>
</n-space>
</CollapseItem>
<CollapseItem name="数据设置" :expanded="true">

View File

@ -62,6 +62,8 @@ export const option = {
videoBorderWidth: 2,
videoBorderColor: '#008000',
videoPadding: 4,
videoTitleFontSize: 12,
videoTitleFontColor: '#ffffff',
},
}

View File

@ -288,6 +288,20 @@
:options="textAlignOptions"
/>
</SettingItem>
<SettingItem name="视频字体标题颜色">
<n-color-picker
size="small"
:modes="['hex']"
v-model:value="optionData.dataStyle.videoTitleFontColor"
></n-color-picker>
</SettingItem>
<SettingItem name="视频字体标题大小">
<n-input-number
v-model:value="optionData.dataStyle.videoTitleFontSize"
size="small"
:min="0"
></n-input-number>
</SettingItem>
<SettingItem name="视频宽度">
<n-input-number
v-model:value="optionData.dataStyle.videoWidth"

View File

@ -5,16 +5,31 @@
"type": "success",
"content": "临沂市山东省辖地级市位于山东省东南部地跨北纬34°2236°13东经117°24119°11之间属温带季风气候四季分明雨热同季地势自北而南有沂山、蒙山、尼山3条主要山脉延伸控制着沂沭河上游及其支流的流向向南构成的扇状临郯苍平原是山东三平原之一。",
"time": "2025-02-11 01:27:14",
"imageurl": [ "/src/assets/logo.png", "/src/assets/logo.png" ],
"videourl": [ "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv", "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv" ]
"imageurl": [ "/src/assets/images/chart/zhigan/component/ModalCarouselPng01.png", "/src/assets/images/chart/zhigan/component/ModalCarouselPng02.png" ],
"videos": [
{
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
},
{
"title":"费县马庄镇陈家鱼后村南斜坡后村",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv",
"manufacturer": ""
}
]
},
{
"title":"临沂市",
"type": "success",
"content": "",
"time": "2025-02-11 01:27:15",
"imageurl": "/src/assets/logo.png",
"videourl": "http://111.36.45.20:18000/flv/hls/H-dcb1ea7388588111.flv"
"imageurl": "/src/assets/images/chart/zhigan/component/ModalCarouselPng03.png",
"videos": {
"title": "XZD153狼窝沟西南",
"videourl": "74b95e6575d741489b9a9061bb646467",
"manufacturer": "海康"
}
},
{
"title":"临沂市",

View File

@ -112,94 +112,76 @@
<!-- 视频 -->
<!-- 数组 -->
<div
v-if="Array.isArray(item.videourl) && option.dataStyle.showVideo"
v-if="Array.isArray(item.videos) && option.dataStyle.showVideo"
class="timeLineVideoDivs"
>
<div class="timeLineVideoDiv" v-for="(url, urlindex) in item.videourl" :key="url">
<!-- 编辑状态 -->
<video
v-if="isEdit"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
<div
class="timeLineVideoDiv"
v-for="(videoItem, videoIndex) in item.videos"
:key="videoIndex"
>
<div class="timeLineVideoDivTitle">{{ videoItem.title }}</div>
<n-image
v-if="isEdit || !videoItem.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
src="/src/assets/videos/earth.mp4"
></video>
<!-- 其他情况 -->
<video
v-else
:id="
'HuoQingDetailTimeLine' +
item.title +
'-' +
index +
'-' +
urlindex +
'-' +
option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<PlayVideo
v-if="!isEdit && videoItem.videourl && !videoItem.manufacturer"
:videourl="videoItem.videourl"
:index="index + '-' + videoIndex"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
></video>
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
<MulHKmonitor
v-if="!isEdit && videoItem.videourl && videoItem.manufacturer == '海康'"
:index="index + '-' + videoIndex"
:serialNumberValue="videoItem.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:timestamp="option.dataStyle.timestamp"
/>
</div>
</div>
<!-- 单个 -->
<div
v-if="typeof item.videourl === 'string' && option.dataStyle.showVideo"
v-if="!Array.isArray(item.videos) && item.videos && option.dataStyle.showVideo"
class="timeLineVideoDivs"
>
<div class="timeLineVideoDiv">
<!-- 编辑状态 -->
<video
v-if="isEdit"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
<div class="timeLineVideoDivTitle">{{ item.videos.title }}</div>
<n-image
v-if="isEdit || !item.videos.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
src="/src/assets/videos/earth.mp4"
></video>
<!-- 其他情况 -->
<video
v-else
:id="
'HuoQingDetailTimeLine' +
item.title +
'-' +
index +
'-' +
option.dataStyle.timestamp
"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
lazy
:loop="option.dataStyle.videoLoop"
:muted="option.dataStyle.videoMuted"
src="/src/assets/images/chart/zhichu/component/SheXiangTouModal_Image.png"
preview-disabled
/>
<PlayVideo
v-if="!isEdit && item.videos.videourl && !item.videos.manufacturer"
:videourl="item.videos.videourl"
:index="index + '-0'"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
></video>
:timestamp="option.dataStyle.timestamp"
:videoLoop="option.dataStyle.videoLoop"
:videoMuted="option.dataStyle.videoMuted"
:videoFit="option.dataStyle.videoFit"
/>
<MulHKmonitor
v-if="!isEdit && item.videos.videourl && item.videos.manufacturer == '海康'"
:index="index + '-' + videoIndex"
:serialNumberValue="item.videos.videourl"
:width="`${option.dataStyle.videoWidth - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:height="`${option.dataStyle.videoHeight - 2 * option.dataStyle.videoBorderWidth - 2 * option.dataStyle.videoPadding}`"
:timestamp="option.dataStyle.timestamp"
/>
</div>
</div>
</template>
@ -218,6 +200,7 @@
import { replaceSqlParams } from '@/utils/sqlHandler';
import Title from './svg/title.vue';
import dayjs from 'dayjs';
import { MulHKmonitor, PlayVideo } from './video/index';
const props = defineProps({
chartConfig: {
@ -241,77 +224,16 @@
() => option.status.hide,
() => {
if (!option.status.hide) {
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
}
},
);
//
let players: any = [];
function handlerPlayVideo() {
if (!option.status.hide) {
option.dataset.forEach((element, index) => {
//
if (Array.isArray(element.videourl)) {
element.videourl.forEach((url, urlindex) => {
if (players[index * 100 + urlindex]) {
players[index * 100 + urlindex].src(url);
} else {
players[index * 100 + urlindex] = TCPlayer(
'HuoQingDetailTimeLine' +
element.title +
'-' +
index +
'-' +
urlindex +
'-' +
option.dataStyle.timestamp,
{},
);
players[index * 100 + urlindex].src(url);
}
});
}
//
if (typeof element.videourl === 'string') {
if (players[index * 100]) {
players[index * 100].src(element.videourl);
} else {
players[index * 100] = TCPlayer(
'HuoQingDetailTimeLine' +
element.title +
'-' +
index +
'-' +
option.dataStyle.timestamp,
{},
);
players[index * 100].src(element.videourl);
}
}
});
}
}
//
onMounted(() => {
// id
if (!option.dataStyle.timestamp) {
option.dataStyle.timestamp = dayjs().unix();
}
option.dataset.forEach((element) => {
let player: any = null;
players.push(player);
});
if (!window.location.href.includes('/chart/home/')) {
setTimeout(function () {
handlerPlayVideo();
}, 1000);
}
//
const sql = props.chartConfig.request?.requestSQLContent?.sql;
@ -320,23 +242,10 @@
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
handlerPlayVideo();
});
});
});
//
onBeforeUnmount(() => {
if (players) {
players.forEach((player) => {
if (player) {
player.dispose();
player = null;
}
});
}
});
// callback
useChartDataFetch(props.chartConfig, useChartEditStore, (resData: any[]) => {
option.dataset = resData;
@ -399,11 +308,17 @@
border: v-bind('`${option.dataStyle.videoBorderWidth}px`') solid
v-bind('`${option.dataStyle.videoBorderColor}`');
padding: v-bind('`${option.dataStyle.videoPadding}px`');
}
video {
display: block;
object-fit: v-bind('option.dataStyle.videoFit');
position: relative;
.timeLineVideoDivTitle {
position: absolute;
z-index: 10;
top: 5px;
left: 5px;
font-size: v-bind('`${option.dataStyle.videoTitleFontSize}px`');
color: v-bind('`${option.dataStyle.videoTitleFontColor}`');
}
}
::v-deep .n-timeline-item-timeline__line {
@ -413,8 +328,4 @@
::v-deep .n-timeline-item-timeline {
margin-left: v-bind('`${option.dataStyle.timelineMarginLeft}px`') !important;
}
::v-deep .vjs-live-control .vjs-live-display {
width: 100px !important;
}
</style>

View File

@ -0,0 +1,7 @@
import MulHKmonitor from './mulHKmonitor.vue';
import PlayVideo from './playVideo.vue';
export {
MulHKmonitor,
PlayVideo,
};

View File

@ -0,0 +1,338 @@
<template>
<div :id="'camera-box-' + props.index" class="camera-box">
<!-- 视口区域 -->
<div :id="'playWnd-' + props.index + '-' + props.timestamp" class="playWnd"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, watch, ref, nextTick } from 'vue';
import { JSEncrypt } from 'jsencrypt';
const props = defineProps(['serialNumberValue', 'index', 'width', 'height', 'timestamp']);
//
let initCount = 0;
let pubKey = '';
let oWebControl: any = null;
//
const initPlugin = () => {
oWebControl = new window.WebControl({
szPluginContainer: 'playWnd-' + props.index + '-' + props.timestamp, // id
iServicePortStart: 15900, // 使
iServicePortEnd: 15909,
szClassId: '23BF3B0A-2C56-4D97-9C03-0CB103AA8F11', // IE10使ActiveXclsid
cbConnectSuccess: function () {
// WebControl
oWebControl
.JS_StartService('window', {
// WebControlVideoPluginPlugin.exe
dllPath: './VideoPluginConnect.dll', // "./VideoPluginConnect.dll"
})
.then(
function () {
//
oWebControl.JS_SetWindowControlCallback({
//
cbIntegrationCallBack: cbIntegrationCallBack,
});
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl
.JS_CreateWnd('playWnd-' + props.index + '-' + props.timestamp, width, height)
.then(function () {
init(); //
});
},
function () {
//
console.log('创建播放实例失败!!!');
},
);
},
cbConnectError: function () {
// WebControl
oWebControl = null;
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件未启动,正在尝试启动,请稍候...';
}
window.WebControl.JS_WakeUp('VideoWebPlugin://'); // errorwakeup
initCount++;
if (initCount < 3) {
setTimeout(function () {
initPlugin();
}, 3000);
} else {
let d = document.getElementById('playWnd-' + props.index + '-' + props.timestamp);
if (d) {
d.innerHTML = '插件启动失败,请检查插件是否安装!';
}
}
},
cbConnectClose: function (bNormalClose) {
// bNormalClose = false
// JS_DisconnectbNormalClose = true
oWebControl = null;
},
});
};
//
function init() {
getPubKey(function () {
let appkey = '23604396'; //appkey
let ip = '221.2.83.54'; //IP
let port = 1443;
let appSecret = 'NZJ8L3bxCOOV6rtTFjsx';
let secret = setEncrypt(appSecret); //secret
let layerOut = '1x1';
let playMode = 0; //0-1-
let snapDir = 'D:\\SnapDir'; //
let videoDir = 'D:\\VideoDir'; //
let layout = layerOut; //playMode 1*1
let enableHTTPS = 1; //HTTPS1
let encryptedFields = 'secret'; //secret
let showToolbar = 0; //0-0-
let showSmart = 1; //线0-0-
let buttonIDs = '0'; //
oWebControl
.JS_RequestInterface({
funcName: 'init',
argument: JSON.stringify({
appkey: appkey, //APIappkey
secret: secret, //APIsecret
ip: ip, //APIIP
playMode: playMode, //
port: port, //
snapDir: snapDir, //
videoDir: videoDir, //
layout: layout, //
enableHTTPS: enableHTTPS, //HTTPS
encryptedFields: encryptedFields, //
showToolbar: showToolbar, //
showSmart: showSmart, //
buttonIDs: buttonIDs, //
}),
})
.then(function (oData) {
//
reSizeVideo();
// -
oWebControl.JS_SetWindowControlCallback({
cbIntegrationCallBack: function (oData) {
// oData web
if (oData.responseMsg.type == '7') {
setFullScreen();
}
},
});
});
//
oWebControl.JS_RequestInterface({
funcName: 'startPreview',
argument: {
cameraIndexCode: props.serialNumberValue,
streamMode: 0,
transMode: 1,
gpuMode: 0,
wndId: 1,
},
});
});
}
//
function closeHkVideo() {
if (oWebControl != null) {
//
oWebControl.JS_HideWnd();
//
oWebControl.JS_RequestInterface({ funcName: 'destroyWnd' });
//
oWebControl.JS_Disconnect();
}
}
//
function reSizeVideo() {
if (oWebControl != null) {
//
let width = props.width;
let height = props.height;
const divElement = document.getElementById('camera-box-' + props.index);
if (divElement) {
const rect = divElement.getBoundingClientRect();
const rectWidth = rect.width;
const rectHeight = rect.height;
if (rectWidth < width) {
width = rectWidth;
}
if (rectHeight < height) {
height = rectHeight;
}
}
oWebControl.JS_Resize(width, height); // resizefirefoxDIV
}
}
//
function setFullScreen() {
oWebControl.JS_RequestInterface({
funcName: 'setFullScreen',
});
}
watch(
() => props.serialNumberValue,
() => {
//
init();
},
);
watch(
() => props.width,
() => {
nextTick(() => {
//
reSizeVideo();
});
},
);
//
function getPubKey(callback) {
oWebControl
.JS_RequestInterface({
funcName: 'getRSAPubKey',
argument: JSON.stringify({
keyLength: 1024,
}),
})
.then(function (oData) {
if (oData.responseMsg.data) {
pubKey = oData.responseMsg.data;
callback();
}
});
}
// RSA
function setEncrypt(value) {
let encrypt = new JSEncrypt();
encrypt.setPublicKey(pubKey);
return encrypt.encrypt(value);
}
//
function cbIntegrationCallBack(oData) {
// showCBInfo(JSON.stringify(oData.responseMsg));
}
onMounted(() => {
//
initPlugin();
//
const elements = document.querySelectorAll('.HuoQingDetailTimeLine');
if (elements.length > 0) {
// scroll
elements.forEach((element) => {
element.addEventListener('scroll', reSizeVideo);
});
}
});
onUnmounted(() => {
//
closeHkVideo();
//
const elements = document.querySelectorAll('.HuoQingDetailTimeLine');
if (elements.length > 0) {
// scroll
elements.forEach((element) => {
element.removeEventListener('scroll', reSizeVideo);
});
}
});
defineExpose({
initPlugin,
init,
closeHkVideo,
});
</script>
<style scoped>
.camera-box-0 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-1 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-2 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.camera-box-3 {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
border-radius: 5px;
position: relative;
z-index: 10 !important;
position: fixed;
left: 50%;
top: 50%;
z-index: 10;
transform: translate(-105%, -135%);
padding: 0px;
}
.playWnd {
width: v-bind('`${props.width}px`');
height: v-bind('`${props.height}px`');
}
</style>

View File

@ -0,0 +1,93 @@
<template>
<div>
<video
:id="'ZhiGan_ModalTimeLine' + props.index + props.timestamp"
class="TCPlayer-video-contaiiner"
preload="auto"
crossOrigin="anonymous"
playsinline
autoplay
:loop="props.videoLoop"
:muted="props.videoMuted"
:style="{
width: props.width + 'px',
height: props.height + 'px',
}"
/>
</div>
</template>
<script setup lang="ts">
import { nextTick, onMounted, onUnmounted, watch } from 'vue';
const props = defineProps([
'videourl',
'index',
'width',
'height',
'timestamp',
'videoLoop',
'videoMuted',
'videoFit',
]);
watch(
() => props.videourl,
() => {
handlerPlayVideo();
},
);
watch(
() => props.width,
() => {
handlerPlayVideo();
},
);
//
let player: any = null;
function handlerPlayVideo() {
nextTick(function () {
if (player) {
player.src(props.videourl);
} else {
player = TCPlayer('ZhiGan_ModalTimeLine' + props.index + props.timestamp, {});
player.src(props.videourl);
}
});
}
function closePlayerVideo() {
if (player) {
player.dispose();
player = null;
}
}
onMounted(() => {
handlerPlayVideo();
});
onUnmounted(() => {
closePlayerVideo();
});
defineExpose({
handlerPlayVideo,
closePlayerVideo,
});
</script>
<style lang="scss" scoped>
video {
display: block;
object-fit: v-bind('props.videoFit');
}
::v-deep .vjs-live-display {
width: 40px !important;
}
::v-deep .vjs-button {
width: 20px !important;
}
</style>

View File

@ -87,25 +87,25 @@
</tbody>
</n-table>
</div>
<div v-else>
<!-- <div v-else>
<n-radio-group v-model:value="data.requestParamsBodyType" name="radiogroup">
<n-space>
<n-radio v-for="bodyEnum in RequestBodyEnumList" :key="bodyEnum" :value="bodyEnum">
{{ bodyEnum }}
</n-radio>
</n-space>
</n-radio-group>
</n-radio-group> -->
<!-- none -->
<n-card
<!-- none -->
<!-- <n-card
class="go-mt-3 go-pb-3"
v-if="data.requestParamsBodyType === RequestBodyEnum['NONE']"
>
<n-text depth="3">该接口没有 Body </n-text>
</n-card>
</n-card> -->
<!-- 具有对象属性时 -->
<template
<!-- 具有对象属性时 -->
<!-- <template
v-else-if="
data.requestParamsBodyType === RequestBodyEnum['FORM_DATA'] ||
data.requestParamsBodyType === RequestBodyEnum['X_WWW_FORM_URLENCODED']
@ -116,10 +116,10 @@
:target="data.requestParams[RequestParamsTypeEnum.BODY][data.requestParamsBodyType]"
@update="updateRequestBodyTable"
></request-header-table>
</template>
</template> -->
<!-- json -->
<template v-else-if="data.requestParamsBodyType === RequestBodyEnum['JSON']">
<!-- json -->
<!-- <template v-else-if="data.requestParamsBodyType === RequestBodyEnum['JSON']">
<monaco-editor
v-model:modelValue="
data.requestParams[RequestParamsTypeEnum.BODY][data.requestParamsBodyType]
@ -128,10 +128,10 @@
height="200px"
language="json"
/>
</template>
</template> -->
<!-- xml -->
<template v-else-if="data.requestParamsBodyType === RequestBodyEnum['XML']">
<!-- xml -->
<!-- <template v-else-if="data.requestParamsBodyType === RequestBodyEnum['XML']">
<monaco-editor
v-model:modelValue="
data.requestParams[RequestParamsTypeEnum.BODY][data.requestParamsBodyType]
@ -141,7 +141,7 @@
language="html"
/>
</template>
</div>
</div> -->
</div>
</div>
</n-space>
@ -177,7 +177,6 @@
type: Number,
},
});
console.log(props.panel);
const data: any = ref({
requestUrl: '',

View File

@ -26,6 +26,7 @@
import axios from 'axios';
import { getAppEnvConfig } from '@/utils/env';
import { fun_Delete } from '@/api/demo/files';
import { uploadSldStyle } from '@/api/application/layer';
const { VITE_GLOB_API_URL } = getAppEnvConfig();
async function fetchXMLDataWithAxios(url) {
@ -40,7 +41,12 @@
const { createMessage, createConfirm } = useMessage();
defineOptions({ name: 'MenuDrawer' });
const editorJson = ref();
const params: any = ref({});
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
console.log(data);
params.value.filepath = data.urlData.url;
params.value.styleName = data.styleName;
params.value.tablename = data.tableName;
setModalProps({ confirmLoading: false });
fileData.value = data.urlData;
// 使
@ -150,7 +156,18 @@
const changeHandle = (value) => {
editorJson.value = value;
};
const editorSubmit = () => {};
const editorSubmit = () => {
console.log(params.value);
uploadSldStyle(params.value).then((res) => {
console.log(res);
if (res) {
closeModal();
createMessage.success('提交成功!');
} else {
createMessage.error('提交失败!');
}
});
};
</script>
<style lang="less" scoped>
.v-json-box {

View File

@ -0,0 +1,50 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" title="下载模板" :showOkBtn="false">
<a-button type="primary" @click="downloadFile(0)">Excel</a-button>
<a-button type="primary" @click="downloadFile(1)">Shp</a-button>
</BasicModal>
</template>
<script lang="ts" setup>
import { BasicModal, useModalInner } from '@/components/Modal';
import { getAppEnvConfig } from '@/utils/env';
import axios from 'axios';
const { VITE_GLOB_API_URL } = getAppEnvConfig();
defineOptions({ name: 'MenuDrawer' });
const props = defineProps(['tableName']);
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
setModalProps({ confirmLoading: false });
});
const downloadFile = (type) => {
const fileName = type == 0 ? 'Excel模板' : 'Shp模板';
const params = {
type,
tableName: props.tableName,
};
axios({
method: 'get',
url: VITE_GLOB_API_URL + '/api/Layer/TempeleteByTableName',
params: params,
headers: {
'X-Token': localStorage.getItem('X-Token'),
},
responseType: 'blob',
}).then((res) => {
const elink = document.createElement('a');
elink.download = fileName;
elink.style.display = 'none';
elink.href = URL.createObjectURL(res.data);
document.body.appendChild(elink);
elink.click();
URL.revokeObjectURL(elink.href);
document.body.removeChild(elink);
});
};
</script>
<style lang="less" scoped>
button {
margin: 10px;
}
</style>

View File

@ -24,7 +24,7 @@
style="width: 200px; margin-right: 10px"
/>
<a-button type="primary" @click="getList"> </a-button>
<a-button type="primary" @click="handleCreate"> </a-button>
<a-button type="primary" @click="exportTemplate"> </a-button>
<a-button type="primary" @click="handleItem"> </a-button>
<a-button type="primary" @click="changeBatchProcessingModal(true)"> </a-button>
<a-button type="primary" @click="styleHandle"> </a-button>
@ -101,6 +101,8 @@
<!-- 样式配置 -->
<div class="data-style" v-if="showTable == 'style'">
<div class="img-box">
<a-input v-model:value="styleName" placeholder="样式名称" style="margin-bottom: 10px" />
<p style="color: #ed6f6f" v-if="styleName == ''"></p>
<a-upload-dragger
v-model:fileList="fileList"
name="file"
@ -144,17 +146,18 @@
@changeBatchProcessingModal="changeBatchProcessingModal"
/>
</a-modal>
<TempeleteModel @register="registerTempeleteModel" :tableName="tableName" />
</PageWrapper>
</template>
<script setup lang="ts">
import { LayerTree, AddModel, Map, EditorModel } from './page';
import { LayerTree, AddModel, Map, EditorModel, TempeleteModel } from './page';
import { ref, UnwrapRef, reactive, onMounted } from 'vue';
import { PageWrapper } from '@/components/Page';
import { useModal } from '@/components/Modal';
import { CloseOutlined, InboxOutlined } from '@ant-design/icons-vue';
import { BasicTable, useTable, TableAction } from '@/components/Table';
import { columns } from './data';
import { tableDataByTableName, updateTableData } from '@/api/application/layer';
import { tableDataByTableName, updateTableData, uploadSldStyle } from '@/api/application/layer';
import { ValidateErrorEntity } from 'ant-design-vue/es/form/interface';
import { useMessage } from '@/hooks/web/useMessage';
import { uploadFile, fun_Delete } from '@/api/demo/files';
@ -171,6 +174,8 @@
const batchProcessingModalOpen = ref(false);
const [registerAddModal, { openModal: openAddModal }] = useModal();
const [registerEditorModal, { openModal: openEditorModal }] = useModal();
const [registerTempeleteModel, { openModal: openTempeleteModel }] = useModal();
const labelCol = { span: 6 };
const wrapperCol = { span: 18 };
const keyWord = ref(null);
@ -212,6 +217,7 @@
const formState = ref({});
const tableName = ref();
const styleName = ref();
const rules = {
name: [
{ required: true, message: 'Please input Activity name', trigger: 'blur' },
@ -312,15 +318,19 @@
},
});
};
const fileUrl = ref('');
const fileUrlView: any = ref({});
const posData = (record) => {};
const styleHandle = () => {
fileUrl.value = '';
fileUrlView.value = {};
styleName.value = '';
showTable.value = 'style';
};
const handleChange = (info) => {
fileList.value = info.fileList;
};
const fileUrl = ref('');
const fileUrlView: any = ref({});
//
const handleCustomRequest = (options) => {
fileList.value = [];
@ -330,7 +340,7 @@
uploadFile(formData)
.then((res: any) => {
fileUrl.value = res[0].filePath;
fileUrlView.value.url = VITE_GLOB_API_URL + '/' + res[0].filePath;
fileUrlView.value.url = res[0].filePath;
fileUrlView.value.id = res[0].id;
createMessage.success('上传成功!');
})
@ -339,7 +349,23 @@
});
};
const styleSubmit = () => {
console.log(fileUrl.value);
if (!styleName.value) {
return createMessage.warning('样式名称不能为空!');
}
const params = {
filepath: fileUrl.value,
styleName: styleName.value,
tablename: tableName.value,
};
uploadSldStyle(params).then((res) => {
console.log(res);
if (res) {
showTable.value = '';
createMessage.success('提交成功!');
} else {
createMessage.error('提交失败!');
}
});
};
const styleCancel = () => {
if (fileUrlView.value.id) {
@ -360,8 +386,13 @@
}
};
const editorHandle = () => {
if (!styleName.value) {
return createMessage.warning('样式名称不能为空!');
}
openEditorModal(true, {
urlData: fileUrlView.value,
styleName: styleName.value,
tableName: tableName.value,
});
};
const changeBatchProcessingModal = (type: boolean) => {
@ -397,6 +428,9 @@
setColumns(arr);
});
};
const exportTemplate = () => {
openTempeleteModel(true);
};
onMounted(() => {});
</script>

View File

@ -2,3 +2,4 @@ export { default as LayerTree } from './LayerTree.vue';
export { default as AddModel } from './AddModel.vue';
export { default as Map } from './Map.vue';
export { default as EditorModel } from './EditorModel.vue';
export { default as TempeleteModel } from './TempeleteModel.vue';

View File

@ -21,6 +21,7 @@
...getStatusStyle(item.status),
...getPreviewConfigStyle(item.preview),
...(getBlendModeStyle(item.styles) as any),
...setMouseEventClose(item.mouseSetting),
}"
>
<component
@ -49,6 +50,7 @@
getComponentAttrStyle,
getStatusStyle,
getPreviewConfigStyle,
setMouseEventClose
} from '../../utils';
import { useLifeHandler } from '@/hooks';
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore';