Selaa lähdekoodia

Merge remote-tracking branch 'origin/dev-security' into dev-security

xiayu3 4 vuotta sitten
vanhempi
commit
b6f500b56d
21 muutettua tiedostoa jossa 1342 lisäystä ja 335 poistoa
  1. 6 3
      security-protection-platform/package.json
  2. 25 0
      security-protection-platform/src/api/dashboard/index.js
  3. 6 2
      security-protection-platform/src/api/system/index.js
  4. 7 3
      security-protection-platform/src/api/videoSurveillance/index.js
  5. BIN
      security-protection-platform/src/assets/images/indexT1.png
  6. BIN
      security-protection-platform/src/assets/images/indexT2.png
  7. BIN
      security-protection-platform/src/assets/images/indexTitle.png
  8. BIN
      security-protection-platform/src/assets/images/indexTop.png
  9. BIN
      security-protection-platform/src/assets/images/polygon.png
  10. 128 0
      security-protection-platform/src/components/VideoPlayer/index.vue
  11. 476 1
      security-protection-platform/src/modules/dashboard/index.vue
  12. 25 4
      security-protection-platform/src/modules/system/monitor/HomePageSettings/AreaMonitor.vue
  13. 11 6
      security-protection-platform/src/modules/system/monitor/HomePageSettings/Card.vue
  14. 6 5
      security-protection-platform/src/modules/system/monitor/HomePageSettings/UpdateName.vue
  15. 27 62
      security-protection-platform/src/modules/system/monitor/VideoMonitor/ShiftSceneDialog.vue
  16. 290 139
      security-protection-platform/src/modules/system/monitor/VideoMonitor/index.vue
  17. 10 4
      security-protection-platform/src/modules/system/monitor/components/ViewCard/UpdateName.vue
  18. 21 26
      security-protection-platform/src/modules/system/monitor/components/ViewCard/index.vue
  19. 173 0
      security-protection-platform/src/modules/videoSurveillance/components/ReplayDialog/index.vue
  20. 130 80
      security-protection-platform/src/modules/videoSurveillance/index.vue
  21. 1 0
      security-protection-platform/src/styles/index.scss

+ 6 - 3
security-protection-platform/package.json

@ -61,8 +61,7 @@
61 61
    "stylelint-order": "^0.7.0",
62 62
    "stylelint-scss": "^2.1.0",
63 63
    "vue-loader": "^14.2.3",
64
    "vue-template-compiler": "^2.2.1",
65
    "vuedraggable": "2.19"
64
    "vue-template-compiler": "^2.2.1"
66 65
  },
67 66
  "dependencies": {
68 67
    "aid-elements-desktop": "latest",
@ -75,6 +74,10 @@
75 74
    "vuex": "^2.3.1",
76 75
    "vuex-router-sync": "^4.1.2",
77 76
    "js-cookie": "",
78
    "element-ui": "2.14.1"
77
    "element-ui": "2.14.1",
78
    "vuedraggable": "2.19",
79
    "video.js": "7.10.2",
80
    "videojs-playlist": "4.3.1",
81
    "echarts": "^4.9.0"
79 82
  }
80 83
}

+ 25 - 0
security-protection-platform/src/api/dashboard/index.js

@ -0,0 +1,25 @@
1
import http from '@/http'
2
3
const { $default } = http
4
5
const api = {
6
  // 出勤(饼状图)
7
  queryAttendanceChart () {
8
    return $default.get('/sp/homePage/queryAttendanceChart', {}).then(resp => {
9
      return resp.data
10
    })
11
  },
12
  // 报警(柱状图)
13
  queryAlarmAnalysisChart () {
14
    return $default.get('/sp/homePage/queryAlarmAnalysisChart', {}).then(resp => {
15
      return resp.data
16
    })
17
  },
18
  // 报警(TOP4)
19
  queryAlarmAnalysisTopList () {
20
    return $default.get('/sp/homePage/queryAlarmAnalysisTopList', {}).then(resp => {
21
      return resp.data
22
    })
23
  }
24
}
25
export default api

+ 6 - 2
security-protection-platform/src/api/system/index.js

@ -157,14 +157,18 @@ const api = {
157 157
      return $default.delete(`/sp/monitorSceneTerminal/deleteMonitorSceneTerminalRelByRelId?monitorSceneTerminalRelId=${data.monitorSceneTerminalRelId}`)
158 158
    }
159 159
  },
160
  moveTerminalRelIndex(data) {
161
    return $default.put('/sp/monitorSceneTerminal/moveMonitorSceneTerminalRelIndex', data)
160
  moveTerminalRelIndex(params) {
161
    params = keysMapping(params, mappingMonitor, false)
162
    return $default.put('/sp/monitorSceneTerminal/moveMonitorSceneTerminalRelIndex', {params})
162 163
  },
163 164
  getOneMonitorScene(monitorSceneId) {
164 165
    return $default.get(`/sp/monitorSceneManagement/queryOneMonitorScene?monitorSceneId=${monitorSceneId}`)
165 166
  },
166 167
  getqueryMonitorSceneLayoutList() {
167 168
    return $default.get(`/sp/monitorSceneManagement/queryMonitorSceneLayoutList`)
169
  },
170
  getDepartments() {
171
    return $default.get('/sp/workEmployee/queryAllOrganize')
168 172
  }
169 173
}
170 174

+ 7 - 3
security-protection-platform/src/api/videoSurveillance/index.js

@ -1,14 +1,18 @@
1 1
import http from '@/http'
2
const { $http } = http
2
const { $http, $default } = http
3 3
4 4
const api = {
5 5
  // 获取风场大门表格数据
6
  getVideoSurveillanceData(params) {
6
  getVideoSurveillanceData (params) {
7 7
    return $http.get('/videoSurveillance/getVideoSurveillanceData', params)
8 8
  },
9 9
  // 获取识别记录数据
10
  getDistinguishData(params) {
10
  getDistinguishData (params) {
11 11
    return $http.get('/videoSurveillance/getDistinguishData', params)
12
  },
13
  // 视频回放
14
  getVideoPlayBack (id) {
15
    return $default.get(`/sp/uploadFile/getFileUrl?fileName=${id}`).catch((err) => { return err })
12 16
  }
13 17
}
14 18
export default api

BIN
security-protection-platform/src/assets/images/indexT1.png


BIN
security-protection-platform/src/assets/images/indexT2.png


BIN
security-protection-platform/src/assets/images/indexTitle.png


BIN
security-protection-platform/src/assets/images/indexTop.png


BIN
security-protection-platform/src/assets/images/polygon.png


+ 128 - 0
security-protection-platform/src/components/VideoPlayer/index.vue

@ -0,0 +1,128 @@
1
<template>
2
  <div>
3
    <video ref="player" class="video-js vjs-default-skin vjs-big-play-centered"></video>
4
  </div>
5
</template>
6
7
<script>
8
import videojs from 'video.js'
9
10
window.videojs = videojs
11
12
require('videojs-playlist')
13
require('video.js/dist/lang/zh-CN.js')
14
require('video.js/dist/video-js.min.css')
15
16
const defaultPlayerOptions = {
17
  controls: true,
18
  autoplay: false,
19
  muted: false,
20
  language: 'zh-CN',
21
  fluid: true,
22
  // liveui: true,
23
  controlBar: {
24
    children: [
25
      {name: 'playToggle'}, // 播放按钮
26
      {name: 'currentTimeDisplay'}, // 当前已播放时间
27
      {name: 'progressControl'}, // 播放进度条
28
      {name: 'durationDisplay'}, // 总时间
29
      { // 倍数播放
30
        name: 'playbackRateMenuButton',
31
        playbackRates: [0.5, 1, 1.5, 2, 2.5]
32
      },
33
      {
34
        name: 'volumePanel', // 音量控制
35
        inline: false // 不使用水平方式
36
      },
37
      {name: 'FullscreenToggle'} // 全屏
38
    ]
39
  }
40
}
41
42
export default {
43
  name: 'VideoPlayer',
44
  props: {
45
    sources: {
46
      type: Array,
47
      default: () => []
48
    },
49
    options: {
50
      type: Object,
51
      default() { return {} }
52
    },
53
    autoadvance: {
54
      type: Number,
55
      default: null
56
    }
57
  },
58
  data() {
59
    const playerOptions = Object.assign({}, defaultPlayerOptions, this.options)
60
    return {
61
      player: null,
62
      playerOptions
63
    }
64
  },
65
  computed: {
66
    playlist() {
67
      return this.sources
68
    }
69
  },
70
  watch: {
71
    playlist: {
72
      handler(list) {
73
        if (!this.player) return
74
        this.player.playlist(list)
75
        if (list.length > 0) {
76
          this.player.playlist.autoadvance(this.autoadvance)
77
          // this.player.playlist.first();
78
        }
79
        this.$emit('playlistchange', list)
80
      },
81
      immediate: true
82
    }
83
  },
84
  mounted() {
85
    this.init()
86
  },
87
  beforeDestroy() {
88
    if (this.player) {
89
      this.player.dispose()
90
    }
91
  },
92
  methods: {
93
    init() {
94
      const player = videojs(this.$refs.player, this.playerOptions)
95
      this.player = player
96
      this.player.on('playlistitem', (...args) => {
97
        this.$emit('playlistitem', ...args)
98
      })
99
      this.$emit('player-inited', player)
100
    }
101
  }
102
}
103
</script>
104
105
<style lang="scss">
106
107
.vjs-paused .vjs-big-play-button,
108
.vjs-paused.vjs-has-started .vjs-big-play-button {
109
    display: block;
110
}
111
112
.vjs-slider-vertical .vjs-volume-level:before {
113
  top: -.4em;
114
  left: -.4em;
115
}
116
117
.video-js {
118
  .vjs-play-progress:before {
119
    top: -.5em;
120
    transform-origin: center;
121
  }
122
  .vjs-progress-control:hover {
123
      .vjs-play-progress:before {
124
        transform: translateY(0.17em);
125
      }
126
    }
127
}
128
</style>

+ 476 - 1
security-protection-platform/src/modules/dashboard/index.vue

@ -1,13 +1,488 @@
1 1
<template>
2
  <div>首页</div>
2
  <div class="index">
3
    <div :style="`background-image: url(${imgBg})`" class="top" >
4
      <img src="@/assets/images/brand.png" class="top-logo">
5
    </div>
6
    <div>
7
      <div class="time"><span style="color: #00d8f3;font-size: 21px;">{{ nowDate | dateFormat }}</span></div>
8
      <div class="goto"><t-icon icon="arrow-right-outline"></t-icon>进入系统</div>
9
    </div>
10
    <div class="body">
11
      <div class="body-left">
12
        <div :style="`height:260px`" class="body-left-item">
13
          <div :style="`background-image: url(${titleImgBg})`" class="title">
14
            <span class="title-span">出勤统计</span>
15
          </div>
16
          <div id="doughnut" style="height: 100%"></div>
17
        </div>
18
        <div :style="`height:260px;margin-top: 24px;`" class="body-left-item">
19
          <div :style="`background-image: url(${titleImgBg})`" class="title">
20
            <span class="title-span">告警分析</span>
21
          </div>
22
          <div id="bar" style="height: 100%"></div>
23
        </div>
24
        <div :style="`height:220px;margin-top: 24px;`" class="body-left-item">
25
          <div :style="`background-image: url(${titleImgBg})`" class="title">
26
            <span class="title-span">近24h告警</span>
27
          </div>
28
          <div class="top4">
29
            <t-row :gutter="2" align="center" class="top4-row">
30
              <t-col span="6">
31
                <div :style="`background-image: url(${polygon})`" class="polygon">1</div>
32
                &nbsp;&nbsp;{{ topData[0].name }}</t-col>
33
              <t-col span="2" offset="4">{{ topData[0].value }}个</t-col>
34
            </t-row>
35
            <t-row :gutter="2" align="center" class="top4-row">
36
              <t-col span="6">
37
                <div :style="`background-image: url(${polygon})`" class="polygon">2</div>
38
                &nbsp;&nbsp;{{ topData[1].name }}</t-col>
39
              <t-col span="2" offset="4">{{ topData[1].value }}个</t-col>
40
            </t-row>
41
            <t-row :gutter="2" align="center" class="top4-row">
42
              <t-col span="6">
43
                <div :style="`background-image: url(${polygon})`" class="polygon">3</div>
44
                &nbsp;&nbsp;{{ topData[2].name }}</t-col>
45
              <t-col span="2" offset="4">{{ topData[2].value }}个</t-col>
46
            </t-row>
47
            <t-row :gutter="2" align="center" class="top4-row">
48
              <t-col span="6">
49
                <div :style="`background-image: url(${polygon})`" class="polygon">4</div>
50
                &nbsp;&nbsp;{{ topData[3].name }}</t-col>
51
              <t-col span="2" offset="4">{{ topData[3].value }}个</t-col>
52
            </t-row>
53
          </div>
54
        </div>
55
      </div>
56
      <div class="body-center">
57
        <div :style="`background-image: url(${titleImgBg})`" class="title" style="width: 370px;">
58
          <span class="title-span">重点区域监控</span>
59
        </div>
60
        <img src="@/assets/images/indexT1.png" style="width: 730px;height: 730px;padding-left: 20px;padding-top: 10px;">
61
      </div>
62
      <div class="body-right">
63
        <div :style="`background-image: url(${titleImgBg})`" class="title" style="width: 330px;">
64
          <span class="title-span">人员进出识别</span>
65
        </div>
66
        <img src="@/assets/images/indexT2.png" style="width: 325px;height: 730px;padding-left: 15px;padding-top: 10px;">
67
      </div>
68
    </div>
69
  </div>
3 70
</template>
4 71
5 72
<script>
73
import imgBg from '@/assets/images/indexTop.png'
74
import titleImgBg from '@/assets/images/indexTitle.png'
75
import polygon from '@/assets/images/polygon.png'
76
import echarts from 'echarts'
77
import dasapi from '@/api/dashboard'
78
6 79
export default {
80
  filters: {
81
    dateFormat(value) {
82
      var year = value.getFullYear()
83
      var month = value.getMonth() + 1
84
      month >= 10 ? month : '0' + month
85
      var day = value.getDate() >= 10 ? value.getDate() : '0' + value.getDate()
86
      var hours =
87
          value.getHours() >= 10 ? value.getHours() : '0' + value.getHours()
88
      var minutes =
89
          value.getMinutes() >= 10
90
            ? value.getMinutes()
91
            : '0' + value.getMinutes()
92
      var seconds =
93
          value.getSeconds() >= 10
94
            ? value.getSeconds()
95
            : '0' + value.getSeconds()
96
      return (
97
        year +
98
          '年' +
99
          month +
100
          '月' +
101
          day +
102
          '日 ' +
103
          hours +
104
          ':' +
105
          minutes +
106
          ':' +
107
          seconds
108
      )
109
    }
110
  },
111
  components: {},
112
  data() {
113
    return {
114
      nowDate: new Date(),
115
      imgBg: imgBg,
116
      titleImgBg: titleImgBg,
117
      polygon: polygon,
118
      attendanceData: [],
119
      population: 0,
120
      alarmDataX: [],
121
      alarmDataY: [],
122
      topData: [
123
        {name: '未戴安全帽', value: 0},
124
        {name: '人员聚集', value: 0},
125
        {name: '吸烟', value: 0},
126
        {name: '摔倒', value: 0}]
127
    }
128
  },
129
  computed: {
130
  },
131
  mounted () {
132
    setInterval(() => { // 当前时间
133
      this.nowDate = new Date()
134
    }, 1000)
135
    this.initAttendance()
136
    this.initAlarm()
137
    this.init24Top()
138
  },
139
  methods: {
140
    initAttendance() {
141
      debugger
142
      this.attendanceData = dasapi.queryAttendanceChart().then(res => {
143
        debugger
144
        this.population = res.data.totalSize
145
        res.data.dataList.forEach(e => {
146
          if (e.name === '在岗') {
147
            e.itemStyle = { color: '#00A7F4' }
148
          }
149
          if (e.name === '请假') {
150
            e.itemStyle = { color: '#FFCE00' }
151
          }
152
          if (e.name === '缺勤') {
153
            e.itemStyle = { color: '#FF3F00' }
154
          }
155
        })
156
        this.attendanceData = res.data.dataList
157
        this.initAttendanceData()
158
      })
159
    },
160
    initAlarm() {
161
      debugger
162
      this.population = dasapi.queryAlarmAnalysisChart().then(res => {
163
        debugger
164
        res.data.forEach(e => {
165
          this.alarmDataX.push(e.name)
166
          this.alarmDataY.push(e.value)
167
        })
168
        this.initAlarmData()
169
      })
170
    },
171
    init24Top() {
172
      debugger
173
      this.topData = dasapi.queryAlarmAnalysisTopList().then(res => {
174
        debugger
175
        this.topData = res.data
176
      })
177
    },
178
    initAttendanceData() {
179
      var dom = document.getElementById('doughnut')
180
      var myChart = echarts.init(dom)
181
      var option = null
182
183
      option = {
184
        tooltip: {
185
          trigger: 'item',
186
          formatter: '{a} <br/>{b} : {c}人 ({d}%)'
187
        },
188
        legend: {
189
          bottom: '20%',
190
          left: 'center',
191
          data: this.attendanceData,
192
          formatter: this.legendFormatter,
193
          textStyle: {
194
            color: '#fff'
195
          }
196
        },
197
        graphic: [ // 为环形图中间添加文字
198
          {
199
            type: 'text',
200
            left: 'center',
201
            top: '38%',
202
            style: {
203
              text: this.population + '人',
204
              textAlign: 'center',
205
              fill: '#ffffff',
206
              fontSize: 12
207
            }
208
          }
209
        ],
210
        series: [
211
          {
212
            type: 'pie',
213
            radius: ['25%', '40%'],
214
            center: ['50%', '40%'],
215
            name: '出勤统计',
216
            label: {
217
              normal: {
218
                formatter: '{d}%  '
219
              }
220
            },
221
            data: this.attendanceData,
222
            emphasis: {
223
              itemStyle: {
224
                shadowBlur: 10,
225
                shadowOffsetX: 0,
226
                shadowColor: 'rgba(0, 0, 0, 0.5)'
227
              }
228
            }
229
          }
230
        ]
231
      }
232
      if (option && typeof option === 'object') {
233
        myChart.setOption(option, true)
234
      }
235
    },
236
    legendFormatter(data) {
237
      var legend
238
      this.attendanceData.forEach(e => {
239
        if (data === e.name) {
240
          legend = e.value
241
        }
242
      })
243
      return data + ': ' + legend + '人'
244
    },
245
    initAlarmData() {
246
      var dom = document.getElementById('bar')
247
      var myChart = echarts.init(dom)
248
      var option = null
249
      var gridWidth = 320 // 可以根据canvas的宽度和grid的right,left,width进行计算
250
      var fontsize = 12 // 字体大小
251
      var wordNum = parseInt((gridWidth / this.alarmDataX.length) / fontsize);
252
      var flag = 0
253
      this.alarmDataX.forEach(value => {
254
        var strs = value.split('')
255
        var str = ''
256
        for (var i = 0, s; s = strs[i++];) {
257
          str += s
258
          if (!(i % wordNum)) {
259
            flag = -20
260
          }
261
        }
262
      })
263
      option = {
264
        color: ['#3398DB'],
265
        tooltip: {
266
          trigger: 'axis',
267
          axisPointer: { // 坐标轴指示器,坐标轴触发有效
268
            type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
269
          }
270
        },
271
        grid: {
272
          left: '4%',
273
          right: '7%',
274
          bottom: '15%',
275
          top: '10%',
276
          containLabel: true
277
        },
278
        xAxis: [
279
          {
280
            type: 'category',
281
            data: this.alarmDataX,
282
            axisTick: {
283
              alignWithLabel: true
284
            },
285
            axisLabel: {
286
              show: true,
287
              interval: 0,
288
              rotate: flag,
289
              textStyle: {
290
                fontSize: 12,
291
                color: '#fff'
292
              }
293
            }
294
          }
295
        ],
296
        yAxis: [
297
          {
298
            type: 'value',
299
            axisLabel: {
300
              show: true,
301
              textStyle: {
302
                fontSize: 13,
303
                color: '#fff'
304
              }
305
            },
306
            splitLine: {
307
              show: false
308
            }
309
          }
310
        ],
311
        series: [
312
          {
313
            name: '数量',
314
            type: 'bar',
315
            barWidth: '40%',
316
            data: this.alarmDataY,
317
            itemStyle: {
318
              normal: {
319
                color: new echarts.graphic.LinearGradient(
320
                  0, 0, 0, 1,
321
                  [
322
                    {offset: 0, color: '#00FEFF'},
323
                    {offset: 1, color: '#0C7EFC'}
324
                  ]
325
                ),
326
                label: {
327
                  show: true, // 是否展示
328
                  position: 'top', // 在上方显示
329
                  formatter: function(name) {
330
                    return name.value + '人'
331
                  },
332
                  textStyle: {
333
                    fontSize: 14,
334
                    color: '#fff'
335
                  }
336
                }
337
              }
338
            }
7 339
340
          }
341
        ]
342
      }
343
      if (option && typeof option === 'object') {
344
        myChart.setOption(option, true)
345
      }
346
    }
347
  }
8 348
}
9 349
</script>
10 350
11 351
<style lang="scss">
352
.index{
353
  width: 1500px;
354
  height: 880px;
355
  background-color: #011d40;
356
  .time{
357
    width: 500px;
358
    height: 28px;
359
    padding-left: 48px;
360
    margin-top: -14px;
361
  }
362
  .goto{
363
    display:block;
364
    float:right;
365
    margin-top: -30px;
366
    width: 122px;
367
    height: 40px;
368
    border-radius: 5px;
369
    background-color: #011d40; /* 浏览器不支持的时候显示 */
370
    box-shadow: 0 0 30px -10px #009bf3 inset;
371
    margin-right: 10px;
372
    align-items: center;
373
    text-align: center;
374
    padding-top: 6px;
375
    color:#00d8f3;
376
    font-size: 18px;
377
  }
378
  .top{
379
    -moz-background-size:100% 100%;
380
    background-size:100% 100%;
381
    display: flex;
382
    align-items: center;
383
    text-align: center;
384
    height: 45.1px;
385
    width: 1500px;
386
    overflow: hidden;
387
    position: relative;
388
    .top-logo{
389
      position: absolute;
390
      top:50%;
391
      left:50%;
392
      transform: translate(-50%,-50%);
393
      height: 24px;
394
      width: 400px;
395
      vertical-align: middle
396
    }
397
  }
398
  .body{
399
    display: flex;
400
    width: 1500px;
401
    padding-top: 5px;
402
    justify-content: space-around;
403
    .body-left{
404
      width: 340px;
405
      height: 788px;
406
      .body-left-item{
407
        width: 340px;
408
        border-radius: 5px;
409
        background-color: #011d40; /* 浏览器不支持的时候显示 */
410
        box-shadow: 0 0 30px -10px #009bf3 inset;
411
        .top4{
412
          padding-left: 15px;
413
          padding-right: 15px;
414
          color: #00d8f3;
415
          font-size: 15px;
416
          font-family: "Microsoft YaHei";
417
          height: 100%;
418
          .top4-row{
419
            border: 0 none;
420
            border-bottom: 2px dotted #00466b;
421
            height: 20%;
422
            .col-6{
423
              display: flex;
424
              .polygon{
425
                -moz-background-size:100% 100%;
426
                background-size:100% 100%;
427
                align-items: center;
428
                text-align: center;
429
                height: 100%;
430
                width: 16%;
431
              }
432
            }
433
          }
434
        }
435
      }
436
    }
437
    .body-center{
438
      width: 750px;
439
      height: 788px;
440
      border-radius: 5px;
441
      background-color: #011d40; /* 浏览器不支持的时候显示 */
442
      box-shadow: 0 0 30px -10px #009bf3 inset;
443
    }
444
    .body-right{
445
      width: 340px;
446
      height: 788px;
447
      border-radius: 5px;
448
      background-color: #011d40; /* 浏览器不支持的时候显示 */
449
      box-shadow: 0 0 30px -10px #009bf3 inset;
450
    }
451
  }
452
  .title{
453
    -moz-background-size:100% 100%;
454
    background-size:100% 100%;
455
    align-items: center;
456
    text-align: center;
457
    height: 28px;
458
    width: 340px;
459
    margin: 0 auto;
460
    .title-span{
461
      height: 28px;
462
      align-items: center;
463
      text-align: center;
464
      font-size: 14px;
465
      color: #00d8f3;
466
      margin: auto;
467
    }
468
  }
469
  .titleWide{
470
    -moz-background-size:100% 100%;
471
    background-size:100% 100%;
472
    align-items: center;
473
    text-align: center;
474
    height: 28px;
475
    width: 350px;
476
    margin: 0 auto;
477
    .title-span{
478
      height: 28px;
479
      align-items: center;
480
      text-align: center;
481
      font-size: 14px;
482
      color: #00d8f3;
483
      margin: auto;
484
    }
485
  }
12 486
487
}
13 488
</style>

+ 25 - 4
security-protection-platform/src/modules/system/monitor/HomePageSettings/AreaMonitor.vue

@ -162,7 +162,11 @@ export default {
162 162
        sysapi
163 163
          .modifyTerminalRel(target)
164 164
          .then((resp) => {
165
            this.$Message.success('修改成功')
165
            if (resp.data.success === false) {
166
              this.$Message.danger(resp.data.fail.message)
167
            } else {
168
              this.$Message.success('修改成功')
169
            }
166 170
          }).catch((error) => {
167 171
            console.log(error)
168 172
            this.$Message.danger('修改失败')
@ -172,7 +176,11 @@ export default {
172 176
      } else {
173 177
        sysapi.createTerminalRel(data)
174 178
          .then((resp) => {
175
            this.$Message.success('增添成功')
179
            if (resp.data.success === false) {
180
              this.$Message.danger(resp.data.fail.message)
181
            } else {
182
              this.$Message.success('增添成功')
183
            }
176 184
          })
177 185
          .catch((error) => {
178 186
            console.log(error)
@ -183,8 +191,21 @@ export default {
183 191
      }
184 192
    },
185 193
    datadragEnd(evt) {
186
      console.log('拖动前的索引 :' + this.areaMonitorList[evt.oldIndex].title)
187
      console.log('拖动后的索引 :' + this.areaMonitorList[evt.newIndex].title)
194
      if (evt.oldIndex !== evt.newIndex) {
195
        let params = {
196
          monitorSceneTerminalRelId: this.areaMonitorList[evt.oldIndex].monitorSceneTerminalRelId, // 场景与终端关联ID
197
          monitorSceneId: this.monitorScene.monitorSceneId, // 场景ID
198
          resourceToolId: this.areaMonitorList[evt.oldIndex].resourceToolId, // 终端ID
199
          resourceToolIndex: this.areaMonitorList[evt.newIndex].resourceToolIndex // 移动位置序号
200
        }
201
        sysapi.moveTerminalRelIndex(params).then((resp) => {})
202
          .catch((error) => {
203
            console.log(error)
204
            this.$Message.danger('修改位置失败')
205
          }).finally(() => {
206
            this.geTerminalRel()
207
          })
208
      }
188 209
    }
189 210
  }
190 211
}

+ 11 - 6
security-protection-platform/src/modules/system/monitor/HomePageSettings/Card.vue

@ -5,7 +5,7 @@
5 5
        <img :style="{ height: gridHeight, width: gridWidth }" :src="data.pictureUrl" alt="" />
6 6
      </div>
7 7
      <div class="opt">
8
        <t-button shape="round" icon="arrow-expand-all-outline" style="margin: 0px 0px 0px 0px">移动</t-button>
8
        <div class="move">拖拽移动</div>
9 9
        <t-button shape="round" icon="swap-outline" style="margin: 0px 2px 0px 2px" @click="handleEdit">替换</t-button>
10 10
        <t-button shape="round" icon="delete" @click="handleDelete">删除</t-button>
11 11
        <div v-show="showConfirm" class="popover">
@ -76,6 +76,9 @@ export default {
76 76
        this.$emit('nameChange', this.data)
77 77
      }
78 78
    },
79
    handleDelete() {
80
      this.showConfirm = true
81
    },
79 82
    handleConfirmDelete() {
80 83
      // 把事件抛出去,保持控件的干净
81 84
      this.$emit('deleted', this.data)
@ -83,9 +86,6 @@ export default {
83 86
    handleEdit() {
84 87
      this.$emit('edit', this.data)
85 88
    },
86
    handleDelete() {
87
      this.showConfirm = true
88
    },
89 89
    handleCancelDelete() {
90 90
      this.showConfirm = false
91 91
    }
@ -108,7 +108,12 @@ export default {
108 108
      display: flex;
109 109
      justify-content: center;
110 110
      align-items: center;
111
111
    .move{
112
      color: rgb(255, 255, 255);
113
      position: absolute;
114
      top: 12px;
115
      text-align: center;
116
    }
112 117
      &::before {
113 118
        content: "";
114 119
        display: block;
@ -117,7 +122,7 @@ export default {
117 122
        top: 0;
118 123
        width: 100%;
119 124
        height: 100%;
120
        background-color: black;
125
        background-color: #00000038;
121 126
        border-radius: 4px;
122 127
        opacity: 0.8;
123 128
      }

+ 6 - 5
security-protection-platform/src/modules/system/monitor/HomePageSettings/UpdateName.vue

@ -1,5 +1,5 @@
1 1
<template>
2
  <div class="div-base">
2
  <div class="update-name">
3 3
    <div v-if="text_tatus == 0" @mouseover="mouseOver">
4 4
      {{ name }}
5 5
    </div>
@ -65,11 +65,12 @@ export default {
65 65
</script>
66 66
67 67
<style lang="scss">
68
.div-base {
69
  margin: 5px 10px 0px 10px;
68
.update-name {
69
  font-size: 14px;
70
  padding: 0 5px;
71
70 72
  .iconChange {
71
    margin: -5px 0px 0px 0px;
72
    height: 24px;
73
    height: 20px;
73 74
    float: right;
74 75
  }
75 76
}

+ 27 - 62
security-protection-platform/src/modules/system/monitor/VideoMonitor/ShiftSceneDialog.vue

@ -4,6 +4,7 @@
4 4
    :title="title"
5 5
    :mask-closable="false"
6 6
    :ok="handleSubmit"
7
    :cancel="handlecancel"
7 8
    width="500px"
8 9
    height="300px"
9 10
  >
@ -12,7 +13,7 @@
12 13
        <t-col style="text-align: center" span="3">场景名称:</t-col>
13 14
        <t-col span="9">
14 15
          <t-input
15
            v-model="data.sceneName"
16
            v-model="form.monitorSceneName"
16 17
            placeholder="请输入..."
17 18
            style="width: 250px"
18 19
          >
@ -24,17 +25,18 @@
24 25
        >布&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;局:</t-col
25 26
        >
26 27
        <t-col span="9">
27
          <t-radio-group v-model="data.displayType" type="button">
28
            <t-radio value="1" label="1X1"></t-radio>
29
            <t-radio value="2" label="2X2"></t-radio>
30
            <t-radio value="3" label="3X3"></t-radio>
31
          <t-radio value="4" label="4X4"></t-radio> </t-radio-group
32
        ></t-col>
28
          <t-radio-group v-model="form.monitorViewLayout" type="button">
29
            <t-radio v-for="layout in SceneLayoutList" :key="layout.layoutCode"
30
                     :value="layout.layoutCode" :label="layout.layoutName"></t-radio>
31
32
          </t-radio-group>
33
        </t-col>
33 34
      </t-row>
34 35
      <t-row>
35 36
        <t-col span="3"></t-col>
36 37
        <t-col span="9"
37 38
        ><t-button
39
          v-if="form.monitorSceneId != null "
38 40
          ghost
39 41
          color="info"
40 42
          icon="delete-outline"
@ -87,6 +89,7 @@ export default {
87 89
    return {
88 90
      visibled: false,
89 91
      form: {},
92
      SceneLayoutList: [],
90 93
      searchValue: null,
91 94
      loadingSubmit: false,
92 95
      showConfirm: false,
@ -95,7 +98,7 @@ export default {
95 98
  },
96 99
  computed: {
97 100
    title() {
98
      return this.data.id == null ? '新增场景' : '编辑场景'
101
      return this.data.monitorSceneId == null ? '新增场景' : '编辑场景'
99 102
    }
100 103
  },
101 104
  watch: {
@ -105,72 +108,34 @@ export default {
105 108
      this.visibled = true
106 109
    }
107 110
  },
111
  mounted() {
112
    this.getLayoutList()
113
  },
108 114
  methods: {
109
    getCameras() {
110
      sysapi.getCameras().then((resp) => {
111
        this.cameraList = resp.data || []
115
    getLayoutList() {
116
      sysapi.getqueryMonitorSceneLayoutList().then((resp) => {
117
        this.SceneLayoutList = resp.data.data || []
112 118
      })
113 119
    },
114
    groupClick(item) {
115
      // 选中更换摄像头
116
      if (this.form.title == null) {
117
        this.form.title = item.title
118
      }
119
      this.form.cameraId = item.cameraId
120
      this.form.imgsrc = item.imgsrc
121
    },
122 120
    handleDelete() {
123 121
      this.showConfirm = true
124 122
    },
123
    // 保存
125 124
    handleSubmit() {
126
      this.loadingSubmit = true
127
      sysapi
128
        .submitSchedule(this.form)
129
        .then(
130
          (resp) => {
131
            if (resp.data.areaMonitorId == null) {
132
              this.form.areaMonitorId = resp.data.areaMonitorId
133
            }
134
            this.$emit('submit', this.form)
135
            this.visibled = false
136
            this.$Message.success('提交成功')
137
          },
138
          (err) => {
139
            console.log(err)
140
            this.$Message.danger('提交失败')
141
          }
142
        )
143
        .finally(() => {
144
          this.loadingSubmit = false
145
        })
146
    },
147
    onChange(page) {
148
      this.page = page
149
      this.getAreaMonitors()
125
      this.$emit('submit', this.form)
150 126
    },
151 127
    handleCancelDelete() {
152 128
      this.showConfirm = false
153 129
    },
130
    // 删除场景
154 131
    handleConfirmDelete() {
155
      // this.loadingDelete = true;
156
157
      this.$emit('deleted', this.data)
158
      //   sysapi
159
      //     .deleteSchedule(this.data.scheduleId)
160
      //     .then(
161
      //       (resp) => {
162
      //         console.log(resp);
163
      //         this.$emit("deleted", this.data);
164
      //       },
165
      //       (err) => {
166
      //         console.log(err);
167
      //         this.$Message.danger("删除失败,请稍后再试!", 3);
168
      //       }
169
      //     )
170
      //     .finally(() => {
171
      //       this.loadingDelete = false;
172
      //       this.showConfirm = false;
173
      //     });
132
      this.showConfirm = false
133
      this.visibled = false
134
      this.$emit('deleted', this.form)
135
    },
136
    handlecancel() {
137
    // 有问题
138
    // this.$forceUpdate()
174 139
    }
175 140
  }
176 141
}

+ 290 - 139
security-protection-platform/src/modules/system/monitor/VideoMonitor/index.vue

@ -5,76 +5,98 @@
5 5
        <t-col>
6 6
          <div style="float: left">
7 7
            <span>风场: </span>
8
            <t-select v-model="currentWindPlaceValue" style="width: 200px; height: 32px">
9
              <t-option value="1">风场1</t-option>
10
              <t-option value="2">风场2</t-option>
8
            <t-select
9
              v-model="currentWindPlaceValue"
10
              style="width: 200px; height: 32px"
11
              @change="WindPlaceChenged"
12
            >
13
              <t-option
14
                v-for="item in departmentList"
15
                :key="item.code"
16
                :value="item.code"
17
              >{{ item.name }}</t-option
18
              >
11 19
            </t-select>
12 20
          </div>
13 21
        </t-col>
14
        <t-col>
15
          <div style="float: right">
16
            <t-button-group>
17
              <t-button :class="['base', btnIsClicked ? 'active' : '']" @click="btnOnClick('areaMonitor')">
18
                <span>大门</span>
19
                <div v-if="dialogSceneData.id == '1'" style="float: right; width: 14px; height: 14px" @click="handleSceneEdit('123')">
20
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
21
                </div>
22
              </t-button>
23
24
              <t-button :class="['base', btnIsClicked ? 'active' : '']" @click="btnOnClick('areaMonitor')">
25
                <span>值班室</span>
26
                <div v-if="dialogSceneData.id == '456'" style="float: right; width: 14px; height: 14px" @click="handleSceneEdit('456')">
27
                  <t-icon icon="edit" shape="circle" class="ico"></t-icon>
22
        <t-col span="8">
23
          <div>
24
            <t-button-group style="float: right">
25
              <t-button
26
                v-for="item in monitorSceneList"
27
                :key="item.monitorSceneId"
28
                :class="[
29
                  'base',
30
                  item.monitorSceneId == currenScene.monitorSceneId
31
                    ? 'active'
32
                    : '',
33
                ]"
34
                style="
35
                  display: inline-block;
36
                  -moz-appearance: button;
37
                  -webkit-appearance: button;
38
                  appearance: button;
39
                "
40
                @click="handleSceneOnClick(item)"
41
              >
42
                <div>
43
                  {{ item.monitorSceneName }}
44
                  <div class="div_edit" @click.stop="handleSceneEdit(item)">
45
                    <t-icon
46
                      v-if="item.monitorSceneId == currenScene.monitorSceneId"
47
                      icon="edit"
48
                      shape="circle"
49
                      class="ico"
50
                    ></t-icon>
51
                  </div>
28 52
                </div>
29 53
              </t-button>
54
              <t-button
55
                style="48px"
56
                icon="plus-outline"
57
                @click="btnAddClick()"
58
              ></t-button>
30 59
            </t-button-group>
31
            <t-button style="width: 48px" @click="btnAddClick()">+</t-button>
32 60
          </div>
33 61
        </t-col>
34 62
      </t-row>
35 63
      <t-row>
36
        <t-col style="margin-top:10px;">
37
          <t-button color="info" icon="plus-circle" @click="handleCreate">新增监控</t-button>
64
        <t-col style="margin-top: 10px">
65
          <t-button color="info" icon="plus-circle" @click="handleCreate"
66
          >新增监控</t-button
67
          >
38 68
        </t-col>
39 69
      </t-row>
40 70
      <!--header-->
41 71
    </div>
42 72
    <div style="min-height: 280px; height: auto !important">
43
      <draggable-grid v-model="areaMonitorList" :show-page="true" key-word="areaMonitorId" @update="datadragEnd">
44
        <!-- <template v-slot:prepend="{scope}">
45
          <create-card key="create-card" :style="{ width: scope.width + 'px', height: scope.height + 'px' }"/>
46
        </template> -->
47
        <template v-slot="{scope}">
73
      <draggable-grid
74
        v-model="areaMonitorList"
75
        :show-page="true"
76
        :grid="currenScene.monitorViewLayout!=null?currenScene.monitorViewLayout.split('X'):[4,1]"
77
        key-word="monitorSceneTerminalRelId"
78
        @update="datadragEnd"
79
      >
80
        <template v-slot="{ scope }">
48 81
          <view-card
49 82
            :data="scope.data"
50 83
            :width="scope.width + 'px'"
51 84
            :height="scope.height + 'px'"
85
            :monitor-scene-type-name="currenScene.monitorSceneTypeName"
86
            @nameChange="handleCameraSubmit"
52 87
            @edit="handleEdit"
53 88
            @deleted="handleDeleted"
54 89
          />
55 90
        </template>
56 91
      </draggable-grid>
57
      <!-- <draggable v-model="areaMonitorList" @update="datadragEnd"> -->
58
      <!-- <transition-group>
59
          <div v-for="(viewArray,index) in viewDataList" :key="index">
60
            <div style="text-align: right;">
61
              <span style="width:300px">第{{ index+1 }}/{{ viewDataList.length }}页</span>
62
            </div>
63
            <draggable v-model="viewDataList[index]" v-bind="dragOptions" @update="datadragEnd">
64
              <camera-card
65
                v-for="item in viewArray"
66
                :key="item.areaMonitorId"
67
                :data="item"
68
                :item-width="itemWidth"
69
                @edit="handleEdit"
70
                @deleted="handleDeleted"
71
              />
72
            </draggable>
73
          </div>
74
        </transition-group> -->
75
      <!-- </draggable> -->
76
      <shift-scene-dialog :data="dialogSceneData" @submit="handleCameraSubmit" />
77
      <shift-camera-dialog :data="dialogData" @submit="handleCameraSubmit" />
92
      <shift-scene-dialog
93
        :data="dialogSceneData"
94
        @submit="handlesceneSubmit"
95
        @deleted="handlesceneDelete"
96
      />
97
      <shift-camera-dialog :data="dialogData" :monitor-scene-type-name="currenScene.monitorSceneTypeName"
98
                           :monitor-scene-type-id="currenScene.monitorSceneType"
99
                           @submit="handleCameraSubmit"/>
78 100
    </div>
79 101
  </div>
80 102
</template>
@ -87,6 +109,7 @@ import ShiftCameraDialog from '../HomePageSettings/ShiftCameraDialog'
87 109
import DraggableGrid from '../components/DraggableGrid'
88 110
import ViewCard from '../components/ViewCard'
89 111
import CreateCard from '../components/CreateCard'
112
import sysapi from '@/api/system'
90 113
91 114
export default {
92 115
  components: {
@ -106,76 +129,40 @@ export default {
106 129
  },
107 130
  data() {
108 131
    return {
132
      // 选中的组织机构ID
109 133
      currentWindPlaceValue: '2',
110
      currentitem: {},
134
      currenScene: {},
111 135
      btnIsClicked: true,
136
      //
112 137
      dialogSceneData: {},
113 138
      dialogData: {},
114
      currentType: 3,
139
      currentType: 4,
115 140
      itemWidth: null,
116
      sceneList: [{
117
        sceneName: '大门',
118
        id: '1',
119
        parentId: '1',
120
        displayType: '4'
121
      },
122
      {
123
        sceneName: '值班室',
124
        id: '2',
125
        parentId: '1',
126
        displayType: '3'
127
      }
141
      departmentList: [],
142
      monitorSceneList: [
143
        {
144
          sceneName: '大门',
145
          id: '1',
146
          parentId: '1',
147
          displayType: '4'
148
        },
149
        {
150
          sceneName: '值班室',
151
          id: '2',
152
          parentId: '1',
153
          displayType: '3'
154
        }
128 155
      ],
129
      areaMonitorList: [{
130
        title: '摄像头001',
131
        cameraId: '001',
132
        areaMonitorId: '001',
133
        sceneId: '1',
134
        sortOrder: 0,
135
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
136
      },
137
      {
138
        title: '摄像头002',
139
        cameraId: '002',
140
        areaMonitorId: '002',
141
        sortOrder: 1,
142
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
143
      },
144
      {
145
        title: '摄像头003',
146
        cameraId: '003',
147
        areaMonitorId: '003',
148
        sortOrder: 2,
149
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
150
      },
151
      {
152
        title: '摄像头004',
153
        cameraId: '004',
154
        areaMonitorId: '004',
155
        sortOrder: 3,
156
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
157
      },
158
      {
159
        title: '摄像头005',
160
        cameraId: '005',
161
        areaMonitorId: '005',
162
        sortOrder: 4,
163
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
164
      },
165
      {
166
        title: '摄像头006',
167
        cameraId: '006',
168
        areaMonitorId: '006',
169
        sortOrder: 5,
170
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
171
      },
172
      {
173
        title: '摄像头007',
174
        cameraId: '007',
175
        areaMonitorId: '007',
176
        sortOrder: 6,
177
        imgsrc: 'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
178
      }
156
      areaMonitorList: [
157
        {
158
          title: '摄像头001',
159
          cameraId: '001',
160
          areaMonitorId: '001',
161
          sceneId: '1',
162
          sortOrder: 0,
163
          imgsrc:
164
            'https://pics4.baidu.com/feed/b17eca8065380cd7343d6b5ebb93033358828145.jpeg?token=25a11140fcaf2cdf44307a26985a6e26'
165
        }
179 166
      ]
180 167
    }
181 168
  },
@ -189,8 +176,11 @@ export default {
189 176
    viewDataList: function () {
190 177
      let tempDataList = []
191 178
      for (
192
        let i = 0; i < Math.ceil(this.areaMonitorList.length / this.currentType); i++
193
      ) { // this.currentType需要*this.currentType,测试减少一个组的数据
179
        let i = 0;
180
        i < Math.ceil(this.areaMonitorList.length / this.currentType);
181
        i++
182
      ) {
183
        // this.currentType需要*this.currentType,测试减少一个组的数据
194 184
        tempDataList[i] = this.areaMonitorList.slice(
195 185
          i * this.currentType,
196 186
          (i + 1) * this.currentType
@ -202,52 +192,205 @@ export default {
202 192
  mounted() {
203 193
    let dom = this.$refs.box
204 194
    this.itemWidth = dom.clientWidth / this.currentType - 25
195
    this.getDepartments()
205 196
  },
206 197
  methods: {
207
    handleSceneEdit(item) {
208
      alert(item)
209
      event.stopPropagation()
198
    //  获取组织
199
    getDepartments() {
200
      sysapi.getDepartments().then((resp) => {
201
        this.departmentList = resp.data.data || []
202
        if (this.departmentList.length > 0) {
203
          this.currentWindPlaceValue = this.departmentList[0].code
204
          this.getMonitorScene(this.currentWindPlaceValue)
205
        }
206
      })
207
    },
208
    // 获取监控场景
209
    getMonitorScene(orgId) {
210
      sysapi.getMonitorScene(orgId).then((resp) => {
211
        this.monitorSceneList = resp.data.data || []
212
        if (this.monitorSceneList.length > 0) {
213
          this.currenScene = this.monitorSceneList[0]
214
          this.geTerminalRel(this.currenScene)
215
        }
216
      })
217
    },
218
    // 场景ID查询该场景下所有监控终端列表
219
    geTerminalRel(monitorScene) {
220
      sysapi.getTerminalRel(monitorScene.monitorSceneId).then((resp) => {
221
        this.areaMonitorList = resp.data.data || []
222
      })
223
    },
224
    WindPlaceChenged(cloneValue) {
225
      this.getMonitorScene(cloneValue)
226
    },
227
    handleSceneOnClick(item) {
228
      if (this.currenScene !== item) {
229
        this.currenScene = item
230
        this.geTerminalRel(this.currenScene)
231
      }
210 232
    },
211
    btnOnClick(item) {
212
      this.dialogSceneData = item
233
    // 场景
234
    handleSceneEdit(item) {
235
      this.dialogSceneData = this.currenScene
236
      // event.stopPropagation()
213 237
    },
214 238
    btnAddClick() {
215 239
      this.dialogSceneData = {
216
        sceneName: null,
217
        id: null,
218
        parentId: this.currentWindPlaceValue,
219
        displayType: null
240
        monitorSceneId: null, // 场景ID(新增时为空,修改时必填)
241
        monitorSceneName: null, // 场景名称(必填)
242
        organizationId: this.currentWindPlaceValue, // 组织标识(必填)
243
        monitorViewLayout: '1X1', // 布局CODE(必填)
244
        monitorSceneCode: '' // 场景CODE(暂时为空)
220 245
      }
221 246
    },
247
    handlesceneDelete(item) {
248
      sysapi.deleteMonitorScene(item)
249
        .then((resp) => {
250
          this.$Message.danger('删除成功')
251
        }).catch((error) => {
252
          console.log(error)
253
          this.$Message.danger('删除失败')
254
        }).finally(() => {
255
          this.getMonitorScene(this.currentWindPlaceValue)
256
        })
257
    },
258
    handlesceneSubmit(data) {
259
      if (data.monitorSceneId != null) {
260
        const target = this.monitorSceneList.find(
261
          (item) =>
262
            item.monitorSceneId ===
263
          data.monitorSceneId
264
        )
265
        Object.assign(target, data)
266
        sysapi
267
          .modifyMonitorScene(target)
268
          .then((resp) => {
269
            if (resp.data.success === false) {
270
              this.$Message.danger(resp.data.fail.message)
271
            } else {
272
              this.$Message.success('修改成功')
273
            }
274
          }).catch((error) => {
275
            console.log(error)
276
            this.$Message.danger('修改失败')
277
          }).finally(() => {
278
            this.getMonitorScene(this.currentWindPlaceValue)
279
          })
280
      } else {
281
        sysapi.createMonitorScene(data)
282
          .then((resp) => {
283
            if (resp.data.success === false) {
284
              this.$Message.danger(resp.data.fail.message)
285
            } else {
286
              this.$Message.success('增添成功')
287
            }
288
          })
289
          .catch((error) => {
290
            console.log(error)
291
            this.$Message.danger('增添失败')
292
          }).finally(() => {
293
            this.getMonitorScene(this.currentWindPlaceValue)
294
          })
295
      }
296
    },
297
    // 监控
222 298
    handleEdit(item) {
223 299
      this.dialogData = Object.assign({}, item)
224 300
      console.log(item.title)
225 301
    },
226 302
    handleCreate() {
227 303
      this.dialogData = {
228
        title: null,
229
        cameraId: null,
230
        areaMonitorId: null,
231
        sortOrder: 5,
232
        imgsrc: null
304
        customProperties: {},
305
        validDate: null,
306
        expireDate: null,
307
        dataStatus: '1',
308
        createDate: '2020-12-01 23:48:51',
309
        createOpId: null,
310
        createOrgId: null,
311
        doneCode: null,
312
        doneDate: '2020-12-01 23:48:51',
313
        opId: null,
314
        orgId: null,
315
        mgmtDistrict: null,
316
        mgmtCounty: null,
317
        regionId: null,
318
        tenantCode: null,
319
        monitorSceneTerminalRelId: null, // 场景与监控终端关联ID
320
        monitorSceneId: this.currenScene.monitorSceneId, // 场景ID
321
        resourceToolId: null, // 监控终端ID
322
        resourceToolName: null, // 监控终端名称
323
        pictureUrl: null, // 监控终端图片URL
324
        videoUrl: null, // 监控终端视频URL
325
        place: null, // 监控终端位置
326
        resourceToolIndex: null, // 监控终端在场景中的序号
327
        effectType: 'OUT'
233 328
      }
234 329
    },
235
    handleDeleted(index) {
236
      this.areaMonitorList.splice(index, 1)
330
    handleDeleted(data) {
331
      sysapi.deleteTerminalRel(data)
332
        .then((resp) => {
333
        }).catch((error) => {
334
          console.log(error)
335
          this.$Message.danger('删除失败')
336
        }).finally(() => {
337
          this.geTerminalRel(this.currenScene)
338
        })
237 339
    },
238 340
    datadragEnd(evt) {
239
      console.log(evt)
240
      console.log('拖动前的索引 :' + this.areaMonitorList[evt.oldIndex].title)
241
      console.log('拖动后的索引 :' + this.areaMonitorList[evt.newIndex].title)
341
      if (evt.oldIndex !== evt.newIndex) {
342
        let params = {
343
          monitorSceneTerminalRelId: this.areaMonitorList[evt.oldIndex].monitorSceneTerminalRelId, // 场景与终端关联ID
344
          monitorSceneId: this.currenScene.monitorSceneId, // 场景ID
345
          resourceToolId: this.areaMonitorList[evt.oldIndex].resourceToolId, // 终端ID
346
          resourceToolIndex: this.areaMonitorList[evt.newIndex].resourceToolIndex // 移动位置序号
347
        }
348
        sysapi.moveTerminalRelIndex(params).then((resp) => {})
349
          .catch((error) => {
350
            console.log(error)
351
            this.$Message.danger('修改位置失败')
352
          }).finally(() => {
353
            this.geTerminalRel(this.currenScene)
354
          })
355
      }
242 356
    },
243 357
    handleCameraSubmit(data) {
244
      if (this.dialogData.areaMonitorId != null) {
358
      if (data.monitorSceneTerminalRelId != null) {
245 359
        const target = this.areaMonitorList.find(
246
          (item) => item.areaMonitorId === this.dialogData.areaMonitorId
360
          (item) =>
361
            item.monitorSceneTerminalRelId ===
362
          data.monitorSceneTerminalRelId
247 363
        )
248 364
        Object.assign(target, data)
365
        sysapi
366
          .modifyTerminalRel(target)
367
          .then((resp) => {
368
            if (resp.data.success === false) {
369
              this.$Message.danger(resp.data.fail.message)
370
            } else {
371
              this.$Message.success('修改成功')
372
            }
373
          }).catch((error) => {
374
            console.log(error)
375
            this.$Message.danger('修改失败')
376
          }).finally(() => {
377
            this.geTerminalRel(this.currenScene)
378
          })
249 379
      } else {
250
        this.areaMonitorList.unshift(data)
380
        sysapi.createTerminalRel(data)
381
          .then((resp) => {
382
            if (resp.data.success === false) {
383
              this.$Message.danger(resp.data.fail.message)
384
            } else {
385
              this.$Message.success('增添成功')
386
            }
387
          })
388
          .catch((error) => {
389
            console.log(error)
390
            this.$Message.danger('增添失败')
391
          }).finally(() => {
392
            this.geTerminalRel(this.currenScene)
393
          })
251 394
      }
252 395
    }
253 396
  }
@ -255,15 +398,23 @@ export default {
255 398
</script>
256 399
257 400
<style lang="scss">
401
.div_edit {
402
  float: right;
403
  width: 14px;
404
  height: 14px;
405
  position: absolute;
406
  top: 0.4833px;
407
  right: 1.8px;
408
  z-index: 100;
258 409
  .ico {
259 410
    width: 14px;
260 411
    height: 14px;
261 412
    line-height: 14px !important;
262 413
    margin: 2px;
263 414
  }
264
265
  .table-pager {
266
    justify-content: flex-end;
267
    float: right;
268
  }
415
}
416
.table-pager {
417
  justify-content: flex-end;
418
  float: right;
419
}
269 420
</style>

+ 10 - 4
security-protection-platform/src/modules/system/monitor/components/ViewCard/UpdateName.vue

@ -11,7 +11,7 @@
11 11
    </div>
12 12
    <div v-else @mouseleave="mouseLeave">
13 13
      <t-input
14
        v-model="name"
14
        v-model="cname"
15 15
        size="sm"
16 16
        icon="check-outline"
17 17
        icon-placement="right"
@ -30,11 +30,14 @@ export default {
30 30
  },
31 31
  data() {
32 32
    return {
33
      text_tatus: 0
33
      text_tatus: 0,
34
      cname: null
34 35
    }
35 36
  },
36 37
  watch: {},
37
  mounted() {},
38
  mounted() {
39
    this.cname = this.name
40
  },
38 41
  methods: {
39 42
    // 移入
40 43
    mouseOver() {
@ -42,6 +45,9 @@ export default {
42 45
    },
43 46
    // 移出
44 47
    mouseLeave() {
48
      if (this.text_tatus === 2) {
49
        this.$emit('nameSubmit', this.cname)
50
      }
45 51
      this.text_tatus = 0
46 52
    },
47 53
    // 修改
@ -51,7 +57,7 @@ export default {
51 57
    // 提交
52 58
    iconSubmit() {
53 59
      this.text_tatus = 1
54
      this.$emit('nameSubmit', this.name)
60
      this.$emit('nameSubmit', this.cname)
55 61
    }
56 62
  }
57 63
}

+ 21 - 26
security-protection-platform/src/modules/system/monitor/components/ViewCard/index.vue

@ -1,14 +1,14 @@
1 1
<template>
2 2
  <div :class="{ active: showConfirm, lock: loadingDelete }" :style="{ width, height }" class="masonry__item div-block">
3 3
    <div class="card card-has-shadowed card-main">
4
      <div :style="`backgroundImage:url(${data.imgsrc})`" class="card-bg" />
4
      <div :style="`backgroundImage:url(${data.pictureUrl})`" class="card-bg" />
5 5
      <div class="opt">
6
        <t-button shape="round" icon="arrow-expand-all-outline" style="margin: 0px 0px 0px 0px">移动</t-button>
6
        <div class="move">拖拽移动</div>
7 7
        <t-button shape="round" icon="swap-outline" style="margin: 0px 2px 0px 2px" @click="handleEdit">替换</t-button>
8 8
        <t-button shape="round" icon="delete" @click="handleDelete">删除</t-button>
9 9
        <div v-show="showConfirm" class="popover">
10 10
          <t-icon color="warning" icon="alert-circle" style="vertical-align: middle" />
11
          你确定删除该监控吗?
11
          你确定删除该{{ monitorSceneTypeName }}吗?
12 12
          <div class="btn-block">
13 13
            <t-button :loading="loadingDelete" size="sm" color="primary" @click="handleConfirmDelete">确定</t-button>
14 14
            <t-button size="sm" color="secondary" style="margin-right: 8px" @click="handleCancelDelete">取消</t-button>
@ -17,7 +17,7 @@
17 17
      </div>
18 18
    </div>
19 19
    <div class="card card-has-shadowed card-title">
20
      <update-name :name="data.title" @nameSubmit="nameChange" />
20
      <update-name :name="name" @nameSubmit="handleChangeName" />
21 21
    </div>
22 22
  </div>
23 23
</template>
@ -48,13 +48,21 @@ export default {
48 48
      loadingDelete: false
49 49
    }
50 50
  },
51
  computed: {
52
    name: function () {
53
      return this.data.resourceToolName
54
    }
55
  },
51 56
  mounted() {
52 57
53 58
  },
54 59
  methods: {
55
    nameChange: function (name) {
60
    handleChangeName: function (name) {
56 61
      // 修改名称
57
      alert(name)
62
      if (this.data.resourceToolName !== name) {
63
        this.data.resourceToolName = name
64
        this.$emit('nameChange', this.data)
65
      }
58 66
    },
59 67
    handleDelete() {
60 68
      this.showConfirm = true
@ -64,25 +72,8 @@ export default {
64 72
      this.showConfirm = false
65 73
    },
66 74
    handleConfirmDelete() {
67
      // this.loadingDelete = true;
68 75
      // 把事件抛出去,保持控件的干净
69 76
      this.$emit('deleted', this.data)
70
      //   sysapi
71
      //     .deleteSchedule(this.data.scheduleId)
72
      //     .then(
73
      //       (resp) => {
74
      //         console.log(resp);
75
      //         this.$emit("deleted", this.data);
76
      //       },
77
      //       (err) => {
78
      //         console.log(err);
79
      //         this.$Message.danger("删除失败,请稍后再试!", 3);
80
      //       }
81
      //     )
82
      //     .finally(() => {
83
      //       this.loadingDelete = false;
84
      //       this.showConfirm = false;
85
      //     });
86 77
    },
87 78
    handleEdit() {
88 79
      this.$emit('edit', this.data)
@ -123,7 +114,12 @@ export default {
123 114
      display: flex;
124 115
      justify-content: center;
125 116
      align-items: center;
126
117
      .move{
118
        color: rgb(255, 255, 255);
119
        position: absolute;
120
        top: 12px;
121
        text-align: center;
122
      }
127 123
      &::before {
128 124
        content: "";
129 125
        display: block;
@ -132,11 +128,10 @@ export default {
132 128
        top: 0;
133 129
        width: 100%;
134 130
        height: 100%;
135
        background-color: black;
131
        background-color: #00000038;
136 132
        border-radius: 4px;
137 133
        opacity: 0.8;
138 134
      }
139
140 135
      &::after {
141 136
        content: "";
142 137
        display: none;

+ 173 - 0
security-protection-platform/src/modules/videoSurveillance/components/ReplayDialog/index.vue

@ -0,0 +1,173 @@
1
<template>
2
  <t-modal :visibled.sync="visible" :header-visibled="false" :footer-visibled="false" :no-padding="true" width="100%">
3
    <div class="replayer">
4
      <div class="replayer-list">
5
        <t-tabs v-model="currentTab" mode="scrollY" orientation="vertical" width="150px" @change="handleTabChange">
6
          <t-tab-panel v-for="item in list" :key="item.fileId" :label="item.fileName" :panel-id="item.fileId" />
7
        </t-tabs>
8
      </div>
9
10
      <div class="replayer-video">
11
        <t-loading v-model="loadVideo">
12
          <span class="text-md text-info">获取视频资源...</span>
13
        </t-loading>
14
        <video-player
15
          :sources="videoList"
16
          :autoadvance="0"
17
          :style="{opacity: loadVideo ? 0: 1}"
18
          @player-inited="handlePlayerInited"
19
          @playlistitem="handlePlayerCurrentChange"
20
        />
21
      </div>
22
    </div>
23
  </t-modal>
24
</template>
25
26
<script>
27
import VideoPlayer from '@/components/VideoPlayer'
28
29
export default {
30
  components: { VideoPlayer },
31
  props: {
32
    list: {
33
      type: Array,
34
      default: () => []
35
    },
36
    visibled: {
37
      type: Boolean,
38
      default: false
39
    }
40
  },
41
  data() {
42
    return {
43
      currentTab: null,
44
      loadVideo: false,
45
      videoList: [],
46
      $player: null
47
    }
48
  },
49
  computed: {
50
    visible: {
51
      get() { return this.visibled },
52
      set(val) {
53
        if (!val) this.$player.pause()
54
        this.$emit('update:visibled', val)
55
      }
56
    }
57
  },
58
  watch: {
59
    list: {
60
      handler(val) {
61
        console.warn(`list Change`)
62
        this.resetVideoList()
63
        if (val.length > 0) {
64
          this.currentTab = val[0].fileId
65
          // 手动触发第一个tab点击事件
66
          this.handleTabChange(null, 0)
67
        }
68
      },
69
      immediate: true
70
    }
71
  },
72
  methods: {
73
    handlePlayerInited(player) {
74
      this.$player = player
75
      window.player = this
76
    },
77
    async handleTabChange(name, index) {
78
      this.$player.pause()
79
      await this.preloadOriVideoUrl(index)
80
      this.play(index)
81
    },
82
    handlePlayerCurrentChange(e, item) {
83
      const { index, fileId } = item
84
      this.currentTab = fileId
85
      this.preloadOriVideoUrl(index)
86
    },
87
    resetVideoList() {
88
      const videoList = this.list.map((item, index) => {
89
        const { fileId, fileType } = item
90
        return {
91
          index,
92
          fileId,
93
          fileType,
94
          loaded: false
95
        }
96
      })
97
98
      this.videoList = videoList
99
    },
100
    play(index) {
101
      console.log(`播放:index=${index}`)
102
      // 调用额外的currentItem方法以避免currentItem在首次不生效
103
      // https://github.com/brightcove/videojs-playlist/blob/master/docs/api.md
104
      this.$player.playlist.currentItem()
105
      this.$player.playlist.currentItem(index)
106
      this.$player.play()
107
    },
108
    /**
109
     *  从index开始预载videoList的视频地址
110
     *  此方法将在获取index对应的地址后就立即返回
111
     */
112
    preloadOriVideoUrl(index = 0, maxLength = 5) {
113
      return new Promise((resolve, reject) => {
114
        for (let i = index; i in this.videoList && i - index < maxLength; i++) {
115
          console.log(`预载地址:index=${i}`)
116
          const item = this.videoList[i]
117
          const task = item.loaded
118
            ? Promise.resolve()
119
            : this.getOriVideoUrl(item.fileId).then(resp => {
120
              console.log(`预载完成,更新播放源:index=${i}`)
121
              item.loaded = true
122
              item.sources = [{
123
                src: resp.url,
124
                type: item.fileType
125
              }]
126
            })
127
          if (i === index) {
128
            this.loadVideo = !item.loaded
129
            task.then(() => {
130
              resolve()
131
            }).finally(() => {
132
              this.loadVideo = false
133
            })
134
          }
135
        }
136
      })
137
    },
138
    /*
139
     * 获取真实视频地址
140
     */
141
    getOriVideoUrl(fileId) {
142
      console.log(`请求地址:${fileId}`)
143
      // fake
144
      return new Promise((resolve, reject) => {
145
        setTimeout(() => {
146
          const x = Math.random()
147
          const url = x > 0.5
148
            ? 'http://10.19.90.34:19000/tool-image/tool-image_7d359725fac4464fb248284caf321993.mp4'
149
            : 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4'
150
          resolve({
151
            url
152
          })
153
        }, 1000)
154
      })
155
    }
156
  }
157
}
158
</script>
159
160
<style lang="scss">
161
.replayer {
162
  display: flex;
163
  &-list {
164
    margin-right: 20px;
165
    // width: 200px;
166
  }
167
168
  &-video {
169
    position: relative;
170
    flex: auto;
171
  }
172
}
173
</style>

+ 130 - 80
security-protection-platform/src/modules/videoSurveillance/index.vue

@ -12,28 +12,38 @@
12 12
    </div>
13 13
    <div class="page-bottom">
14 14
      <div v-for="(item,index) in videoList" :key="index">
15
        <t-card :class="index%3===0?'card-video-first':'card-video'">
15
        <t-card class="card-video">
16 16
          <img :src="item.url" class="card-image">
17 17
          <div slot="foot" class="bottom">
18 18
            <span v-tooltip="item.videoDetail">{{ item.videoDetail.content | handleText }}</span>
19 19
            <div style="margin-left:auto">
20
              <t-button v-tooltip="item.options1" class="bottom-btn" @click="goDistinguishRecord(item.videoId)"><t-icon size="16" icon="image-outline"></t-icon></t-button>
21
              <t-button v-tooltip="item.options2" class="bottom-btn"><t-icon size="16" icon="piechart-outline"></t-icon></t-button>
22
              <t-button v-tooltip="item.options3" class="bottom-btn"><t-icon size="16" icon="arrow-expand-all-outline"></t-icon></t-button>
20
              <t-button v-tooltip="item.options1" class="bottom-btn" @click="goDistinguishRecord(item.videoId)">
21
                <t-icon size="16" icon="image-outline"></t-icon>
22
              </t-button>
23
              <t-button v-tooltip="item.options2" class="bottom-btn" @click="handleReview(item.videoId)">
24
                <t-icon size="16" icon="piechart-outline"></t-icon>
25
              </t-button>
26
              <t-button v-tooltip="item.options3" class="bottom-btn">
27
                <t-icon size="16" icon="arrow-expand-all-outline"></t-icon>
28
              </t-button>
23 29
            </div>
24 30
          </div>
25 31
        </t-card>
26 32
      </div>
27 33
    </div>
28 34
    <t-pager :page-size="videoPageSize" :current="videoCurrent" :total="videoTotal" :sizer-range="[ 5, 10, 20, 30 ]" class="pager" show-elevator @on-change="onChangeGate"></t-pager>
35
    <replay-dialog :list="replayList" :visibled.sync="showReplayDialog" />
29 36
  </div>
30 37
</template>
31 38
<script>
32 39
import sysapi from '@/api/videoSurveillance'
33 40
import commonapi from '@/api/common'
41
import ReplayDialog from './components/ReplayDialog'
42
34 43
export default {
44
  components: { ReplayDialog },
35 45
  filters: {
36
    handleText(value) {
46
    handleText (value) {
37 47
      if (!value) return ''
38 48
      if (value.length > 13) {
39 49
        return value.slice(0, 13) + '...'
@ -41,7 +51,7 @@ export default {
41 51
      return value
42 52
    }
43 53
  },
44
  data() {
54
  data () {
45 55
    return {
46 56
      videoCurrent: 1, // 大门分页数据
47 57
      videoPageSize: 10, // 大门分页数据
@ -56,22 +66,66 @@ export default {
56 66
      gateFieldData: 101101,
57 67
      videoList: [],
58 68
      totalList: [],
59
      roomList: []
69
      roomList: [],
70
71
      showReplayDialog: false,
72
      replayList: []
60 73
    }
61 74
  },
62
  mounted() {
75
  mounted () {
63 76
    this.getWindFiledList() // 获取风场列表
64 77
    this.getVideoSurveillanceData() // 获取视频监控界面数据
65 78
  },
66 79
  methods: {
67
    async tabClick(id) {
80
    async handleReview (id) {
81
      // const res = await sysapi.getVideoPlayBack(id)
82
      // console.log(res)
83
      this.replayList = [{
84
        fileName: '12月14 16:55',
85
        fileId: 'ai-video_5A02296PAKA885B-video20201214165526.mp4',
86
        fileType: 'video/mp4'
87
      }, {
88
        fileName: '12月14 16:56',
89
        fileId: 'ai-video_5A02296PAKA885B-video20201214165527.mp4',
90
        fileType: 'video/mp4'
91
      }, {
92
        fileName: '12月14 16:57',
93
        fileId: 'ai-video_5A02296PAKA885B-video20201214165528.mp4',
94
        fileType: 'video/mp4'
95
      }, {
96
        fileName: '12月14 16:58',
97
        fileId: 'ai-video_5A02296PAKA885B-video20201214165529.mp4',
98
        fileType: 'video/mp4'
99
      }, {
100
        fileName: '12月14 16:59',
101
        fileId: 'ai-video_5A02296PAKA885B-video20201214165530.mp4',
102
        fileType: 'video/mp4'
103
      }, {
104
        fileName: '12月14 17:00',
105
        fileId: 'ai-video_5A02296PAKA885B-video20201214165531.mp4',
106
        fileType: 'video/mp4'
107
      }]
108
      this.replayList = [{
109
        sources: [{
110
          src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
111
          type: 'video/mp4'
112
        }]
113
      }, {
114
        sources: [{
115
          src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
116
          type: 'video/mp4'
117
        }]
118
      }]
119
      this.showReplayDialog = true
120
    },
121
    async tabClick (id) {
68 122
      this.paramsObj.page = 0
69 123
      this.videoList = []
70 124
      this.tabId = id
71 125
      this.videoCurrent = 1
72 126
      this.getVideoSurveillanceData()
73 127
    },
74
    getWindFiledList() {
128
    getWindFiledList () {
75 129
      commonapi.getDepartments().then(resp => {
76 130
        this.organizationList = []
77 131
        console.log(resp)
@ -87,13 +141,13 @@ export default {
87 141
      })
88 142
    },
89 143
    // 获得风场大门数据
90
    getVideoSurveillanceData(isWind) {
144
    getVideoSurveillanceData (isWind) {
91 145
      if (isWind) {
92 146
        this.videoList = []
93 147
      }
94 148
      if (this.videoList.length <= 10) {
95 149
        this.paramsObj.page = this.videoCurrent
96
        sysapi.getVideoSurveillanceData({params: this.paramsObj}).then(res => {
150
        sysapi.getVideoSurveillanceData({ params: this.paramsObj }).then(res => {
97 151
          this.departments = res.data.departments
98 152
          this.videoTotal = this.departments[this.tabId - 1].total
99 153
          res.data.data.forEach((element, index) => {
@ -114,11 +168,11 @@ export default {
114 168
      }
115 169
    },
116 170
    // 进入识别记录界面
117
    goDistinguishRecord(id) {
118
      this.$router.push({path: '/videoSurveillance/distinguishRecord', query: {videoId: id}})
171
    goDistinguishRecord (id) {
172
      this.$router.push({ path: '/videoSurveillance/distinguishRecord', query: { videoId: id } })
119 173
    },
120 174
    // 风场大门分页
121
    onChangeGate(val) {
175
    onChangeGate (val) {
122 176
      this.videoList = []
123 177
      this.videoCurrent = val
124 178
      this.getVideoSurveillanceData()
@ -127,81 +181,77 @@ export default {
127 181
}
128 182
</script>
129 183
<style lang="scss" scoped>
130
.page-main{
131
    padding:30px 24px 24px 24px;
132
    .top-btn{
133
        float: right;
134
    }
135
    .page-bottom{
136
        display: flex;
184
.page-main {
185
  padding: 30px 24px 24px 24px;
186
  .top-btn {
187
    float: right;
188
  }
189
  .page-bottom {
190
    display: flex;
191
    width: 100%;
192
    flex-wrap: wrap;
193
    margin-left: -24px;
194
    .card-video-first,
195
    .card-video {
196
      width: 354px;
197
      height: 240px;
198
      margin-top: 20px;
199
      .card-image {
137 200
        width: 100%;
138
        flex-wrap: wrap;
139
        .card-video-first, .card-video{
140
          width:397px;
141
          height:245px;
142
          margin-top: 20px;
143
            .card-image{
144
                width: 100%;
145
                height: 100%;
146
            }
147
            .bottom{
148
                padding: 0 12px;
149
                display: flex;
150
                align-items: center;
151
                background-color: rgba(0, 0, 0, 0.5);
152
                height: 40px;
153
                color: #fff;
154
                font-size: 14px;
155
                .bottom-btn{
156
                    color: #fff;
157
                    border: none;
158
                    padding:0 !important;
159
                    &:hover{
160
                        color: #0089d4;
161
                    }
162
                }
163
            }
164
        }
165
        .card-video-first{
166
          .card-footer{
167
             padding: 0px !important;
168
             background: none;
169
             width: 100%;
170
             position: absolute;
171
             border-top: none;
172
             bottom: 0px;
173
             }
174
            .card-block{
175
              padding:0 !important;
176
            }
177
        }
178
        .card-video{
179
          .card-footer{
180
             padding: 0px 0 0 24px !important;
181
             background: none;
182
             width: 100%;
183
             position: absolute;
184
             border-top: none;
185
             bottom: 0px;
186
             }
187
            .card-block, .card-video-block{
188
              margin-left: 24px;
189
              padding:0 !important;
190
            }
201
        height: 100%;
202
      }
203
      .bottom {
204
        padding: 0 12px;
205
        display: flex;
206
        align-items: center;
207
        background-color: rgba(0, 0, 0, 0.5);
208
        height: 40px;
209
        color: #fff;
210
        font-size: 14px;
211
        .bottom-btn {
212
          color: #fff;
213
          border: none;
214
          padding: 0 !important;
215
          &:hover {
216
            color: #0089d4;
217
          }
191 218
        }
219
      }
220
    }
221
    .card-video {
222
      .card-footer {
223
        padding: 0px 0 0 24px !important;
224
        background: none;
225
        width: 100%;
226
        position: absolute;
227
        border-top: none;
228
        bottom: 0px;
229
      }
230
      .card-block,
231
      .card-video-block {
232
        margin-left: 24px;
233
        padding: 0 !important;
234
      }
192 235
    }
193
    .pager{
236
  }
237
  .pager {
194 238
    margin-right: auto;
195 239
    margin: 21px 0px 24px 0;
196 240
    float: right;
197 241
  }
198
.btn-primary, .radio-group-button .form-radio:checked, .radio-group-button .form-radio[checked]{
242
  .btn-primary,
243
  .radio-group-button .form-radio:checked,
244
  .radio-group-button .form-radio[checked] {
199 245
    color: #0089d4;
200 246
    background-color: #fff;
201 247
    border: 1px solid #0089d4;
202
}
203
.btn-secondary, .radio-group-button .form-radio, .checkbox-group--button .form-checkbox .form-checkbox__inner, .btn-dashed-secondary, .btn-outline-secondary{
248
  }
249
  .btn-secondary,
250
  .radio-group-button .form-radio,
251
  .checkbox-group--button .form-checkbox .form-checkbox__inner,
252
  .btn-dashed-secondary,
253
  .btn-outline-secondary {
204 254
    background: none;
205
}
255
  }
206 256
}
207 257
</style>

+ 1 - 0
security-protection-platform/src/styles/index.scss

@ -25,6 +25,7 @@ html {
25 25
*,
26 26
*:before,
27 27
*:after {
28
  font-family: inherit;
28 29
  box-sizing: inherit;
29 30
}
30 31