Lita-Tako 4 months ago
parent
commit
c733838339

+ 8 - 0
src/api/video/index.js

@@ -52,3 +52,11 @@ export function manualCapture(data) {
52 52
     data: formData
53 53
   })
54 54
 }
55
+
56
+export function getPlayback(data) {
57
+  return request({
58
+    url: `${depot_monitor}/previewPlayback/getPlayback`,
59
+    method: 'post',
60
+    data: data
61
+  })
62
+}

+ 2 - 2
src/components/common/data.js

@@ -616,8 +616,8 @@ export const DEVICE_TYPE_2 = [
616 616
 
617 617
 export const CAMERA_TYPE = [
618 618
   { value: '1', label: '球形摄像机'},
619
-  { value: '2', label: '球形摄像机'},
620
-  { value: '3', label: '球形摄像机'},
619
+  { value: '2', label: '枪式摄像机'},
620
+  { value: '3', label: '球形摄像机'},
621 621
 ]
622 622
 
623 623
 export const BUS_TYPE = [

+ 13 - 9
src/components/common/player/live_v2.vue

@@ -34,7 +34,6 @@ export default {
34 34
   mounted() {
35 35
     this.init()
36 36
     this.createPlayer()
37
-    this.getVideo()
38 37
   },
39 38
   methods: {
40 39
     init() {
@@ -258,6 +257,11 @@ export default {
258 257
     doControl(command, action = 0, speed = 50, presetIndex = 10) {
259 258
       if(this.videoMap[this.currentWindowIndex]) {
260 259
         const data = this.videoMap[this.currentWindowIndex]
260
+        const cameraId = data.cameraId
261
+        const c = this.findCameraByCameraId(cameraId)
262
+        if(c.cameraType	!== '1') {
263
+          return this.$message.warning('该操作必须是球形摄像机')
264
+        }
261 265
         const cmd = {
262 266
           action,
263 267
           command,
@@ -403,14 +407,14 @@ export default {
403 407
             <el-button type="primary" class="btn" @click="recordEnd">录像结束</el-button>
404 408
           </el-col>
405 409
         </el-row>
406
-        <el-row class="row" style="margin-top: 10px">
407
-          <el-col :span="12">
408
-            <el-input v-model="viewUrl"/>
409
-          </el-col>
410
-          <el-col :span="12">
411
-            <el-button type="primary" class="btn" @click="testPaly">test</el-button>
412
-          </el-col>
413
-        </el-row>
410
+<!--        <el-row class="row" style="margin-top: 10px">-->
411
+<!--          <el-col :span="12">-->
412
+<!--            <el-input v-model="viewUrl"/>-->
413
+<!--          </el-col>-->
414
+<!--          <el-col :span="12">-->
415
+<!--            <el-button type="primary" class="btn" @click="testPaly">test</el-button>-->
416
+<!--          </el-col>-->
417
+<!--        </el-row>-->
414 418
       </el-tab-pane>
415 419
       </el-tabs>
416 420
     </div>

+ 337 - 50
src/components/common/player/playback_v2.vue

@@ -1,75 +1,362 @@
1
-<template>
2
-  <div class="box">
3
-    <el-row>
4
-      <el-col :span="17">
5
-        <div class="title">
6
-          <span><i></i> 回放通道</span>
7
-        </div>
8
-        <video-player></video-player>
9
-      </el-col>
10
-      <el-col :span="1" style="border: 1px solid transparent;"></el-col>
11
-      <el-col :span="6">
12
-        <playback-control :show-playback-control="showPlaybackControl" :show-camera-control="showCameraControl"></playback-control>
13
-      </el-col>
14
-    </el-row>
15
-
16
-  </div>
17
-</template>
18
-
19 1
 <script>
2
+import liveControl from "@/components/common/player/components/liveControl.vue";
3
+import videoPlayer from "@/components/common/player/components/videoPlayer.vue";
4
+import {mapGetters} from "vuex";
5
+import cameraControl from "@/components/common/player/components/cameraControl.vue";
6
+import CommonSelect from "@/components/common/commonSelect/index.vue";
7
+import {getPreview, getNVRVideo, recordStart, recordStop, controlling, manualCapture, getPlayback} from "@/api/video";
8
+const IS_MOVE_DEVICE = false
9
+const MSE_IS_SUPPORT = !!window.MediaSource // 是否支持mse
20 10
 
21
-import videoPlayer from './components/videoPlayer'
22
-import playbackControl from "./components/playbackControl"
23
-import cameraControl from "./components/cameraControl"
24 11
 export default {
25
-  name: "playback",
26
-  props: {
27
-    showPlaybackControl: {
28
-      type: Boolean,
29
-      required: false,
30
-      default: true,
31
-    },
32
-    showCameraControl: {
33
-      type: Boolean,
34
-      required: false,
35
-      default: false,
12
+  components: {CommonSelect, cameraControl, videoPlayer, liveControl},
13
+  computed: {
14
+    ... mapGetters(['orgName', 'orgId']),
15
+    mode: function() {
16
+      // return this.tabActive === 'mse' ? 0 : 1
17
+      return 0 // 0 普通模式   1 高级模式
36 18
     }
37 19
   },
38
-  components: {
39
-    videoPlayer, playbackControl,
40
-  },
41 20
   data() {
42 21
     return {
43
-      options: [],
44
-      selected: this.value,
22
+      cameraListData: [],
23
+      activeName: 'cameraList',
24
+      isMoveDevice: IS_MOVE_DEVICE,
25
+      player: null,
26
+      splitNum: 1,
27
+      mseSupport: MSE_IS_SUPPORT,
28
+      videoMap: {}, // window index - {ws url, camera index code}
29
+      currentWindowIndex: 0,
30
+      viewUrl: null,
31
+      date: []
45 32
     }
46 33
   },
47
-  created() {
34
+  mounted() {
48 35
     this.init()
49
-  },
50
-  watch: {
51
-    value(newVal) {
52
-      this.selected = newVal;
53
-    }
36
+    this.createPlayer()
54 37
   },
55 38
   methods: {
56 39
     init() {
40
+      window.addEventListener('resize', () => {
41
+        this.player.JS_Resize()
42
+      })
43
+      this.getCameraList()
44
+    },
45
+    createPlayer() {
46
+      this.player = new window.JSPlugin({
47
+        szId: 'player',
48
+        szBasePath: "/static/js/h5player/",
49
+        iMaxSplit: 4,
50
+        iCurrentSplit: this.splitNum,
51
+        openDebug: true,
52
+        oStyle: {
53
+          borderSelect: IS_MOVE_DEVICE ? '#000' : '#FFCC00',
54
+        }
55
+      })
57 56
 
57
+      // 事件回调绑定
58
+      this.player.JS_SetWindowControlCallback({
59
+        windowEventSelect: function (iWndIndex) {  //插件选中窗口回调
60
+          console.log('windowSelect callback: ', iWndIndex);
61
+          this.currentWindowIndex = iWndIndex
62
+        },
63
+        pluginErrorHandler: function (iWndIndex, iErrorCode, oError) {  //插件错误回调
64
+          console.log('pluginError callback: ', iWndIndex, iErrorCode, oError);
65
+        },
66
+        windowEventOver: function (iWndIndex) {  //鼠标移过回调
67
+          //console.log(iWndIndex);
68
+        },
69
+        windowEventOut: function (iWndIndex) {  //鼠标移出回调
70
+          //console.log(iWndIndex);
71
+        },
72
+        windowEventUp: function (iWndIndex) {  //鼠标mouseup事件回调
73
+          //console.log(iWndIndex);
74
+        },
75
+        windowFullCcreenChange: function (bFull) {  //全屏切换回调
76
+          console.log('fullScreen callback: ', bFull);
77
+        },
78
+        firstFrameDisplay: function (iWndIndex, iWidth, iHeight) {  //首帧显示回调
79
+          console.log('firstFrame loaded callback: ', iWndIndex, iWidth, iHeight);
80
+        },
81
+        performanceLack: function () {  //性能不足回调
82
+          console.log('performanceLack callback: ');
83
+        }
84
+      });
58 85
     },
59
-    emitChange() {
60
-      this.$emit("input", this.selected);
61
-    }
86
+    play(index, url) {
87
+      return new Promise((resolve, reject) => {
88
+        this.player.JS_Play(url, { playURL: url, mode: this.mode }, index).then(
89
+          () => {
90
+            console.log('realplay success')
91
+            resolve()
92
+          },
93
+          e => {
94
+            console.error(e)
95
+            reject(e)
96
+          }
97
+        )
98
+      })
99
+    },
100
+    testPaly() {
101
+      this.viewUrl = this.viewUrl.replace('59.220.180.103', '172.18.93.217')
102
+      this.player.JS_Play(this.viewUrl, { playURL: this.viewUrl, mode: this.mode }, 0).then(
103
+        () => {
104
+          console.log('realplay success')
105
+          resolve()
106
+        },
107
+        e => {
108
+          console.error(e)
109
+          reject(e)
110
+        }
111
+      )
112
+    },
113
+    stopPlay() {
114
+      if(this.videoMap[this.currentWindowIndex]) {
115
+        const data = this.videoMap[this.currentWindowIndex]
116
+        if(data.taskID) {
117
+          return this.$message.warning('该窗口有正在录制的视频,请先结束录制')
118
+        }
119
+      }
120
+      this.player.JS_Stop().then(
121
+        () => {
122
+          console.log('stop realplay success')
123
+          if(this.videoMap[this.currentWindowIndex]) {
124
+            delete this.videoMap[this.currentWindowIndex]
125
+          }
126
+        },
127
+        e => { console.error(e) }
128
+      )
129
+    },
130
+    stopAllPlay() {
131
+      for(const i of Object.keys(this.videoMap)) {
132
+        const data = this.videoMap[i]
133
+        if(data.taskID) {
134
+          return this.$message.warning('该窗口有正在录制的视频,请先结束录制')
135
+        }
136
+      }
137
+      this.player.JS_StopRealPlayAll().then(
138
+        () => { console.log('stopAllPlay success'); this.videoMap = {} },
139
+        e => { console.error(e) }
140
+      )
141
+    },
142
+    wholeFullScreen() {
143
+      this.player.JS_FullScreenDisplay(true).then(
144
+        () => { console.log(`wholeFullScreen success`) },
145
+        e => { console.error(e) }
146
+      )
147
+    },
148
+    arrangeWindow(n) {
149
+      let splitNum = parseInt(this.splitNum)
150
+      console.log('split num', splitNum)
151
+      this.player.JS_ArrangeWindow(splitNum).then(
152
+        () => { console.log(`arrangeWindow to ${splitNum}x${splitNum} success`) },
153
+        e => { console.error(e) }
154
+      )
155
+    },
156
+    getCameraList() {
157
+      this.cameraListData = []
158
+      return getNVRVideo({orgid: this.orgId}).then(resp => {
159
+        const list = resp || []
160
+        const tree = [
161
+          {
162
+            root: true,
163
+            label: '仓内',
164
+            children: [],
165
+          },
166
+          {
167
+            root: true,
168
+            label: '业务',
169
+            children: [],
170
+          },
171
+          {
172
+            root: true,
173
+            label: '安防',
174
+            children: [],
175
+          },
176
+        ]
177
+        list.forEach(d => {
178
+          const type = d.cameraType
179
+          const temp = {
180
+            label: d.cameraName,
181
+            ... d
182
+          }
183
+          if(type === '1') {
184
+            tree[0].children.push(temp)
185
+          }else if(type === '2') {
186
+            tree[1].children.push(temp)
187
+          }else if(type === '3') {{
188
+            tree[2].children.push(temp)
189
+          }}
190
+        })
191
+        this.cameraListData = tree
192
+      })
193
+    },
194
+    onTreeNodeClick(n) {
195
+      console.log('select tree node', n)
196
+      if(n.root) return
197
+      if(! this.date || this.date.length <= 0 ) {
198
+        return this.$message.warning('请先选择日期')
199
+      }
200
+      this.getPlaybackVideo(n.cameraIndexCode).then(resp => {
201
+        const {url} = resp
202
+        if(url) {
203
+          const { startTime, endTime } = this.date
204
+          this.player.JS_Play(url, { playURL: url, mode: this.mode }, 0, startTime, endTime).then(
205
+            () => {
206
+              console.log('playbackStart success')
207
+            },
208
+            e => { console.error(e) }
209
+          )
210
+        }else {
211
+          this.$message.error('无法获取视频地址')
212
+        }
213
+      })
214
+
215
+    },
216
+    getPlaybackVideo(cameraIndexCode) {
217
+      const [beginTime, endTime] = this.date
218
+      return getPlayback({
219
+        beginTime, endTime, cameraIndexCode, recordLocation: 1, protocol: 'WSS'
220
+      })
221
+    },
222
+
223
+    pause() {
224
+      this.player.JS_Pause().then(
225
+        () => { console.log('playbackPause success') },
226
+        e => { console.error(e) }
227
+      )
228
+    },
229
+    resume() {
230
+      this.player.JS_Resume().then(
231
+        () => { console.log('playbackResume success') },
232
+        e => { console.error(e) }
233
+      )
234
+    },
235
+    stop() {
236
+      this.player.JS_Stop().then(
237
+        () => {  },
238
+        e => { console.error(e) }
239
+      )
240
+    },
241
+    slow() {
242
+      this.player.JS_Slow().then(
243
+        rate => {
244
+          // this.playback.rate = rate
245
+        },
246
+        e => { console.error(e) }
247
+      )
248
+    },
249
+    fast(){
250
+      this.player.JS_Fast().then(
251
+        rate => {
252
+          // this.playback.rate = rate
253
+        },
254
+        e => { console.error(e) }
255
+      )
256
+    },
257
+    findCameraByCameraId(cameraId) {
258
+      for(const root of this.cameraListData) {
259
+        const list = root.children || []
260
+        for(const d of list) {
261
+          if(d.cameraId == cameraId) {
262
+            return d
263
+          }
264
+        }
265
+      }
266
+      return undefined
267
+    },
268
+
62 269
   }
63 270
 }
64 271
 </script>
65 272
 
273
+<template>
274
+  <div class="box">
275
+    <div class="player-box">
276
+      <div class="title">
277
+        <span><i></i> 播放通道</span>
278
+        <span>{{orgName}}</span>
279
+        <span @click="wholeFullScreen" style="cursor: pointer;"><i></i>全屏画面播放</span>
280
+      </div>
281
+      <div id="player"></div>
282
+    </div>
283
+    <div class="control-box">
284
+      <el-tabs v-model="activeName" type="card">
285
+        <el-tab-pane label="摄像头列表" name="cameraList" style="margin: 5px 5px 5px 5px;">
286
+          回放日期: <el-date-picker type="datetimerange" value-format="yyyy-MM-ddTHH:mm:ssZ" v-model="date" style="margin-top: 5px;"/>
287
+          <el-tree :data="cameraListData" :props="{children: 'children', label: 'label'}" @node-click="onTreeNodeClick" style="margin-top: 10px" />
288
+        </el-tab-pane>
289
+        <el-tab-pane label="操作" name="options" style="margin: 5px 5px 5px 5px;">
290
+          <el-row class="row">
291
+            <el-col :span="12">
292
+              <el-button type="primary" class="btn" @click="slow">慢放</el-button>
293
+            </el-col>
294
+            <el-col :span="12">
295
+              <el-button type="primary" class="btn" @click="fast">快放</el-button>
296
+            </el-col>
297
+          </el-row>
298
+          <el-row class="row">
299
+            <el-col :span="6">
300
+              <el-button type="primary" class="btn" @click="pause">暂停</el-button>
301
+            </el-col>
302
+            <el-col :span="6">
303
+              <el-button type="primary" class="btn" @click="resume">恢复</el-button>
304
+            </el-col>
305
+            <el-col :span="6">
306
+              <el-button type="primary" class="btn" @click="stop">停止</el-button>
307
+            </el-col>
308
+          </el-row>
309
+        </el-tab-pane>
310
+      </el-tabs>
311
+    </div>
312
+
313
+  </div>
314
+</template>
315
+
66 316
 <style scoped lang="scss">
67 317
 .box {
68
-  .title {
69
-    display: flex;
70
-    justify-content: space-between;
71
-    margin-bottom: 5px;
318
+  width: 100%;
319
+  display: flex;
320
+  .player-box {
321
+    .title {
322
+      display: flex;
323
+      justify-content: space-between;
324
+      margin-bottom: 5px;
325
+    }
326
+  }
327
+  .control-box {
328
+    margin-left: 10px;
329
+    width: 30%;
330
+
331
+    .btn {
332
+      width: 100px;
333
+      margin-top: 5px;
334
+      margin-left: 10px;
335
+    }
336
+
337
+    .small-btn {
338
+      width: 80px;
339
+      margin-top: 5px;
340
+    }
72 341
   }
73 342
 }
74 343
 
344
+@media screen and (max-width: 991px) {
345
+  #player {
346
+    width: calc(100vw - 16px);
347
+    height: calc((100vw - 16px) * 5 / 8);
348
+  }
349
+  .title {
350
+    width: calc(100vw - 16px);
351
+  }
352
+}
353
+@media screen and (min-width: 992px) {
354
+  #player {
355
+    width: calc(50vw - 8px);
356
+    height: calc((50vw - 8px) * 5 / 8);
357
+  }
358
+  .title {
359
+    width: calc(50vw - 8px);
360
+  }
361
+}
75 362
 </style>

+ 75 - 0
src/page/granaryComprehensiveExhibition/granaryReplay.vue

@@ -0,0 +1,75 @@
1
+<template>
2
+  <div class="content-main">
3
+    <replay :show-camera-control="true"></replay>
4
+  </div>
5
+</template>
6
+
7
+<script>
8
+
9
+import commonSelect from "@/components/common/commonSelect"
10
+import replay from "@/components/common/player/playback_v2.vue"
11
+
12
+export default {
13
+  name: "granaryReplay",
14
+  components: {
15
+    replay,
16
+    commonSelect,
17
+  },
18
+  data() {
19
+    return {
20
+      limit: {
21
+        page: 1,
22
+        size: 10,
23
+        total: 0
24
+      },
25
+      tableData: [],
26
+      form: {
27
+        type: null,
28
+        status: null,
29
+        name: null,
30
+      },
31
+      paginationShow: true,
32
+      listLoading: false,
33
+      inOutType: 'in',
34
+      notificationType: 'grain',
35
+      addShow: false,
36
+      addShowCookingOil: false,
37
+    }
38
+  },
39
+  computed: {
40
+
41
+  },
42
+  methods: {
43
+    search() {
44
+
45
+    },
46
+    reset(formName) {
47
+      if(this.$refs[formName]) {
48
+        this.$refs[formName].resetFields()
49
+      }
50
+    },
51
+    add() {
52
+      this.addShow = true
53
+
54
+    },
55
+    manage(data) {
56
+
57
+    },
58
+    handleCurrentChangeTask() {
59
+
60
+    },
61
+    handleSizeChangeTask() {
62
+
63
+    }
64
+  }
65
+}
66
+</script>
67
+
68
+<style scoped lang="scss">
69
+.small-field {
70
+  width: 150px;
71
+}
72
+.small-date {
73
+  width: 250px;
74
+}
75
+</style>

+ 4 - 4
src/page/spillageLeakageLossCollection/components/spillageLeakageLossCollectionEdit.vue

@@ -5,7 +5,7 @@
5 5
       <el-form ref="editForm" :model="form" :rules="rules" label-width="150px">
6 6
         <el-row type="flex" align="middle" justify="center" class="row">
7 7
           <el-col :span="8">
8
-            <el-form-item label="损单号" prop="sydh">
8
+            <el-form-item label="损单号" prop="sydh">
9 9
               <el-input v-model="form.sydh" placeholder="选择仓房/货位后生成" readonly />
10 10
             </el-form-item>
11 11
           </el-col>
@@ -182,7 +182,7 @@
182 182
 
183 183
         <el-row type="flex" align="middle" justify="center" class="row">
184 184
           <el-col :span="8">
185
-            <el-form-item label="损原因" prop="lossProfitReason">
185
+            <el-form-item label="损原因" prop="lossProfitReason">
186 186
               <el-input v-model="form.lossProfitReason" :readonly="readonly"/>
187 187
             </el-form-item>
188 188
           </el-col>
@@ -280,7 +280,7 @@ export default {
280 280
         impurityOut: null, // number 出库杂质
281 281
         isNormalLoss: null, // integer($int32) 损溢是否正常 1:正常;2:不正常;
282 282
         leadershipAuditor: null, // string 领导审核人
283
-        lossProfitReason: null, // string 损原因
283
+        lossProfitReason: null, // string 损原因
284 284
         moistureImpurityLoss: null, // number 水杂减量
285 285
         moistureIn: null, // number 入库水分
286 286
         moistureLoss: null, // number 水分减量
@@ -295,7 +295,7 @@ export default {
295 295
         storageLoss: null, // number 存储损耗
296 296
         storageTime: null, // string($date-time) 入库时间
297 297
         storageYears: null, // integer($int32) 存储年限
298
-        sydh: null, // string 损单号
298
+        sydh: null, // string 损单号
299 299
         updatedate: null, // string($date-time) 更新日期
300 300
         updatename: null, // string 更新人
301 301
         warehouseAuditor: null, // string 仓储审核人

+ 8 - 0
src/router/system/granaryComprehensiveExhibitionModule.js

@@ -39,6 +39,14 @@ export default {
39 39
       }
40 40
     },
41 41
     {
42
+      path: "/granaryComprehensiveExhibition/granaryReplay",
43
+      name: "granaryLive",
44
+      component: () => import("@/page/granaryComprehensiveExhibition/granaryReplay"),
45
+      meta: {
46
+        title: "视频回放"
47
+      }
48
+    },
49
+    {
42 50
       path: "/granaryComprehensiveExhibition/storehouseWorkRecord",
43 51
       name: "storehouseWorkRecord",
44 52
       component: () => import("@/page/granaryComprehensiveExhibition/storehouseWorkRecord"),