index.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. <template>
  2. <view class="pageContainer">
  3. <view style="width: 100%; min-height: 500rpx; background: #000000;">
  4. <view class="container" v-html="videoHtml"> </view>
  5. </view>
  6. <view class="well-cell">
  7. <view class="well-cell-hd">选择时间:</view>
  8. <view class="well-cell-bd">
  9. <view @click="showCalendar" class="time" style="">{{ timess }}</view>
  10. <!-- <u-input v-model="timess" placeholder="请选择时间" type="text" @click="show = true" /> -->
  11. </view>
  12. <u-icon name="arrow-right"></u-icon>
  13. </view>
  14. <view class="well-cell">
  15. <view class="well-cell-hd">通道选择:</view>
  16. <view class="well-cell-bd">
  17. <u-radio-group @change="radioGroupChange" v-model="videoDevicesIdx">
  18. <u-radio v-for="(item, index) in videoDevices" :key="index" :name="index">
  19. {{ item.videoNumber }}
  20. </u-radio>
  21. </u-radio-group>
  22. </view>
  23. </view>
  24. <view class="well-cell">
  25. <view class="well-cell-hd mt10">媒体类型:</view>
  26. <view class="well-cell-bd">
  27. <u-radio-group v-model="fordata.dataType">
  28. <u-radio :name="0">音视频</u-radio>
  29. <u-radio :name="1">音频</u-radio>
  30. <u-radio :name="2">视频</u-radio>
  31. <u-radio :name="3">视频或音视频</u-radio>
  32. </u-radio-group>
  33. </view>
  34. </view>
  35. <view class="well-cell">
  36. <view class="well-cell-hd mt10">流码类型:</view>
  37. <view class="well-cell-bd">
  38. <u-radio-group v-model="fordata.dataRate">
  39. <u-radio :name="1">主流码</u-radio>
  40. <u-radio :name="2">子码流</u-radio>
  41. </u-radio-group>
  42. </view>
  43. </view>
  44. <playBack @scrollEnd="scrollEnd" ref="playBack" :timeSection="dateAndChannelData"></playBack>
  45. <view style="padding: 20rpx 30rpx;">
  46. <u-button type="primary" shape="circle" @click="btnplayback">回放</u-button>
  47. <u-button class="mt20" type="info" shape="circle" @click="btnoffback">关闭回放</u-button>
  48. </view>
  49. <u-calendar :show="show" mode="single" @close="show = false" ref="calendar" :formatter="formatter"
  50. :maxDate="maxDate"
  51. minDate="2023-10-01"
  52. monthNum="24" @confirm="confirm"></u-calendar>
  53. <u-toast ref="uToast" />
  54. </view>
  55. </template>
  56. <script>
  57. import playBack from '@/components/playBack'
  58. import createFlvPlayer from "./FlvPlayerVideo.js";
  59. import { uniqueId } from 'lodash'
  60. import { getDetail, dayStat, playbackPull, playbackPlay } from "@/api/system/video";
  61. export default {
  62. components: {
  63. playBack
  64. },
  65. data() {
  66. return {
  67. flvServer: '',
  68. show: false,
  69. mode: 'date',
  70. vehicleId: '',
  71. maxDate: this.dayjs().add(365, 'day').format('YYYY-MM-DD'),
  72. datatimes: {
  73. deviceId: '',
  74. startDate: '',
  75. endDate: '',
  76. },
  77. timess: '',
  78. dayStatList: [],//存在视频日期
  79. Datelist: [],//存在视频时间
  80. videoNumber: [1, 2, 3, 4],
  81. videoDevices:[],
  82. videoDevicesIdx:0,
  83. fordata: {
  84. channel: 1,//路数
  85. dataType: 0,//媒体类型
  86. dataRate: 1,//码流
  87. deviceId: '',//设备id
  88. endTime: '',//结束时间
  89. startTime: '',//开始时间
  90. storageType: 0,
  91. },
  92. flvform: '',
  93. player: '',
  94. videoHtml: "",
  95. videoItem: {
  96. url: '',
  97. dataNumber: '',
  98. dataDeviceId: '',
  99. dataCameraId: ''
  100. },
  101. dateAndChannelData: []
  102. };
  103. },
  104. computed: {},
  105. watch: {},
  106. created() { },
  107. mounted() {
  108. window.closeMaker = this.closeMaker
  109. },
  110. onLoad(option) {
  111. console.log('参数', option)
  112. //组装当月的第一天和最后一天获取是否有数据
  113. this.datatimes.startDate = this.dayjs().startOf('month').format('YYYY-MM-DD');
  114. this.datatimes.endDate = this.dayjs().endOf('month').format('YYYY-MM-DD');
  115. //废弃
  116. // if (option.deviceId) {
  117. // this.fordata.deviceId = option.deviceId
  118. // this.videoId = uniqueId('flv_video_')
  119. // this.getDayStat();
  120. // }
  121. if (option.vehicleId) {
  122. this.vehicleId=option.vehicleId
  123. this.getDetail()
  124. }
  125. },
  126. onReady() {
  127. // 如果需要兼容微信小程序的话,需要用此写法
  128. this.$refs.calendar.setFormatter(this.formatter)
  129. },
  130. methods: {
  131. // 获取车辆信息
  132. async getDetail() {
  133. console.log('获取车辆信息',this.vehicleId)
  134. let { data } = await getDetail({
  135. vehicleId: this.vehicleId
  136. })
  137. if(data.videoDevices.length>0){
  138. this.videoDevices = data.videoDevices
  139. this.fordata.deviceId = data.videoDevices[0].deviceId
  140. this.fordata.channel = data.videoDevices[0].videoNumber
  141. this.videoId = uniqueId('flv_video_')
  142. this.getDayStat();
  143. }else{
  144. uni.showToast({
  145. title: '设备号不存在',
  146. duration: 2000,
  147. icon:'none'
  148. });
  149. }
  150. },
  151. // 获取设备有回放日期
  152. async getDayStat() {
  153. let { data } = await dayStat({
  154. deviceId: this.fordata.deviceId,//设备号
  155. startDate: '2023-10-01',
  156. endDate: this.dayjs().add(365, 'day').format('YYYY-MM')//
  157. })
  158. this.dayStatList = data.map(e => {
  159. return e.statDate
  160. })
  161. console.log('数据', this.dayStatList)
  162. },
  163. showCalendar() {
  164. this.show = true
  165. },
  166. formatter(day) {
  167. let date = this.dayjs(day.date).format('YYYY-MM-DD')
  168. if (this.dayStatList.includes(date)) {
  169. day.bottomInfo = '有记录'
  170. day.dot = true
  171. }
  172. return day
  173. },
  174. //切换月份的时候拉取数据 旧版
  175. // async tomonth(date2) {
  176. // var date = new Date(date2);
  177. // var firstDay = new Date(date.getFullYear(), date.getMonth(), 1);
  178. // var lastDay = new Date(date.getFullYear(), date.getMonth() + 1, 0);
  179. // this.datatimes.startDate = this.$moment(firstDay).locale("zh-cn").format("YYYY-MM-DD");
  180. // this.datatimes.endDate = this.$moment(lastDay).locale("zh-cn").format("YYYY-MM-DD");
  181. // for (var k in this.datatimes) {
  182. // console.log(this.datatimes)
  183. // if (this.datatimes[k] == null) {
  184. // this.$refs.uToast.show({ title: "参数不完整", type: "error" });
  185. // return
  186. // }
  187. // }
  188. // this.Datelist = [];
  189. // //根据设备号获取当月有那一下视频数据
  190. // let url2 = this.$u.api.vehContainer.findVideoResByDate;
  191. // let res2 = await this.$u.post(url2, this.datatimes);
  192. // //组装数据
  193. // if (res2.errorCode == '0') {
  194. // for (var i = 0; i < res2.data.length; i++) {
  195. // this.Datelist.push(res2.data[i].statDate);
  196. // }
  197. // }
  198. // },
  199. // async findVideoResByDate() {
  200. // let obj = {
  201. // vehicle_id: this.vehicleId,
  202. // };
  203. // this.Datelist = [];
  204. // //获取车辆信息
  205. // let url = this.$u.api.vehContainer.queryVideoInfoById;
  206. // let res = await this.$u.post(url, obj, { showLoading: false });
  207. // if (res.errorCode == '0') {
  208. // this.flvform = res.data;
  209. // //多设备
  210. // if (res.data.videoDeviceId == null) {
  211. // this.datatimes.deviceId = res.data.deviceId;
  212. // } else {
  213. // this.datatimes.deviceId = res.data.videoDeviceId;
  214. // }
  215. // this.fordata.deviceId = this.datatimes.deviceId;//设备id
  216. // //获取设置的通道号
  217. // if (res.data.videoDeviceId != null) {
  218. // var nubervideo = res.data.videoDeviceId.split(',');
  219. // if (nubervideo.length > 0) {
  220. // for (var i = 0; i < nubervideo.length; i++) {
  221. // if (nubervideo[i] == '') {
  222. // nubervideo.splice(i, 0);
  223. // }
  224. // }
  225. // }
  226. // this.videoNumber = nubervideo;
  227. // }
  228. // for (var k in this.datatimes) {
  229. // console.log(this.datatimes)
  230. // if (this.datatimes[k] == null) {
  231. // this.$refs.uToast.show({ title: "参数不完整", type: "error" });
  232. // return
  233. // }
  234. // }
  235. // //根据设备号获取当月有那一下视频数据
  236. // let url2 = this.$u.api.vehContainer.findVideoResByDate;
  237. // let res2 = await this.$u.post(url2, this.datatimes);
  238. // //组装数据
  239. // if (res2.errorCode == '0') {
  240. // for (var i = 0; i < res2.data.length; i++) {
  241. // this.Datelist.push(res2.data[i].statDate);
  242. // }
  243. // }
  244. // console.log('组装数据', this.Datelist)
  245. // }
  246. // },
  247. confirm(e) {
  248. console.log('confirm', e)
  249. let result = e[0];
  250. this.show = false
  251. this.timess = result;
  252. this.fordata.startTime = result + ' 00:00:00';
  253. this.fordata.endTime = result + ' 23:59:59';
  254. },
  255. // 选中任一radio时,由radio-group触发videoOneDayResource
  256. radioGroupChange(e) {
  257. this.fordata.channel = this.videoDevices[e].videoNumber;
  258. this.fordata.deviceId = this.videoDevices[e].deviceId;
  259. },
  260. async btnplayback() { //查询可回放时间资源并播放
  261. console.log(123)
  262. if (this.timess == '' || this.timess == undefined || this.timess == null) {
  263. uni.showToast({
  264. title: '请选择时间',
  265. duration: 2000,
  266. icon: 'none'
  267. });
  268. return
  269. }
  270. for (var k in this.fordata) {
  271. console.log(this.fordata)
  272. if (this.fordata[k] == null) {
  273. uni.showToast({
  274. title: '参数不完整',
  275. duration: 2000,
  276. icon: 'none'
  277. });
  278. return
  279. }
  280. }
  281. let { data, code } = await playbackPull({
  282. ...this.fordata,
  283. })
  284. this.dateAndChannelData = data.resources
  285. //获取资源信息
  286. // let url = this.$u.api.vehContainer.videoOneDayResource;
  287. // let res = await this.$u.post(url, this.fordata, { methodType: "body" });
  288. // if (res.errorCode == '0') {
  289. // this.findResByDateAndChannel();
  290. // }
  291. },
  292. async findResByDateAndChannel() {
  293. let url = this.$u.api.vehContainer.findResByDateAndChannel;
  294. let obj = {
  295. deviceId: this.fordata.deviceId,//设备id
  296. fileDate: this.timess,//时间
  297. channel: this.fordata.channel,//通道号
  298. }
  299. let res = await this.$u.post(url, obj);
  300. if (res.errorCode == '0') {
  301. this.dateAndChannelData = res.data[this.fordata.channel]
  302. console.log('视频段', this.dateAndChannelData)
  303. //下发指令
  304. this.postVideoHis()
  305. }
  306. },
  307. generatePlayVideo(flvUrl) {
  308. console.log("flvPlayBox" + this.fordata.channel, '播放视频地址', flvUrl)
  309. this.flvServer = createFlvPlayer(`#${this.videoId}`, flvUrl);
  310. },
  311. checkResultData(data) {
  312. // 检测数据
  313. return data == null || data == undefined ? "" : data;
  314. },
  315. //关闭回放
  316. async btnoffback() {
  317. this.videoHtml = '';
  318. this.$refs.playBack.resetComponents();
  319. this.flvServer.destroyVideo()
  320. },
  321. // 下发视频录像回放
  322. async postVideoHis() {
  323. let videoHtml = ''
  324. let url2 = this.$u.api.vehContainer.videoHis;
  325. this.fordata.fastTimes = 0;
  326. this.fordata.playback = 0;
  327. let res2 = await this.$u.post(url2, this.fordata, { methodType: "body" });
  328. if (res2.errorCode == '0') {
  329. this.$refs.uToast.show({ title: "指令下发成功", type: "success" });
  330. this.$nextTick(() => {
  331. // 指令下发成功
  332. let videoIp = this.checkResultData(this.flvform.videoIp);//视频ip
  333. let videoPort = this.checkResultData(this.flvform.videoPort);//视频端口
  334. let cameraId = this.checkResultData(this.flvform.cameraId); //设备id
  335. let channel = this.checkResultData(this.fordata.channel);//通道号
  336. let timestamp = new Date().getTime();
  337. let flvUrl = `https://${videoIp}:${videoPort}/video/history/${cameraId}-${channel}/time${timestamp}`// 视频流地址
  338. console.log(flvUrl)
  339. this.videoItem = {
  340. url: `https://${videoIp}:${videoPort}/video/now/${cameraId}-${channel}`,
  341. dataNumber: channel,
  342. dataDeviceId: cameraId,
  343. dataCameraId: cameraId + channel
  344. }
  345. videoHtml += `
  346. <view class="videoBox">
  347. <div
  348. class="flvPlayBox"
  349. id="${this.videoId}"
  350. ></div>
  351. <view class="videoTips" style="color: #fff;">
  352. ${channel}路
  353. <i class="online"></i>
  354. <text class="text">在线</text>
  355. </view>
  356. </view>
  357. `;
  358. this.videoHtml = videoHtml;
  359. this.$nextTick(() => {
  360. this.generatePlayVideo(flvUrl);
  361. });
  362. });
  363. }
  364. //
  365. },
  366. //滚动进度条
  367. async scrollEnd(e) {
  368. console.log('开始进度条',e)
  369. if (!e) return;
  370. let { data } = await playbackPlay({
  371. ...this.fordata,
  372. startTime: this.timess + ' ' + e.itemTime,
  373. endTime: e.endTime
  374. })
  375. let flvUrl = this.$getImages(data.videoUrl)
  376. let channel = this.fordata.channel
  377. let cameraId = this.fordata.deviceId
  378. let videoHtml = ''
  379. videoHtml += `
  380. <view class="videoBox">
  381. <div
  382. class="flvPlayBox"
  383. id="${this.videoId}"
  384. ></div>
  385. <view class="videoTips" style="color: #fff;">
  386. ${channel}路
  387. <i class="online"></i>
  388. <text class="text">在线</text>
  389. </view>
  390. </view>
  391. `;
  392. this.videoHtml = videoHtml;
  393. this.$nextTick(() => {
  394. this.generatePlayVideo(flvUrl);
  395. });
  396. }
  397. },
  398. };
  399. </script>
  400. <style scoped lang="scss">
  401. .well-cell {
  402. padding: 20rpx 20rpx 16rpx 20rpx;
  403. display: flex;
  404. align-items: center;
  405. box-sizing: border-box;
  406. .well-cell-bd {
  407. flex: 1;
  408. margin-left: 30rpx;
  409. .time {
  410. width: 100%;
  411. height: 40rpx;
  412. padding-left: 24rpx;
  413. }
  414. /deep/ .u-radio-group {
  415. flex-wrap: wrap;
  416. .u-radio {
  417. margin-left: 20rpx;
  418. margin-bottom: 10rpx;
  419. }
  420. }
  421. }
  422. }
  423. .mt10 {
  424. margin-top: 10rpx;
  425. }
  426. .centeredVideo {
  427. width: 100%;
  428. height: 100%;
  429. }
  430. .mt20 {
  431. margin-top: 20rpx;
  432. }
  433. .videoTips {
  434. color: #fff;
  435. }
  436. </style>