deviceVideo.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. <template>
  2. <div style="display: block; width: 1000px">
  3. <div style="display: flex">
  4. <el-row>
  5. <span style="margin-left: 10px" prop="channelName">通道:</span>
  6. <el-select v-model="channelId" placeholder="请选择" @change="changeChannel" style="width: 200px; margin-right: 10px" size="small">
  7. <el-option v-for="option in channelList" :key="option.value" :label="option.label" :value="option.value"></el-option>
  8. </el-select>
  9. <span style="overflow: auto; margin-left: 10px">日期:</span>
  10. <el-date-picker v-model="queryDate" type="date" size="small" value-format="yyyy-MM-dd" clearable placeholder="选择日期" style="width: 180px; margin-right: 10px" />
  11. <el-button-group style="margin: 0">
  12. <el-button size="mini" type="success" title="查看录像" @click="loadDevRecord()" :disabled="channelId === '' || !queryDate">
  13. <i class="el-icon-video-camera" />
  14. 查看
  15. </el-button>
  16. </el-button-group>
  17. <span style="margin-left: 82px; overflow: auto">时间:</span>
  18. <el-button-group>
  19. <el-time-picker
  20. size="small"
  21. is-range
  22. align="left"
  23. v-model="timeRange"
  24. value-format="yyyy-MM-dd HH:mm:ss"
  25. range-separator="至"
  26. start-placeholder="开始时间"
  27. end-placeholder="结束时间"
  28. placeholder="选择时间范围"
  29. @change="timePickerChange"
  30. style="width: 200px"
  31. :disabled="channelId === '' || !queryDate"
  32. ></el-time-picker>
  33. </el-button-group>
  34. <el-button-group style="margin: 0 0 0 10px">
  35. <el-button size="mini" type="primary" title="下载选定录像" @click="downloadRecord()" :disabled="channelId === '' || !timeRange">
  36. <i class="el-icon-download" />
  37. 转存
  38. </el-button>
  39. </el-button-group>
  40. </el-row>
  41. </div>
  42. <player ref="playbacker" :playerinfo="playinfo" class="components-container"></player>
  43. </div>
  44. </template>
  45. <script>
  46. import player from './player.vue';
  47. import { listChannel, playback, closeStream, playbackSeek } from '@/api/pms/video/channel';
  48. import { getDevRecord, startDownloadRecord } from '@/api/iot/record';
  49. export default {
  50. name: 'DeviceVideo',
  51. components: {
  52. player,
  53. },
  54. data() {
  55. return {
  56. deviceId: '',
  57. channelId: '',
  58. streamId: '',
  59. ssrc: '',
  60. playurl: '',
  61. queryDate: '',
  62. playing: false,
  63. vodData: {},
  64. hisData: [],
  65. playinfo: {},
  66. channelList: [],
  67. playbackinfo: {},
  68. timeRange: null,
  69. startTime: null,
  70. endTime: null,
  71. // 查询参数
  72. queryParams: {
  73. pageNum: 1,
  74. pageSize: 10,
  75. deviceSipId: null,
  76. channelSipId: null,
  77. },
  78. };
  79. },
  80. props: {
  81. device: {
  82. type: Object,
  83. default: null,
  84. },
  85. },
  86. watch: {
  87. // 获取到父组件传递的device后
  88. device: function (newVal, oldVal) {
  89. this.deviceInfo = newVal;
  90. if (this.deviceInfo && this.deviceInfo.deviceId !== 0) {
  91. this.queryParams.deviceSipId = this.deviceInfo.serialNumber;
  92. this.deviceId = this.device.serialNumber;
  93. }
  94. },
  95. },
  96. created() {
  97. this.queryParams.deviceSipId = this.device.serialNumber;
  98. this.deviceId = this.device.serialNumber;
  99. this.getList();
  100. this.playinfo = {
  101. playtype: 'playback',
  102. deviceId: this.device.serialNumber,
  103. };
  104. },
  105. beforeDestroy() {
  106. this.closeStream();
  107. },
  108. methods: {
  109. /** 查询监控设备通道信息列表 */
  110. getList() {
  111. this.loading = true;
  112. listChannel(this.queryParams).then((response) => {
  113. this.channelList = response.rows.map((item) => {
  114. return { value: item.channelSipId, label: item.channelName };
  115. });
  116. });
  117. },
  118. // 改变通道
  119. changeChannel() {
  120. this.playinfo.channelId = this.channelId;
  121. },
  122. initUrl(data) {
  123. if (data) {
  124. this.streamId = data.ssrc;
  125. this.ssrc = data.ssrc;
  126. this.playurl = data.playurl;
  127. } else {
  128. this.streamId = '';
  129. this.ssrc = '';
  130. this.playurl = '';
  131. }
  132. },
  133. getBeijingTime(queryDate) {
  134. // 计算与UTC的时区差,对于北京时间来说是8小时
  135. let offset = 8 * 60 * 60 * 1000;
  136. // 加上时区差,得到北京时间
  137. let beijingTime = new Date(new Date(queryDate).getTime() - offset);
  138. return beijingTime.getTime();
  139. },
  140. // 录像控制
  141. loadDevRecord() {
  142. this.$refs.playbacker.registercallback('playbackSeek', this.seekPlay);
  143. if (this.queryDate === '' || this.queryDate === null) {
  144. this.$message.error('请选择日期');
  145. return;
  146. }
  147. if (this.deviceId && this.channelId) {
  148. const date = this.getBeijingTime(this.queryDate);
  149. const start = date / 1000;
  150. const end = Math.floor((date + 24 * 60 * 60 * 1000 - 1) / 1000);
  151. const query = {
  152. start: start,
  153. end: end,
  154. };
  155. this.vodData = {
  156. start: start,
  157. end: end,
  158. base: start,
  159. };
  160. this.setTime(this.queryDate + ' 00:00:00', this.queryDate + ' 23:59:59');
  161. getDevRecord(this.deviceId, this.channelId, query).then((res) => {
  162. this.hisData = res.data.recordItems;
  163. if (res.data.recordItems) {
  164. const len = this.hisData.length;
  165. if (len > 0) {
  166. if (this.hisData[0].start < start) {
  167. this.hisData[0].start = start;
  168. this.vodData.start = start;
  169. } else {
  170. this.vodData.start = this.hisData[0].start;
  171. }
  172. if (this.hisData[0].end !== 0 && this.hisData[0].end < end) {
  173. this.vodData.end = this.hisData[0].end;
  174. }
  175. this.playback();
  176. } else {
  177. this.$message({
  178. type: 'warning',
  179. message: '请确认设备是否支持录像,或者设备SD卡是否正确插入!',
  180. });
  181. }
  182. } else {
  183. this.$message({
  184. type: 'warning',
  185. message: '请确认设备是否支持录像,或者设备SD卡是否正确插入!',
  186. });
  187. }
  188. });
  189. }
  190. },
  191. /**录像播放*/
  192. playback() {
  193. const query = {
  194. start: this.vodData.start,
  195. end: this.vodData.end,
  196. };
  197. if (this.ssrc) {
  198. closeStream(this.deviceId, this.channelId, this.ssrc).then((res) => {
  199. playback(this.deviceId, this.channelId, query)
  200. .then((res) => {
  201. this.initUrl(res.data);
  202. })
  203. .finally(() => {
  204. this.triggerPlay(this.hisData);
  205. });
  206. });
  207. } else {
  208. playback(this.deviceId, this.channelId, query)
  209. .then((res) => {
  210. this.initUrl(res.data);
  211. })
  212. .finally(() => {
  213. this.triggerPlay(this.hisData);
  214. });
  215. }
  216. },
  217. /**触发播放*/
  218. triggerPlay(playTimes) {
  219. this.$refs.playbacker.playback(this.playurl, playTimes);
  220. this.playing = true;
  221. },
  222. /**录像播放*/
  223. seekPlay(s) {
  224. const curTime = this.vodData.base + s.hour * 3600 + s.min * 60 + s.second;
  225. const seekRange = curTime - this.vodData.start;
  226. if (this.ssrc) {
  227. const query = {
  228. seek: seekRange,
  229. };
  230. const _this = this;
  231. playbackSeek(this.deviceId, this.channelId, this.streamId, query).then((res) => {
  232. _this.$refs.playbacker.setPlaybackStartTime(curTime);
  233. });
  234. }
  235. },
  236. /**关闭播放流*/
  237. closeStream() {
  238. if (this.playing && this.streamId) {
  239. closeStream(this.deviceId, this.channelId, this.streamId).then((res) => {
  240. this.streamId = '';
  241. this.ssrc = '';
  242. this.playurl = '';
  243. this.playing = false;
  244. });
  245. // this.$refs.playbacker.destroy();
  246. }
  247. },
  248. /**销毁录像播放器*/
  249. destroy() {
  250. if (this.playing && this.streamId) {
  251. this.$refs.playbacker.destroy();
  252. }
  253. },
  254. closeDestroy() {
  255. this.closeStream();
  256. this.destroy();
  257. },
  258. /**设置时间*/
  259. timePickerChange: function (val) {
  260. this.setTime(val[0], val[1]);
  261. },
  262. setTime: function (startTime, endTime) {
  263. this.startTime = startTime;
  264. this.endTime = endTime;
  265. this.timeRange = [startTime, endTime];
  266. },
  267. /**下载录像*/
  268. downloadRecord: function () {
  269. const start = new Date(this.startTime).getTime() / 1000;
  270. const end = new Date(this.endTime).getTime() / 1000;
  271. const query = {
  272. startTime: start,
  273. endTime: end,
  274. speed: '4',
  275. };
  276. startDownloadRecord(this.deviceId, this.channelId, query).then((res) => {
  277. console.log('开始转存到流服务器:' + this.deviceId + ' : ' + this.channelId);
  278. if (res.code === 200) {
  279. this.$message({
  280. type: 'success',
  281. message: '转存到流服务器,请前往视频中心->录像管理查看!',
  282. });
  283. }
  284. });
  285. },
  286. },
  287. };
  288. </script>