Sfoglia il codice sorgente

Merge branch 'dev-security' of http://10.1.235.20:3000/asiainfo/ebc into dev-security

liuchang 4 anni fa
parent
commit
36af9d77e8

+ 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
}

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

@ -0,0 +1,26 @@
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
      debugger
10
      return resp.data
11
    })
12
  },
13
  // 报警(柱状图)
14
  queryAlarmAnalysisChart() {
15
    return $default.get('/sp/homePage/queryAlarmAnalysisChart', {}).then(resp => {
16
      return resp.data
17
    })
18
  },
19
  // 报警(TOP4)
20
  queryAlarmAnalysisTopList() {
21
    return $default.get('/sp/homePage/queryAlarmAnalysisTopList', {}).then(resp => {
22
      return resp.data
23
    })
24
  }
25
}
26
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>

+ 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>

+ 59 - 25
security-protection-platform/src/modules/videoSurveillance/index.vue

@ -12,13 +12,13 @@
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 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>
21
              <t-button v-tooltip="item.options2" class="bottom-btn" @click="handleReview(item.videoId)"><t-icon size="16" icon="piechart-outline"></t-icon></t-button>
22 22
              <t-button v-tooltip="item.options3" class="bottom-btn"><t-icon size="16" icon="arrow-expand-all-outline"></t-icon></t-button>
23 23
            </div>
24 24
          </div>
@ -26,12 +26,16 @@
26 26
      </div>
27 27
    </div>
28 28
    <t-pager :page-size="videoPageSize" :current="videoCurrent" :total="videoTotal" :sizer-range="[ 5, 10, 20, 30 ]" class="pager" show-elevator @on-change="onChangeGate"></t-pager>
29
    <replay-dialog :list="replayList" :visibled.sync="showReplayDialog" />
29 30
  </div>
30 31
</template>
31 32
<script>
32 33
import sysapi from '@/api/videoSurveillance'
33 34
import commonapi from '@/api/common'
35
import ReplayDialog from './components/ReplayDialog'
36
34 37
export default {
38
  components: { ReplayDialog },
35 39
  filters: {
36 40
    handleText(value) {
37 41
      if (!value) return ''
@ -56,7 +60,10 @@ export default {
56 60
      gateFieldData: 101101,
57 61
      videoList: [],
58 62
      totalList: [],
59
      roomList: []
63
      roomList: [],
64
65
      showReplayDialog: false,
66
      replayList: []
60 67
    }
61 68
  },
62 69
  mounted() {
@ -64,6 +71,45 @@ export default {
64 71
    this.getVideoSurveillanceData() // 获取视频监控界面数据
65 72
  },
66 73
  methods: {
74
    handleReview() {
75
      this.replayList = [{
76
        fileName: '12月14 16:55',
77
        fileId: 'ai-video_5A02296PAKA885B-video20201214165526.mp4',
78
        fileType: 'video/mp4'
79
      }, {
80
        fileName: '12月14 16:56',
81
        fileId: 'ai-video_5A02296PAKA885B-video20201214165527.mp4',
82
        fileType: 'video/mp4'
83
      }, {
84
        fileName: '12月14 16:57',
85
        fileId: 'ai-video_5A02296PAKA885B-video20201214165528.mp4',
86
        fileType: 'video/mp4'
87
      }, {
88
        fileName: '12月14 16:58',
89
        fileId: 'ai-video_5A02296PAKA885B-video20201214165529.mp4',
90
        fileType: 'video/mp4'
91
      }, {
92
        fileName: '12月14 16:59',
93
        fileId: 'ai-video_5A02296PAKA885B-video20201214165530.mp4',
94
        fileType: 'video/mp4'
95
      }, {
96
        fileName: '12月14 17:00',
97
        fileId: 'ai-video_5A02296PAKA885B-video20201214165531.mp4',
98
        fileType: 'video/mp4'
99
      }]
100
      // this.replayList = [{
101
      //   sources: [{
102
      //     src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
103
      //     type: 'video/mp4'
104
      //   }]
105
      // }, {
106
      //   sources: [{
107
      //     src: 'http://10.19.90.34:19000/tool-image/tool-image_7fa1f7b30f0640f2a67ac8b4c2e0b574.mp4',
108
      //     type: 'video/mp4'
109
      //   }]
110
      // }]
111
      this.showReplayDialog = true
112
    },
67 113
    async tabClick(id) {
68 114
      this.paramsObj.page = 0
69 115
      this.videoList = []
@ -136,9 +182,10 @@ export default {
136 182
        display: flex;
137 183
        width: 100%;
138 184
        flex-wrap: wrap;
185
        margin-left: -24px;
139 186
        .card-video-first, .card-video{
140
          width:397px;
141
          height:245px;
187
          width:354px;
188
          height:240px;
142 189
          margin-top: 20px;
143 190
            .card-image{
144 191
                width: 100%;
@ -162,28 +209,15 @@ export default {
162 209
                }
163 210
            }
164 211
        }
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 212
        .card-video{
179 213
          .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
             }
214
            padding: 0px 0 0 24px !important;
215
            background: none;
216
            width: 100%;
217
            position: absolute;
218
            border-top: none;
219
            bottom: 0px;
220
            }
187 221
            .card-block, .card-video-block{
188 222
              margin-left: 24px;
189 223
              padding:0 !important;

+ 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