| | |
| | | } |
| | | // 如果是录像下载就设置视频间隔十秒 |
| | | if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { |
| | | result.setMp4_max_second(10); |
| | | result.setMp4_max_second(30); |
| | | result.setEnable_mp4(true); |
| | | } |
| | | } |
| | |
| | | /** |
| | | * 分页回去云端录像列表 |
| | | */ |
| | | PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); |
| | | PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); |
| | | |
| | | /** |
| | | * 根据hook消息增加一条记录 |
| | |
| | | private VideoStreamSessionManager streamSession; |
| | | |
| | | @Override |
| | | public PageInfo<CloudRecordItem> getList(int page, int count, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { |
| | | public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { |
| | | // 开始时间和结束时间在数据库中都是以秒为单位的 |
| | | Long startTimeStamp = null; |
| | | Long endTimeStamp = null; |
| | |
| | | |
| | | } |
| | | PageHelper.startPage(page, count); |
| | | List<CloudRecordItem> all = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, endTimeStamp, |
| | | List<CloudRecordItem> all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp, |
| | | null, mediaServerItems); |
| | | return new PageInfo<>(all); |
| | | } |
| | |
| | | } |
| | | long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); |
| | | long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); |
| | | List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(app, stream, startTimeStamp, |
| | | List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, |
| | | endTimeStamp, null, mediaServerItems); |
| | | if (cloudRecordItemList.isEmpty()) { |
| | | return new ArrayList<>(); |
| | |
| | | } |
| | | |
| | | // 为了支持多个数据库,这里不能使用求和函数来直接获取总数了 |
| | | List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList("rtp", inviteInfo.getStream(), null, null, ssrcTransaction.getCallId(), null); |
| | | List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, "rtp", inviteInfo.getStream(), null, null, ssrcTransaction.getCallId(), null); |
| | | |
| | | if (cloudRecordItemList.isEmpty()) { |
| | | logger.warn("[获取下载进度],未找到下载视频信息"); |
| | |
| | | "select * " + |
| | | " from wvp_cloud_record " + |
| | | " where 0 = 0" + |
| | | " <if test='query != null'> AND (app LIKE concat('%',#{query},'%') OR stream LIKE concat('%',#{query},'%') )</if> " + |
| | | " <if test= 'app != null '> and app=#{app}</if>" + |
| | | " <if test= 'stream != null '> and stream=#{stream}</if>" + |
| | | " <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" + |
| | |
| | | " <if test= 'mediaServerItemList != null ' > and media_server_id in " + |
| | | " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + |
| | | " </if>" + |
| | | " order by start_time DESC" + |
| | | |
| | | " </script>") |
| | | List<CloudRecordItem> getList(@Param("app") String app, @Param("stream") String stream, |
| | | List<CloudRecordItem> getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream, |
| | | @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, |
| | | @Param("callId")String callId, List<MediaServerItem> mediaServerItemList); |
| | | |
| | |
| | | @ResponseBody |
| | | @GetMapping("/list") |
| | | @Operation(summary = "分页查询云端录像") |
| | | @Parameter(name = "app", description = "应用名", required = true) |
| | | @Parameter(name = "stream", description = "流ID", required = true) |
| | | @Parameter(name = "query", description = "检索内容", required = false) |
| | | @Parameter(name = "app", description = "应用名", required = false) |
| | | @Parameter(name = "stream", description = "流ID", required = false) |
| | | @Parameter(name = "page", description = "当前页", required = false) |
| | | @Parameter(name = "count", description = "每页查询数量", required = false) |
| | | @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true) |
| | | @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true) |
| | | @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = false) |
| | | @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false) |
| | | @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false) |
| | | public PageInfo<CloudRecordItem> openRtpServer( |
| | | @RequestParam String app, |
| | | @RequestParam String stream, |
| | | @RequestParam(required = false) String query, |
| | | @RequestParam(required = false) String app, |
| | | @RequestParam(required = false) String stream, |
| | | @RequestParam int page, |
| | | @RequestParam int count, |
| | | @RequestParam String startTime, |
| | | @RequestParam String endTime, |
| | | @RequestParam(required = false) String startTime, |
| | | @RequestParam(required = false) String endTime, |
| | | @RequestParam(required = false) String mediaServerId |
| | | |
| | | ) { |
| | |
| | | if (mediaServerItems.isEmpty()) { |
| | | throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体"); |
| | | } |
| | | return cloudRecordService.getList(page, count, app, stream, startTime, endTime, mediaServerItems); |
| | | if (query != null && ObjectUtils.isEmpty(query.trim())) { |
| | | query = null; |
| | | } |
| | | if (app != null && ObjectUtils.isEmpty(app.trim())) { |
| | | app = null; |
| | | } |
| | | if (stream != null && ObjectUtils.isEmpty(stream.trim())) { |
| | | stream = null; |
| | | } |
| | | if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) { |
| | | startTime = null; |
| | | } |
| | | if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) { |
| | | endTime = null; |
| | | } |
| | | return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems); |
| | | } |
| | | |
| | | @ResponseBody |
| | |
| | | <template> |
| | | <div id="app" style="width: 100%"> |
| | | <div id="app" style="width: 100%"> |
| | | <div class="page-header"> |
| | | <div class="page-title"> |
| | | <el-page-header v-if="recordDetail" @back="backToList" content="云端录像"></el-page-header> |
| | |
| | | </div> |
| | | |
| | | <div class="page-header-btn"> |
| | | 搜索: |
| | | <el-input @input="search" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字" |
| | | prefix-icon="el-icon-search" v-model="search" clearable></el-input> |
| | | 开始时间: |
| | | <el-date-picker |
| | | v-model="startTime" |
| | | type="datetime" |
| | | placeholder="选择日期时间"> |
| | | </el-date-picker> |
| | | 结束时间: |
| | | <el-date-picker |
| | | v-model="endTime" |
| | | type="datetime" |
| | | placeholder="选择日期时间"> |
| | | </el-date-picker> |
| | | 节点选择: |
| | | <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" :disabled="recordDetail"> |
| | | <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" |
| | | v-model="mediaServerId" placeholder="请选择" :disabled="recordDetail"> |
| | | <el-option |
| | | v-for="item in mediaServerList" |
| | | :key="item.id" |
| | | :label="item.id" |
| | | :value="item.id"> |
| | | v-for="item in mediaServerList" |
| | | :key="item.id" |
| | | :label="item.id" |
| | | :value="item.id"> |
| | | </el-option> |
| | | </el-select> |
| | | <el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" @click="getRecordList()"></el-button> |
| | | <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteRecord()">批量删除</el-button> |
| | | <el-button v-if="!recordDetail" icon="el-icon-refresh-right" circle size="mini" :loading="loading" |
| | | @click="getRecordList()"></el-button> |
| | | </div> |
| | | </div> |
| | | <div v-if="!recordDetail"> |
| | | |
| | | <!--设备列表--> |
| | | <el-table :data="recordList" style="width: 100%" :height="winHeight"> |
| | | <el-table-column prop="app" label="应用名" > |
| | | <el-table-column prop="app" label="应用名"> |
| | | </el-table-column> |
| | | <el-table-column prop="stream" label="流ID" > |
| | | <el-table-column prop="stream" label="流ID" width="380"> |
| | | </el-table-column> |
| | | <el-table-column prop="time" label="时间" > |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="360" fixed="right"> |
| | | <el-table-column label="开始时间"> |
| | | <template slot-scope="scope"> |
| | | <el-button size="medium" icon="el-icon-folder-opened" type="text" @click="showRecordDetail(scope.row)">查看</el-button> |
| | | <!-- <el-button size="mini" icon="el-icon-delete" type="danger" @click="deleteRecord(scope.row)">删除</el-button>--> |
| | | {{formatTimeStamp(scope.row.startTime)}} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="结束时间"> |
| | | <template slot-scope="scope"> |
| | | {{formatTimeStamp(scope.row.endTime)}} |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="时长"> |
| | | <template slot-scope="scope"> |
| | | <el-tag>{{formatTime(scope.row.timeLen)}}</el-tag> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column prop="fileName" label="文件名称"> |
| | | </el-table-column> |
| | | <el-table-column prop="mediaServerId" label="流媒体"> |
| | | </el-table-column> |
| | | <el-table-column label="操作" width="200" fixed="right"> |
| | | <template slot-scope="scope"> |
| | | <el-button size="medium" icon="el-icon-video-play" type="text" @click="showRecordDetail(scope.row)">播放 |
| | | </el-button> |
| | | <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c" |
| | | @click="deleteRecord(scope.row)">删除 |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <el-pagination |
| | | style="float: right" |
| | | @size-change="handleSizeChange" |
| | | @current-change="currentChange" |
| | | :current-page="currentPage" |
| | | :page-size="count" |
| | | :page-sizes="[15, 25, 35, 50]" |
| | | layout="total, sizes, prev, pager, next" |
| | | :total="total"> |
| | | style="float: right" |
| | | @size-change="handleSizeChange" |
| | | @current-change="currentChange" |
| | | :current-page="currentPage" |
| | | :page-size="count" |
| | | :page-sizes="[15, 25, 35, 50]" |
| | | layout="total, sizes, prev, pager, next" |
| | | :total="total"> |
| | | </el-pagination> |
| | | </div> |
| | | |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import uiHeader from '../layout/UiHeader.vue' |
| | | import MediaServer from './service/MediaServer' |
| | | export default { |
| | | name: 'app', |
| | | components: { |
| | | uiHeader |
| | | }, |
| | | data() { |
| | | return { |
| | | mediaServerList: [], // 滅体节点列表 |
| | | mediaServerId: null, // 媒体服务 |
| | | mediaServerPath: null, // 媒体服务地址 |
| | | recordList: [], // 设备列表 |
| | | chooseRecord: null, // 媒体服务 |
| | | import uiHeader from '../layout/UiHeader.vue' |
| | | import MediaServer from './service/MediaServer' |
| | | import moment from 'moment' |
| | | |
| | | updateLooper: 0, //数据刷新轮训标志 |
| | | winHeight: window.innerHeight - 250, |
| | | currentPage:1, |
| | | count:15, |
| | | total:0, |
| | | loading: false, |
| | | mediaServerObj : new MediaServer(), |
| | | recordDetail: false |
| | | export default { |
| | | name: 'app', |
| | | components: { |
| | | uiHeader |
| | | }, |
| | | data() { |
| | | return { |
| | | search: '', |
| | | startTime: '', |
| | | endTime: '', |
| | | mediaServerList: [], // 滅体节点列表 |
| | | mediaServerId: null, // 媒体服务 |
| | | mediaServerPath: null, // 媒体服务地址 |
| | | recordList: [], // 设备列表 |
| | | chooseRecord: null, // 媒体服务 |
| | | |
| | | }; |
| | | }, |
| | | computed: { |
| | | updateLooper: 0, //数据刷新轮训标志 |
| | | winHeight: window.innerHeight - 250, |
| | | currentPage: 1, |
| | | count: 15, |
| | | total: 0, |
| | | loading: false, |
| | | mediaServerObj: new MediaServer(), |
| | | recordDetail: false |
| | | |
| | | }, |
| | | mounted() { |
| | | this.initData(); |
| | | }, |
| | | destroyed() { |
| | | // this.$destroy('videojs'); |
| | | }, |
| | | methods: { |
| | | initData: function() { |
| | | // 获取媒体节点列表 |
| | | this.getMediaServerList(); |
| | | // this.getRecordList(); |
| | | }, |
| | | currentChange: function(val){ |
| | | this.currentPage = val; |
| | | this.getRecordList(); |
| | | }, |
| | | handleSizeChange: function(val){ |
| | | this.count = val; |
| | | this.getRecordList(); |
| | | }, |
| | | getMediaServerList: function (){ |
| | | let that = this; |
| | | that.mediaServerObj.getOnlineMediaServerList((data)=>{ |
| | | that.mediaServerList = data.data; |
| | | if (that.mediaServerList.length > 0) { |
| | | that.mediaServerId = that.mediaServerList[0].id |
| | | that.setMediaServerPath(that.mediaServerId); |
| | | that.getRecordList(); |
| | | } |
| | | }) |
| | | }, |
| | | setMediaServerPath: function (serverId) { |
| | | let that = this; |
| | | let i; |
| | | for (i = 0; i < that.mediaServerList.length; i++) { |
| | | if (serverId === that.mediaServerList[i].id) { |
| | | break; |
| | | } |
| | | }; |
| | | }, |
| | | computed: {}, |
| | | mounted() { |
| | | this.initData(); |
| | | }, |
| | | destroyed() { |
| | | // this.$destroy('videojs'); |
| | | }, |
| | | methods: { |
| | | initData: function () { |
| | | // 获取媒体节点列表 |
| | | this.getMediaServerList(); |
| | | // this.getRecordList(); |
| | | }, |
| | | currentChange: function (val) { |
| | | this.currentPage = val; |
| | | this.getRecordList(); |
| | | }, |
| | | handleSizeChange: function (val) { |
| | | this.count = val; |
| | | this.getRecordList(); |
| | | }, |
| | | getMediaServerList: function () { |
| | | let that = this; |
| | | that.mediaServerObj.getOnlineMediaServerList((data) => { |
| | | that.mediaServerList = data.data; |
| | | if (that.mediaServerList.length > 0) { |
| | | that.mediaServerId = that.mediaServerList[0].id |
| | | that.setMediaServerPath(that.mediaServerId); |
| | | that.getRecordList(); |
| | | } |
| | | let port = that.mediaServerList[i].httpPort; |
| | | if (location.protocol === "https:" && that.mediaServerList[i].httpSSlPort) { |
| | | port = that.mediaServerList[i].httpSSlPort |
| | | }) |
| | | }, |
| | | setMediaServerPath: function (serverId) { |
| | | let that = this; |
| | | let i; |
| | | for (i = 0; i < that.mediaServerList.length; i++) { |
| | | if (serverId === that.mediaServerList[i].id) { |
| | | break; |
| | | } |
| | | that.mediaServerPath = location.protocol + "//" + that.mediaServerList[i].streamIp + ":" + port |
| | | console.log(that.mediaServerPath) |
| | | }, |
| | | getRecordList: function (){ |
| | | let that = this; |
| | | this.$axios({ |
| | | method: 'get', |
| | | url:`/record_proxy/${that.mediaServerId}/api/record/list`, |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | | } |
| | | }).then(function (res) { |
| | | console.log(res) |
| | | if (res.data.code === 0) { |
| | | that.total = res.data.data.total; |
| | | that.recordList = res.data.data.list; |
| | | } |
| | | that.loading = false; |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | that.loading = false; |
| | | }); |
| | | }, |
| | | backToList(){ |
| | | this.recordDetail= false; |
| | | }, |
| | | chooseMediaChange(val){ |
| | | console.log(val) |
| | | this.total = 0; |
| | | this.recordList = []; |
| | | this.setMediaServerPath(val); |
| | | this.getRecordList(); |
| | | }, |
| | | showRecordDetail(row){ |
| | | this.recordDetail = true; |
| | | this.chooseRecord = row; |
| | | // 查询是否存在录像 |
| | | // this.$axios({ |
| | | // method: 'delete', |
| | | // url:`/record_proxy/api/record/delete`, |
| | | // params: { |
| | | // page: this.currentPage, |
| | | // count: this.count |
| | | // } |
| | | // }).then((res) => { |
| | | // console.log(res) |
| | | // this.total = res.data.data.total; |
| | | // this.recordList = res.data.data.list; |
| | | // }).catch(function (error) { |
| | | // console.log(error); |
| | | // }); |
| | | this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`) |
| | | }, |
| | | deleteRecord(){ |
| | | // TODO |
| | | let that = this; |
| | | this.$axios({ |
| | | method: 'delete', |
| | | url:`/record_proxy/api/record/delete`, |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | | } |
| | | }).then(function (res) { |
| | | console.log(res) |
| | | if (res.data.code === 0) { |
| | | that.total = res.data.data.total; |
| | | that.recordList = res.data.data.list; |
| | | } |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | } |
| | | let port = that.mediaServerList[i].httpPort; |
| | | if (location.protocol === "https:" && that.mediaServerList[i].httpSSlPort) { |
| | | port = that.mediaServerList[i].httpSSlPort |
| | | } |
| | | that.mediaServerPath = location.protocol + "//" + that.mediaServerList[i].streamIp + ":" + port |
| | | console.log(that.mediaServerPath) |
| | | }, |
| | | getRecordList: function () { |
| | | this.$axios({ |
| | | method: 'get', |
| | | url: `/api/cloud/record/list`, |
| | | params: { |
| | | app: '', |
| | | stream: '', |
| | | query: this.search, |
| | | startTime: this.startTime, |
| | | endTime: this.endTime, |
| | | mediaServerId: this.mediaServerId, |
| | | page: this.currentPage, |
| | | count: this.count |
| | | } |
| | | }).then((res) => { |
| | | console.log(res) |
| | | if (res.data.code === 0) { |
| | | this.total = res.data.data.total; |
| | | this.recordList = res.data.data.list; |
| | | } |
| | | this.loading = false; |
| | | }).catch((error) => { |
| | | console.log(error); |
| | | this.loading = false; |
| | | }); |
| | | }, |
| | | backToList() { |
| | | this.recordDetail = false; |
| | | }, |
| | | chooseMediaChange(val) { |
| | | console.log(val) |
| | | this.total = 0; |
| | | this.recordList = []; |
| | | this.setMediaServerPath(val); |
| | | this.getRecordList(); |
| | | }, |
| | | showRecordDetail(row) { |
| | | this.recordDetail = true; |
| | | this.chooseRecord = row; |
| | | // 查询是否存在录像 |
| | | // this.$axios({ |
| | | // method: 'delete', |
| | | // url:`/record_proxy/api/record/delete`, |
| | | // params: { |
| | | // page: this.currentPage, |
| | | // count: this.count |
| | | // } |
| | | // }).then((res) => { |
| | | // console.log(res) |
| | | // this.total = res.data.data.total; |
| | | // this.recordList = res.data.data.list; |
| | | // }).catch(function (error) { |
| | | // console.log(error); |
| | | // }); |
| | | this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`) |
| | | }, |
| | | deleteRecord() { |
| | | // TODO |
| | | let that = this; |
| | | this.$axios({ |
| | | method: 'delete', |
| | | url: `/record_proxy/api/record/delete`, |
| | | params: { |
| | | page: that.currentPage, |
| | | count: that.count |
| | | } |
| | | }).then(function (res) { |
| | | console.log(res) |
| | | if (res.data.code === 0) { |
| | | that.total = res.data.data.total; |
| | | that.recordList = res.data.data.list; |
| | | } |
| | | }).catch(function (error) { |
| | | console.log(error); |
| | | }); |
| | | }, |
| | | formatTime(time) { |
| | | const h = parseInt(time / 3600) |
| | | const minute = parseInt(time / 60 % 60) |
| | | const second = Math.ceil(time % 60) |
| | | |
| | | return (h > 0 ? h + `小时` : '') + (minute > 0 ? minute + '分' : '') + second + '秒' |
| | | }, |
| | | formatTimeStamp(time) { |
| | | return moment.unix(time).format('yyyy-MM-DD HH:mm:ss') |
| | | } |
| | | |
| | | } |
| | | }; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | |
| | | }, |
| | | data() { |
| | | return { |
| | | title: "四倍速下载中...", |
| | | title: "下载中...", |
| | | deviceId: "", |
| | | channelId: "", |
| | | app: "", |