Browse Source

[FE]:修改视频监控页面逻辑以及界面

xiayu3 4 years ago
parent
commit
6ed3c853d8

+ 1 - 0
security-protection-platform/package.json

@ -78,6 +78,7 @@
78 78
    "vuedraggable": "2.19",
79 79
    "video.js": "7.10.2",
80 80
    "videojs-playlist": "4.3.1",
81
    "videojs-flash": "2.2.1",
81 82
    "echarts": "^4.9.0"
82 83
  }
83 84
}

+ 5 - 1
security-protection-platform/src/api/videoSurveillance/index.js

@ -4,12 +4,16 @@ const { $http, $default } = http
4 4
const api = {
5 5
  // 获取风场大门表格数据
6 6
  getVideoSurveillanceData (params) {
7
    return $http.get('/videoSurveillance/getVideoSurveillanceData', params)
7
    return $default.get('/sp/monitorSceneTerminal/queryMonitorSceneTerminalRel', params)
8 8
  },
9 9
  // 获取识别记录数据
10 10
  getDistinguishData (params) {
11 11
    return $http.get('/videoSurveillance/getDistinguishData', params)
12 12
  },
13
  // 获取监控场景列表
14
  getMonitorScene() {
15
    return $default.get('/sp/monitorSceneManagement/queryPageMonitorScene', 0)
16
  },
13 17
  // 视频回放
14 18
  getVideoPlayBack (id) {
15 19
    return $default.get(`/sp/uploadFile/getFileUrl?fileName=${id}`).catch((err) => { return err })

+ 3 - 2
security-protection-platform/src/components/VideoPlayer/index.vue

@ -32,9 +32,10 @@ const defaultPlayerOptions = {
32 32
      },
33 33
      {
34 34
        name: 'volumePanel', // 音量控制
35
        inline: false // 不使用水平方式
35
        inline: true // 不使用水平方式
36 36
      },
37
      {name: 'FullscreenToggle'} // 全屏
37
      {name: 'FullscreenToggle'}, // 全屏
38
      {name: 'FullscreenToggle'}
38 39
    ]
39 40
  }
40 41
}

+ 4 - 4
security-protection-platform/src/modules/system/assignment/index.vue

@ -4,7 +4,7 @@
4 4
      <div class="select-confidtion-box row">
5 5
        <div class="col-3">任务名称:
6 6
          <t-select v-model="taskName" width="200px">
7
            <t-option v-for="item in taskNameList" :key="item.id" :value="item.id">{{ item.name }}</t-option>
7
            <t-option v-for="item in taskNameList" :key="item.id" :value="item.charSpecValueId">{{ item.description }}</t-option>
8 8
          </t-select>
9 9
        </div>
10 10
        <div class="col-3">匹配模型:
@ -14,7 +14,7 @@
14 14
        </div>
15 15
        <div class="col-3">任务状态:
16 16
          <t-select v-model="taskStatus" width="200px">
17
            <t-option v-for="item in taskStatusList" :key="item.id" :value="item.id">{{ item.name }}</t-option>
17
            <t-option v-for="item in taskStatusList" :key="item.id" :value="item.charSpecValueId">{{ item.description }}</t-option>
18 18
          </t-select>
19 19
        </div>
20 20
        <div class="col-2 offset-1 select-button-box" align="end">
@ -110,8 +110,8 @@ export default {
110 110
  },
111 111
  methods: {
112 112
    getTaskName() {
113
      sysapi.getCharSpecList('TASK_STATUS').then(res => {
114
        console.log(res);
113
      sysapi.getCharSpecList('AI_TASK_STATUS').then(res => {
114
        this.taskStatusList = res.data
115 115
      })
116 116
    },
117 117
    getmatchingType() {

+ 166 - 0
security-protection-platform/src/modules/videoSurveillance/components/rtmpVideoPlay/index.vue

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

+ 89 - 45
security-protection-platform/src/modules/videoSurveillance/index.vue

@ -1,17 +1,19 @@
1 1
<template>
2 2
  <div class="page-main">
3 3
    <t-button-group class="top-btn">
4
      <t-button :color="tabId === 1 ? 'primary' : 'secondary'" @click="tabClick(1)">风场大门</t-button>
5
      <t-button :color="tabId === 2 ? 'primary' : 'secondary'" @click="tabClick(2)">集控室</t-button>
4
      <t-button v-for="(item,index) in sceneList" :key="index"
5
                :value="item.monitorSceneId"
6
                :color="item.monitorSceneId === selectedMonitorScene ? 'primary' : 'secondary'"
7
                @click="tabClick(item.monitorSceneId)">{{ item.monitorSceneName }}</t-button>
6 8
    </t-button-group>
7 9
    <div class="page-top">
8 10
      <span>风场:</span>
9
      <t-select v-model="gateFieldData" clearable @change="getVideoSurveillanceData(true)">
10
        <t-option v-for="(item,index) in organizationList" :key="index" :value="item.id">{{ item.org }}</t-option>
11
      <t-select v-model="gateFieldData" clearable @change="getSceneList()">
12
        <t-option v-for="(item,index) in organizationList" :key="index" :value="item.organizationId">{{ item.monitorSceneTypeName }}</t-option>
11 13
      </t-select>
12 14
    </div>
13 15
    <div class="page-bottom">
14
      <div v-for="(item,index) in videoList" :key="index">
16
      <!-- <div v-for="(item,index) in videoList" :key="index">
15 17
        <t-card class="card-video">
16 18
          <img :src="item.url" class="card-image">
17 19
          <div slot="foot" class="bottom">
@ -29,19 +31,58 @@
29 31
            </div>
30 32
          </div>
31 33
        </t-card>
34
      </div> -->
35
      <div style="width:400px;margin:24px 24px 0 0;">
36
        <!-- <video id="videoPlayer" class="video-js vjs-default-skin vjs-big-play-centered"
37
               controls autoplay preload="auto" width="640" height="360"
38
               data-setup="{ &quot;html5&quot; : { &quot;nativeTextTracks&quot; : false } }">
39
          <source src="rtmp://10.19.90.34:2935/live?token=039b6232ce6548210722a4c0de19c62e/1" type="rtmp/flv" />
40
        </video> -->
32 41
      </div>
33 42
    </div>
34 43
    <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" />
44
    <replay-dialog :list="replayList" />
36 45
  </div>
37 46
</template>
38 47
<script>
39 48
import sysapi from '@/api/videoSurveillance'
40 49
import commonapi from '@/api/common'
41
import ReplayDialog from './components/ReplayDialog'
50
import ReplayDialog from './components/rtmpVideoPlay'
51
import VideoPlayer from '@/components/VideoPlayer'
52
import videojs from 'video.js'
53
window.videojs = videojs
54
require('videojs-flash')
55
require('videojs-playlist')
56
require('video.js/dist/lang/zh-CN.js')
57
require('video.js/dist/video-js.min.css')
42 58
59
const defaultPlayerOptions = {
60
  controls: true,
61
  autoplay: false,
62
  muted: false,
63
  language: 'zh-CN',
64
  fluid: true,
65
  // liveui: true,
66
  controlBar: {
67
    children: [
68
      {name: 'playToggle'}, // 播放按钮
69
      {name: 'currentTimeDisplay'}, // 当前已播放时间
70
      {name: 'progressControl'}, // 播放进度条
71
      {name: 'durationDisplay'}, // 总时间
72
      { // 倍数播放
73
        name: 'playbackRateMenuButton',
74
        playbackRates: [0.5, 1, 1.5, 2, 2.5]
75
      },
76
      {
77
        name: 'volumePanel', // 音量控制
78
        inline: false // 不使用水平方式
79
      },
80
      {name: 'FullscreenToggle'} // 全屏
81
    ]
82
  }
83
}
43 84
export default {
44
  components: { ReplayDialog },
85
  components: { ReplayDialog, VideoPlayer },
45 86
  filters: {
46 87
    handleText (value) {
47 88
      if (!value) return ''
@ -52,7 +93,9 @@ export default {
52 93
    }
53 94
  },
54 95
  data () {
96
    const playerOptions = Object.assign({}, defaultPlayerOptions, this.options)
55 97
    return {
98
      playerOptions,
56 99
      videoCurrent: 1, // 大门分页数据
57 100
      videoPageSize: 10, // 大门分页数据
58 101
      videoTotal: 100, // 大门分页总数
@ -61,22 +104,38 @@ export default {
61 104
        page: 0,
62 105
        limit: 10
63 106
      },
64
      departments: '',
65 107
      organizationList: [], // 风场数据
66 108
      gateFieldData: 101101,
67 109
      videoList: [],
68
      totalList: [],
69
      roomList: [],
70
71
      showReplayDialog: false,
110
      sceneList: [], // 场景列表
111
      totalList: [], // 所有风场数据列表
112
      selectedMonitorScene: '',
113
      showReplayDialog: true,
72 114
      replayList: []
73 115
    }
74 116
  },
75 117
  mounted () {
118
    // var myButton = videojs.player.controlBar.addChild('button', {
119
    //   text: 'Press me'
120
    //   // other options
121
    // })
122
    // myButton.addClass('html-classname')
76 123
    this.getWindFiledList() // 获取风场列表
77
    this.getVideoSurveillanceData() // 获取视频监控界面数据
124
    this.handleReview()
78 125
  },
79 126
  methods: {
127
    // 获取场景列表
128
    getSceneList() {
129
      this.sceneList = []
130
      for (let i = 0; i < this.totalList.length; i++) {
131
        if (this.totalList[i].organizationId === this.gateFieldData) {
132
          this.sceneList.push(this.totalList[i])
133
        }
134
      }
135
      const {a, b} = this.totalList[0]
136
      console.log(this.totalList[0]);
137
      console.log(a, b)
138
    },
80 139
    async handleReview (id) {
81 140
      // const res = await sysapi.getVideoPlayBack(id)
82 141
      // console.log(res)
@ -116,54 +175,39 @@ export default {
116 175
          type: 'video/mp4'
117 176
        }]
118 177
      }]
119
      this.showReplayDialog = true
120 178
    },
121 179
    async tabClick (id) {
180
      this.selectedMonitorScene = id
122 181
      this.paramsObj.page = 0
123 182
      this.videoList = []
124 183
      this.tabId = id
125 184
      this.videoCurrent = 1
126
      this.getVideoSurveillanceData()
185
      this.getVideoSurveillanceData(id)
127 186
    },
128 187
    getWindFiledList () {
129
      commonapi.getDepartments().then(resp => {
130
        this.organizationList = []
131
        console.log(resp)
132
        this.organizationList = resp.data.map(item => {
133
          return {
134
            org: item.name,
135
            id: item.id
188
      sysapi.getMonitorScene().then(resp => {
189
        let arr = resp.data.data
190
        this.totalList = arr
191
        for (let i = 0; i < arr.length; i++) {
192
          for (let j = i + 1; j < arr.length; j++) {
193
            if (arr[i].monitorSceneTypeName === arr[j].monitorSceneTypeName) {
194
              ++i
195
            }
136 196
          }
137
        })
197
          this.organizationList.push(arr[i])
198
        }
199
        console.log(this.organizationList)
138 200
      }, err => {
139 201
        this.$Message.danger('获取风场列表失败!')
140 202
        console.log(err)
141 203
      })
142 204
    },
143 205
    // 获得风场大门数据
144
    getVideoSurveillanceData (isWind) {
145
      if (isWind) {
146
        this.videoList = []
147
      }
206
    getVideoSurveillanceData (id) {
148 207
      if (this.videoList.length <= 10) {
149 208
        this.paramsObj.page = this.videoCurrent
150
        sysapi.getVideoSurveillanceData({ params: this.paramsObj }).then(res => {
151
          this.departments = res.data.departments
152
          this.videoTotal = this.departments[this.tabId - 1].total
153
          res.data.data.forEach((element, index) => {
154
            if (element.departmentId === this.tabId) {
155
              this.videoList.push(element)
156
            }
157
          })
158
          this.videoList.forEach(element => {
159
            if (typeof (element.videoDetail) === 'object') {
160
              var txt = element.videoDetail.content
161
            } else { txt = element.videoDetail }
162
            element.videoDetail = {}
163
            element.videoDetail.content = txt
164
            element.videoDetail.placement = 'top'
165
          })
166
          this.getVideoSurveillanceData()
209
        sysapi.getVideoSurveillanceData({ params: {monitorSceneId: id} }).then(res => {
210
          console.log(res)
167 211
        })
168 212
      }
169 213
    },