引入海康威视插件

This commit is contained in:
zhoumengru
2025-09-11 16:14:55 +08:00
parent 671dd9fec7
commit e995c25fd2
57 changed files with 11735 additions and 2304 deletions

View File

@@ -17,7 +17,7 @@
selectedRowKeys: data.selectedRowKeys,
onChange: onSelectChange
}
: false
: {}
"
:expanded-row-keys="data.newTableOpt.expand ? data.expandedKeys : null"
size="middle"

View File

@@ -420,7 +420,7 @@ const data = reactive({
],
treeCheckValue: null,
SHOW_PARENT: TreeSelect.SHOW_PARENT,
// SHOW_PARENT: TreeSelect.SHOW_PARENT,
loading: false,
imageUrl: ''

View File

@@ -49,15 +49,16 @@
<a-modal
v-model:open="modalOpen"
@ok="handleOk"
width="90%"
width="60%"
class="modal-device"
:get-container="() => $refs.device"
>
<div v-if="modalComponent == 1">
<div>
<div v-if="modalComponent == 1" class="modal-content">
<div class="item">
<div class="title">
<div>电流电压</div>
<img src="@/assets/images/titleLine.png" alt="" />
电流电压
<!-- <div>电流电压</div>
<img src="@/assets/images/titleLine.png" alt="" /> -->
</div>
<div class="echarts">
<predictEcharts
@@ -67,11 +68,8 @@
/>
</div>
</div>
<div>
<div class="title">
<div>功率</div>
<img src="@/assets/images/titleLine.png" alt="" />
</div>
<div class="item">
<div class="title">功率</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[1]"
@@ -246,6 +244,8 @@ export default {
},
mounted() {
this.getDeviceList()
},
methods: {
handlePagesizeChange(pageOption) {
@@ -286,8 +286,16 @@ export default {
})
this.chartData.ydata = res.data
this.chartData.xdata = this.generateTimePoints()
this.$refs.chartRef1.initCharts()
this.$refs.chartRef2.initCharts()
this.$nextTick(() => {
if (this.$refs.chartRef1) {
this.$refs.chartRef1.initCharts()
}
if (this.$refs.chartRef2) {
this.$refs.chartRef2.initCharts()
}
})
// this.$refs.chartRef1.initCharts()
// this.$refs.chartRef2.initCharts()
} catch (error) {
console.log(error)
}
@@ -327,13 +335,12 @@ export default {
async openModal(item, val) {
console.log(item, '=============')
this.modalComponent = val
this.modalOpen = true
if (val == 1) {
await this.getDevicCharts(item)
} else {
await this.getDeviceBCUDetail(item)
}
this.modalOpen = true
},
handleOk() {
this.modalOpen = false
@@ -347,17 +354,19 @@ export default {
width: 100%;
height: 100%;
margin-left: 20px;
display: grid;
display: flex;
flex-wrap: wrap;
grid-gap: 20px;
overflow-y: auto;
grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
align-content: flex-start;
// grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
.device-item {
border-radius: 15px;
background: $bg2-color;
padding: 15px;
min-width: 340px;
max-width: 430px;
max-height: 230px;
height: 260px;
flex: 1;
.item-header {
display: flex;
@@ -460,6 +469,25 @@ export default {
.environment {
width: 200px;
}
.modal-device {
color: #fff;
.modal-content {
height: 700px;
.item {
// height: 300px;
.title {
color: #fff;
width: 230px;
border-bottom: 5px solid transparent;
border-image: url('@/assets/boxBottom.png') 0 0 100% 0 stretch;
}
.echarts {
height: 300px;
}
}
}
}
:deep(.ant-modal-body) {
:deep(.ant-table-wrapper .ant-table-row-expand-icon) {
@@ -471,7 +499,19 @@ export default {
background-color: #f0f8ff !important;
}
}
// .a-modal :deep(.ant-table-thead > tr > th) {
// background-color: #f0f8ff !important;
// }
:deep(.ant-table-cell) {
&::before {
width: 0 !important;
}
}
:deep(.ant-table-thead > tr > td) {
border-bottom: none !important;
border-top: none !important;
}
:deep(.ant-table-wrapper .ant-table-tbody > tr > td) {
border-top: none !important;
}
:deep(.ant-table-wrapper .ant-table-thead > tr > th) {
border-bottom: none !important;
}
</style>

View File

@@ -0,0 +1,167 @@
<template>
<div class="title" >
<span>{{ item.name }}</span>
<img
src="@/assets/images/fillScreen.png"
alt=""
width="23px"
style="margin-left: 10px; cursor: pointer"
/>
</div>
<div :id="'divPlugin_' + index" class="plugin"></div>
<!-- <a-button @click="clickLogin">开始登录</a-button>
<a-button @click="clickStartRealPlay">开始预览</a-button> -->
</template>
<script>
export default {
props:{
index: {
type: Number,
default: 0
},
item: {
type: Object,
default: () => {}
}
},
data() {
return {
g_iWndIndex: 0,
szDeviceIdentify: '',
deviceport: '',
channels: [],
ip: '',
port: '',
username: '',
password: '',
iRtspPort: ''
}
},
mounted() {
// this.init()
},
methods: {
// 初始化
init() {
let that = this;
// 初始化插件参数及插入插件
this.$nextTick(() => {
window.WebVideoCtrl.I_InitPlugin('100%', '100%', {
bWndFull: true, // 但窗口双击全屏
iPackageType: 2, // 封装格式 无插件只能是2
iWndowType: 1, // 分屏类型 1*1 2*2 ....
bNoPlugin: true, // 开启无插件模式
cbInitPluginComplete: function () {
console.log("初始化成功!");
window.WebVideoCtrl.I_InsertOBJECTPlugin('divPlugin_' + that.index);
}
});
})
},
// 登录
clickLogin() {
if (!this.ip || !this.port) {
return
}
this.szDeviceIdentify = this.ip+"_"+this.port
WebVideoCtrl.I_Login(this.ip, 1, this.port, this.username, this.password,
{
success: function(xmlDoc) {
this.getChannelInfo() // 获取模拟通道
this.getDevicePort() // 获取端口 (影响不大)
}
})
},
// 获取模拟媒体通道
getChannelInfo() {
let self = this
if (!this.szDeviceIdentify) {
return
}
WebVideoCtrl.I_GetAnalogChannelInfo(self.szDeviceIdentify, {
async: false,
success: function (xmlDoc) {
let oChannels = $(xmlDoc).find("VideoInputChannel");
console.log('获取模拟通道成功', oChannels)
$.each(oChannels, function (i) {
let id = $(this).find("id").eq(0).text(),
name = $(this).find("name").eq(0).text();
if (!name) {
name = "Camera " + (i < 9 ? "0" + (i + 1) : (i + 1));
}
self.channels.push({
id: id,
name: name
})
});
},
error: function (status, xmlDoc) {
console.log('获取模拟通道失败', status, xmlDoc)
}
});
},
// 获取端口 不会对预览效果造成影响
getDevicePort() {
if (!this.szDeviceIdentify) {
return
}
let oPort = WebVideoCtrl.I_GetDevicePort(this.szDeviceIdentify);
console.log('获取通道端口号', oPort)
if (oPort != null) {
this.deviceport = oPort.iDevicePort;
this.iRtspPort= oPort.iRtspPort;
}
},
// 开始预览
clickStartRealPlay() {
let self = this
let oWndInfo = WebVideoCtrl.I_GetWindowStatus(self.g_iWndIndex),
iChannelID = self.channels[0].id
if (!this.szDeviceIdentify) {
return;
}
let startRealPlay = function () {
WebVideoCtrl.I_StartRealPlay(self.szDeviceIdentify, {
iRtspPort: parseInt(self.deviceport, 10), // RTSP端口必须是int
iStreamType: 1, // 码流类型1-主码流 必须int
iChannelID: parseInt(iChannelID, 10), // 播放通道 必须int
bZeroChannel: false, // 是否播放零通道 默认false
success: function () {
console.log("预览成功")
},
error: function (status, xmlDoc) {
console.log("预览失败", status, xmlDoc)
}
});
};
if (oWndInfo != null) {// 已经在播放了,先停止
WebVideoCtrl.I_Stop({
success: function () {
startRealPlay();
}
});
} else {
startRealPlay();
}
}
}
}
</script>
<style lang="scss" scoped>
.plugin{
width:100%;
height:calc(100% - 40px)
}
.title {
display: flex;
align-items: center;
font-size: 24px;
font-weight: 700;
margin-bottom: 10px;
color: #fff;
height: 30px;
}
</style>

View File

@@ -1,24 +1,14 @@
<template>
<div class="videos">
<div class="video-item" v-for="item in videoList" :key="item">
<div class="title">
<span>{{ item.name }}</span>
<img
src="@/assets/images/fillScreen.png"
alt=""
width="23px"
style="margin-left: 10px; cursor: pointer"
/>
</div>
<div class="video">
<video
src="https://media.w3.org/2010/05/sintel/trailer_hd.mp4"
controls="controls"
width="100%"
height="100%"
></video>
</div>
<div class="videosPage" id="videosPage">
<div
class="content"
:class="videosPageWidth < 900 ? 'con-w2' : 'con-w1'"
v-for="(item, index) in videoList"
:key="item"
>
<haikang :index="index" :item="item" class="video"></haikang>
</div>
</div>
<div class="environment">
<div class="tab-header">
@@ -35,8 +25,7 @@
:columns="columns[activeTab]"
:table-data="tableDatas[activeTab]"
ref="comTable"
:table-option="{page:false}"
:table-option="{ page: false }"
>
</ComTable>
</div>
@@ -45,9 +34,10 @@
<script>
import { postReq, getReq } from '@/request/api'
import haikang from './haikang.vue'
export default {
name: '',
components: {},
components: { haikang },
props: {
stationId: {
type: String,
@@ -154,11 +144,26 @@ export default {
select: false,
page: false
},
videoList: []
//
videoList: [],
g_iWndIndex: 0,
szDeviceIdentify: '',
deviceport: '',
channels: [],
ip: '',
port: '',
username: '',
password: '',
iRtspPort: '',
videosPageWidth: ''
}
},
mounted() {
console.log(this.systemType)
this.$nextTick(() => {
const div = document.getElementById('videosPage')
const width = div.offsetWidth
this.videosPageWidth = width
})
this.getEnvironment()
this.getDeviceList()
@@ -168,9 +173,8 @@ export default {
try {
const res = await getReq('/queryEnvironment', { station_id: this.stationId })
this.tableDatas = res.data
} catch (error) {
this.tableDatas={}
this.tableDatas = {}
console.log(error)
}
},
@@ -183,6 +187,7 @@ export default {
})
this.videoList = res.data.concat(res.data)
this.videoList = this.videoList.concat(this.videoList)
} catch (error) {
this.videoList = []
@@ -194,30 +199,27 @@ export default {
</script>
<style lang="scss" scoped>
.videos {
.videosPage {
width: calc(100% - 470px);
height: 100%;
margin-left: 20px;
display: grid;
display: flex;
flex-wrap: wrap;
grid-gap: 20px;
overflow-y: auto;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
.video-item {
align-content: flex-start;
justify-content: flex-start;
.content {
border-radius: 15px;
background: $bg2-color;
padding: 15px;
max-height: 290px;
max-width: 400px;
.title {
display: flex;
align-items: center;
font-size: 24px;
font-weight: 700;
color: #fff;
}
.video {
margin-top: 10px;
}
height: 280px;
}
.con-w1 {
width: calc((100% - 40px) / 3);
}
.con-w2 {
width: calc((100% - 20px) / 2);
}
}
.environment {

View File

@@ -81,7 +81,7 @@ export default {
show: true,
xAxisIndex: 0, // 控制第一个X轴
start: 0, // 初始显示范围起点(百分比)
end: 20, // 初始显示范围终点(百分比)
end: 100, // 初始显示范围终点(百分比)
height: 20, // 滑动条高度
bottom: 10 // 距离底部距离
},
@@ -89,7 +89,7 @@ export default {
type: 'inside', // 内置型(鼠标滚轮/拖拽交互)
xAxisIndex: 0,
start: 0,
end: 20
end: 100
}
],
xAxis: {

View File

@@ -1,13 +1,12 @@
<!-- eslint-disable camelcase -->
<template>
<div class="policyForm">
<div class="policyForm" ref="policyForm">
<div class="title">
<div>基础信息</div>
<img src="@/assets/images/titleLine.png" alt="" />
</div>
<a-form
:model="formData"
layout="inline"
label-align="left"
:label-col="{ style: { width: '85px' } }"
:rules="rules"
@@ -30,7 +29,7 @@
</a-select>
</a-form-item>
<a-form-item label="低谷电价" class="col4" required>
<a-form-item label="低谷电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[0]"
@@ -39,7 +38,7 @@
/>
</a-form-item>
<a-form-item label="平段电价" class="col4" required>
<a-form-item label="平段电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[1]"
@@ -48,7 +47,7 @@
/>
</a-form-item>
<a-form-item label="高峰电价" class="col4" required>
<a-form-item label="高峰电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[2]"
@@ -57,7 +56,7 @@
/>
</a-form-item>
<a-form-item label="尖峰电价" class="col4" required>
<a-form-item label="尖峰电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[3]"
@@ -179,7 +178,7 @@
</a-form-item>
</div>
<a-form-item label="策略描述" class="col2">
<a-form-item label="策略描述" class="col1">
<a-textarea v-model:value="formData.describe" :disabled="formStatus == 'read'" />
</a-form-item>
<a-form-item label="是否启用" class="col2">
@@ -193,7 +192,8 @@
</a-form-item>
</a-form>
</div>
<a-modal v-model:open="periodModal" @ok="handlePeriodModalOk">
<a-modal
v-model:open="periodModal" @ok="handlePeriodModalOk" :get-container="()=>$refs.policyForm">
<a-form
ref="periodRef"
:model="periodForm"
@@ -240,6 +240,7 @@ export default {
default: 'add'
}
},
emits:['closeModal'],
data() {
return {
data: [],
@@ -308,8 +309,8 @@ export default {
handler(newVal) {
if (this.formStatus == 'add') {
this.formData = {
type: '5',
name: '测试',
type: '',
name: '',
price: [0, 0, 0, 0],
period1: [],
period5: [
@@ -321,14 +322,7 @@ export default {
chargeType: null,
dischargeType: null
}
// {
// charge_time: [],
// discharge_time: [],
// charge_power: '',
// discharge_power: '',
// chargeType: 1,
// dischargeType:1
// }
],
is_open: false,
chargePolicy: 1
@@ -474,6 +468,7 @@ export default {
console.log(this.formData)
},
handleAdd() {
if(this.formStatus=='read') return
this.periodModal = true
this.periodForm = {}
},
@@ -481,7 +476,6 @@ export default {
this.$refs.periodRef
.validateFields()
.then((res) => {
console.log(this.formData.period1,'=============')
const target = this.formData.period1.find((item) => item.month == this.periodForm.month)
if (target) {
@@ -574,15 +568,18 @@ export default {
img {
width: 232px;
height: 6px;
margin-top: 10px;
// margin-top: 10px;
}
}
}
.ant-form {
display: flex;
flex-wrap:wrap ;
.charge {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
// display: grid;
// grid-template-columns: 1fr 1fr;
// gap: 10px;
.box {
border: 1px solid $table-border;
padding-left: 10px;
@@ -590,6 +587,7 @@ export default {
padding-bottom: 10px;
border-radius: 10px;
color: #fff;
margin-bottom: 10px;
}
}
}
@@ -615,7 +613,7 @@ export default {
.ant-select,
.ant-input-affix-wrapper,
.ant-input-number {
width: 150px;
width: 200px;
}
textarea {
.ant-input {
@@ -627,6 +625,7 @@ export default {
}
.col4 {
width: 25%;
min-width: 270px;
}
.col1 {
width: 100%;
@@ -645,5 +644,10 @@ export default {
:deep(.ant-table-wrapper .ant-table-cell){
background:none!important;
}
:deep(.ant-table-cell){
&::before{
width: 0 !important;
}
}
</style>