PlaybackList.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <template>
  2. <div class="">
  3. <div class="box box-primary">
  4. <div class="box-header">
  5. <h4 class="text-primary text-center">设备录像列表({{devid}}-{{channel}})</h4>
  6. </div>
  7. <div class="box-body">
  8. <form class="form-inline">
  9. <div class="form-group form-group-sm">
  10. <button type="button" class="btn btn-sm btn-primary" @click.prevent="$router.go(-1)">
  11. <i class="fa fa-chevron-left"></i> 返回
  12. </button>
  13. </div>
  14. <div class="form-group pull-right">
  15. <div class="input-group input-group-sm">
  16. <DatePicker class="form-control" @update:day="updateDay" :day="day" ref="datePicker"></DatePicker>
  17. <div class="input-group-btn">
  18. <button type="button" class="btn btn-sm btn-default" @click.prevent="showDatePicker">
  19. <i class="fa fa-calendar"></i>
  20. </button>
  21. <router-link :to="`/devices/playback/timebox/${this.devid}/${this.channel}/${this.day}`" replace class="btn btn-default btn-sm">
  22. <i class="fa fa-hand-o-right"></i> 时间轴视图
  23. </router-link>
  24. </div>
  25. </div>
  26. </div>
  27. </form>
  28. <br>
  29. <div class="clearfix"></div>
  30. <el-table :data="records" stripe v-loading="loading" element-loading-text="加载中...">
  31. <el-table-column prop="DeviceID" label="通道国标编号" min-width="200" show-overflow-tooltip></el-table-column>
  32. <el-table-column label="操作" min-width="190" v-if="isMobile()">
  33. <template slot-scope="props">
  34. <div class="btn-group btn-group-xs">
  35. <button type="button" class="btn btn-primary" @click.prevent="startPlayback(props.row)" :disabled="props.row.Starting"><i class="fa fa-play-circle"></i> 播放</button>
  36. <button type="button" class="btn btn-info" @click.prevent="downloadPlayback(props.row)" :disabled="props.row.Starting"><i class="fa fa-download"> 下载</i></button>
  37. <a :href="`/play.html?type=playback&ptz=no&serial=${devid}&code=${props.row.DeviceID}&starttime=${props.row.StartTime}&endtime=${props.row.EndTime}`" role="button" class="btn btn-warning" target="_blank"><i class="fa fa-share"></i> 分享页</a>
  38. </div>
  39. </template>
  40. </el-table-column>
  41. <el-table-column prop="Name" label="通道名称" min-width="120" :formatter="formatName" show-overflow-tooltip></el-table-column>
  42. <el-table-column prop="StartTime" label="开始时间" min-width="160" :formatter="formatName"></el-table-column>
  43. <el-table-column prop="EndTime" label="结束时间" min-width="160" :formatter="formatName"></el-table-column>
  44. <el-table-column label="操作" min-width="190" fixed="right" v-if="!isMobile()">
  45. <template slot-scope="props">
  46. <div class="btn-group btn-group-xs">
  47. <button type="button" class="btn btn-primary" @click.prevent="startPlayback(props.row)" :disabled="props.row.Starting"><i class="fa fa-play-circle"></i> 播放</button>
  48. <button type="button" class="btn btn-info" @click.prevent="downloadPlayback(props.row)" :disabled="props.row.Starting"><i class="fa fa-download"> 下载</i></button>
  49. <a :href="`/play.html?type=playback&ptz=no&serial=${devid}&code=${props.row.DeviceID}&starttime=${props.row.StartTime}&endtime=${props.row.EndTime}`" role="button" class="btn btn-warning" target="_blank"><i class="fa fa-share"></i> 分享页</a>
  50. </div>
  51. </template>
  52. </el-table-column>
  53. </el-table>
  54. </div>
  55. </div>
  56. <PlaybackVideoDlg ref="playbackVideoDlg" live></PlaybackVideoDlg>
  57. <PlaybackDownloadDlg ref="playbackDownloadDlg"></PlaybackDownloadDlg>
  58. </div>
  59. </template>
  60. <script>
  61. import _ from "lodash";
  62. import moment from "moment";
  63. import DatePicker from "components/DatePicker.vue";
  64. import PlaybackVideoDlg from "components/PlaybackVideoDlg";
  65. import PlaybackDownloadDlg from "components/PlaybackDownloadDlg";
  66. export default {
  67. props: {
  68. devid: {
  69. type: String,
  70. default: ""
  71. },
  72. channel: {
  73. type: String,
  74. default: ""
  75. },
  76. mode: {
  77. type: String,
  78. default: "list"
  79. },
  80. day: {
  81. type: String,
  82. default: () => moment().format("YYYYMMDD")
  83. }
  84. },
  85. data() {
  86. return {
  87. timerange: [
  88. moment(this.day, "YYYYMMDD").startOf('hour').toDate(),
  89. moment(this.day, "YYYYMMDD").startOf('hour').toDate()
  90. ],
  91. loading: false,
  92. records: []
  93. };
  94. },
  95. watch: {
  96. day: function(newVal, oldVal) {
  97. this.timerange = [
  98. moment(this.day, "YYYYMMDD").startOf('hour').toDate(),
  99. moment(this.day, "YYYYMMDD").startOf('hour').toDate()
  100. ]
  101. }
  102. },
  103. components: {
  104. PlaybackVideoDlg, PlaybackDownloadDlg, DatePicker
  105. },
  106. methods: {
  107. keyDown(e) {
  108. if(e.keyCode == 27) {
  109. this.$el.querySelector('.fa-chevron-left').click();
  110. }
  111. },
  112. isMobile() {
  113. return videojs.browser.IS_IOS || videojs.browser.IS_ANDROID;
  114. },
  115. showDatePicker() {
  116. $(this.$refs.datePicker.$el).focus();
  117. },
  118. updateDay(day) {
  119. this.$router.replace(`/devices/playback/${this.mode}/${this.devid}/${this.channel}/${day}`);
  120. },
  121. nextTimeRange() {
  122. var end = moment(this.day, "YYYYMMDD").add(24, 'hours');
  123. var now = moment().startOf("second");
  124. if(end.isAfter(now, "second")) {
  125. end = now;
  126. }
  127. var r1 = moment(this.timerange[1]);
  128. if(r1.isSameOrAfter(end, "second")){
  129. return false;
  130. }
  131. var r2 = moment(this.timerange[1]).add(6, 'hours');
  132. if(r2.isAfter(end)) {
  133. r2 = end;
  134. }
  135. if(r2.startOf("minute").isSameOrBefore(r1.startOf("minute"), "second")) {
  136. return false;
  137. }
  138. this.timerange = [r1.toDate(), r2.toDate()];
  139. return true;
  140. },
  141. getRecords(refresh) {
  142. if(refresh) {
  143. this.loading = true;
  144. this.records = [];
  145. }
  146. if(!this.nextTimeRange()){
  147. this.loading = false;
  148. return
  149. }
  150. $.ajax("/api/v1/playback/recordlist", {
  151. type: 'get',
  152. global: false,
  153. data: {
  154. timeout: 5,
  155. serial: this.devid,
  156. code: this.channel,
  157. starttime: moment(this.timerange[0]).format("YYYY-MM-DDTHH:mm:ss"),
  158. endtime: moment(this.timerange[1]).format("YYYY-MM-DDTHH:mm:ss")
  159. }
  160. }).then(ret => {
  161. var items = ret.RecordList || [];
  162. this.records = this.records.concat(items.filter(item => {
  163. if(!item || !item.StartTime || !item.EndTime) {
  164. return false;
  165. }
  166. return true;
  167. }));
  168. }).always(() => {
  169. this.$nextTick(() => {
  170. this.getRecords(false);
  171. })
  172. });
  173. },
  174. formatName(row, col, cell) {
  175. if (cell) return cell;
  176. return "-";
  177. },
  178. downloadPlayback(row) {
  179. this.loading = true;
  180. this.$set(row, "Starting", true);
  181. $.get("/api/v1/playback/start", {
  182. serial: this.devid,
  183. code: this.channel,
  184. starttime: row.StartTime,
  185. endtime: row.EndTime,
  186. download: true
  187. }).then(ret => {
  188. this.$refs["playbackDownloadDlg"].download(row.StartTime + " - " + row.EndTime, ret.StreamID);
  189. }).always(() => {
  190. this.loading = false;
  191. this.$delete(row, "Starting");
  192. });
  193. },
  194. startPlayback(row) {
  195. this.loading = true;
  196. this.$set(row, "Starting", true);
  197. $.get("/api/v1/playback/start", {
  198. serial: this.devid,
  199. code: this.channel,
  200. starttime: row.StartTime,
  201. endtime: row.EndTime
  202. }).then(ret => {
  203. var videoUrl = this.isMobile() ? ret.HLS : ret.RTMP;
  204. var protocol = this.isMobile() ? "HLS" : "RTMP";
  205. if(this.flvSupported()) {
  206. if(ret.WS_FLV && !this.isIE()) {
  207. protocol = "WS_FLV";
  208. videoUrl = ret.WS_FLV;
  209. } else if(ret.FLV) {
  210. protocol = "FLV";
  211. videoUrl = ret.FLV;
  212. }
  213. }
  214. var snap = protocol == "RTMP" ? "" : (row.Snap || "");
  215. this.$refs["playbackVideoDlg"].play(
  216. videoUrl,
  217. row.Name || row.DeviceID,
  218. snap,
  219. this.devid,
  220. this.channel,
  221. ret.StreamID
  222. );
  223. }).always(() => {
  224. this.loading = false;
  225. this.$delete(row, "Starting");
  226. });
  227. },
  228. },
  229. mounted() {
  230. this.getRecords(true);
  231. // $(document).on("keydown", this.keyDown);
  232. },
  233. beforeDestroy() {
  234. // $(document).off('keydown', this.keyDown);
  235. },
  236. beforeRouteUpdate(to, from, next) {
  237. next();
  238. this.$nextTick(() => {
  239. this.getRecords(true);
  240. })
  241. }
  242. };
  243. </script>