StreamPushList.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <template>
  2. <div id="streamPushList" style="width: 100%">
  3. <div v-if="!streamPush">
  4. <div class="page-header">
  5. <div class="page-title">推流列表</div>
  6. <div class="page-header-btn">
  7. 搜索:
  8. <el-input @input="getPushList" style="margin-right: 1rem; width: auto;" size="mini" placeholder="关键字"
  9. prefix-icon="el-icon-search" v-model="searchSrt" clearable></el-input>
  10. 流媒体:
  11. <el-select size="mini" @change="getPushList" style="margin-right: 1rem;" v-model="mediaServerId"
  12. placeholder="请选择" default-first-option>
  13. <el-option label="全部" value=""></el-option>
  14. <el-option
  15. v-for="item in mediaServerList"
  16. :key="item.id"
  17. :label="item.id"
  18. :value="item.id">
  19. </el-option>
  20. </el-select>
  21. 推流状态:
  22. <el-select size="mini" style="margin-right: 1rem;" @change="getPushList" v-model="pushing" placeholder="请选择"
  23. default-first-option>
  24. <el-option label="全部" value=""></el-option>
  25. <el-option label="推流进行中" value="true"></el-option>
  26. <el-option label="推流未进行" value="false"></el-option>
  27. </el-select>
  28. <el-button icon="el-icon-upload2" size="mini" style="margin-right: 1rem;" type="primary" @click="importChannel">
  29. 通道导入
  30. </el-button>
  31. <el-button icon="el-icon-download" size="mini" style="margin-right: 1rem;" type="primary">
  32. <a style="color: #FFFFFF; text-align: center; text-decoration: none" href="/static/file/推流通道导入.zip"
  33. download='推流通道导入.zip'>下载模板</a>
  34. </el-button>
  35. <el-button icon="el-icon-delete" size="mini" style="margin-right: 1rem;"
  36. :disabled="multipleSelection.length === 0" type="danger" @click="batchDel">批量移除
  37. </el-button>
  38. <el-button icon="el-icon-plus" size="mini" style="margin-right: 1rem;" type="primary" @click="addStream">添加通道
  39. </el-button>
  40. <el-button icon="el-icon-refresh-right" circle size="mini" @click="refresh()"></el-button>
  41. </div>
  42. </div>
  43. <el-table ref="pushListTable" :data="pushList" style="width: 100%" :height="winHeight" :loading="loading"
  44. @selection-change="handleSelectionChange" :row-key="(row)=> row.app + row.stream">
  45. <el-table-column type="selection" :reserve-selection="true" min-width="55">
  46. </el-table-column>
  47. <el-table-column prop="gbName" label="名称" min-width="200">
  48. </el-table-column>
  49. <el-table-column prop="app" label="应用名" min-width="200">
  50. </el-table-column>
  51. <el-table-column prop="stream" label="流ID" min-width="200">
  52. </el-table-column>
  53. <el-table-column label="推流状态" min-width="100">
  54. <template slot-scope="scope">
  55. <el-tag size="medium" v-if="scope.row.pushIng">推流中</el-tag>
  56. <el-tag size="medium" type="info" v-if="!scope.row.pushIng">已停止</el-tag>
  57. </template>
  58. </el-table-column>
  59. <el-table-column prop="gbDeviceId" label="国标编码" min-width="200" >
  60. </el-table-column>
  61. <el-table-column prop="mediaServerId" label="流媒体" min-width="200" >
  62. </el-table-column>
  63. <el-table-column label="开始时间" min-width="200">
  64. <template slot-scope="scope">
  65. <el-button-group>
  66. {{ scope.row.pushTime == null? "-":scope.row.pushTime }}
  67. </el-button-group>
  68. </template>
  69. </el-table-column>
  70. <el-table-column label="操作" min-width="360" fixed="right">
  71. <template slot-scope="scope">
  72. <el-button size="medium" icon="el-icon-video-play"@click="playPush(scope.row)" type="text">播放
  73. </el-button>
  74. <el-divider direction="vertical"></el-divider>
  75. <el-button size="medium" icon="el-icon-delete" type="text" @click="deletePush(scope.row.id)" style="color: #f56c6c" >删除</el-button>
  76. <el-divider direction="vertical"></el-divider>
  77. <el-button size="medium" icon="el-icon-position" type="text" @click="edit(scope.row)">
  78. 编辑
  79. </el-button>
  80. <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像
  81. </el-button>
  82. </template>
  83. </el-table-column>
  84. </el-table>
  85. <el-pagination
  86. style="float: right"
  87. @size-change="handleSizeChange"
  88. @current-change="currentChange"
  89. :current-page="currentPage"
  90. :page-size="count"
  91. :page-sizes="[15, 25, 35, 50]"
  92. layout="total, sizes, prev, pager, next"
  93. :total="total">
  94. </el-pagination>
  95. </div>
  96. <devicePlayer ref="devicePlayer"></devicePlayer>
  97. <addStreamTOGB ref="addStreamTOGB"></addStreamTOGB>
  98. <importChannel ref="importChannel"></importChannel>
  99. <stream-push-edit v-if="streamPush" :streamPush="streamPush" :closeEdit="closeEdit"></stream-push-edit>
  100. </div>
  101. </template>
  102. <script>
  103. import devicePlayer from './dialog/devicePlayer.vue'
  104. import addStreamTOGB from './dialog/pushStreamEdit.vue'
  105. import uiHeader from '../layout/UiHeader.vue'
  106. import importChannel from './dialog/importChannel.vue'
  107. import MediaServer from './service/MediaServer'
  108. import StreamPushEdit from "./StreamPushEdit";
  109. import ChannelEdit from "./ChannelEdit.vue";
  110. export default {
  111. name: 'streamPushList',
  112. components: {
  113. ChannelEdit,
  114. StreamPushEdit,
  115. devicePlayer,
  116. addStreamTOGB,
  117. uiHeader,
  118. importChannel,
  119. },
  120. data() {
  121. return {
  122. pushList: [], //设备列表
  123. currentPusher: {}, //当前操作设备对象
  124. updateLooper: 0, //数据刷新轮训标志
  125. currentDeviceChannelsLenth: 0,
  126. winHeight: window.innerHeight - 250,
  127. mediaServerObj: new MediaServer(),
  128. currentPage: 1,
  129. count: 15,
  130. total: 0,
  131. searchSrt: "",
  132. pushing: "",
  133. mediaServerId: "",
  134. mediaServerList: [],
  135. multipleSelection: [],
  136. loading: false,
  137. streamPush: null,
  138. };
  139. },
  140. computed: {},
  141. mounted() {
  142. this.initData();
  143. this.updateLooper = setInterval(this.getPushList, 2000);
  144. },
  145. destroyed() {
  146. clearTimeout(this.updateLooper);
  147. },
  148. methods: {
  149. initData: function () {
  150. this.loading = true;
  151. this.mediaServerObj.getOnlineMediaServerList((data) => {
  152. this.mediaServerList = data.data;
  153. })
  154. this.getPushList();
  155. },
  156. currentChange: function (val) {
  157. this.currentPage = val;
  158. this.getPushList();
  159. },
  160. handleSizeChange: function (val) {
  161. this.count = val;
  162. this.getPushList();
  163. },
  164. getPushList: function () {
  165. let that = this;
  166. this.$axios({
  167. method: 'get',
  168. url: `/api/push/list`,
  169. params: {
  170. page: that.currentPage,
  171. count: that.count,
  172. query: that.searchSrt,
  173. pushing: that.pushing,
  174. mediaServerId: that.mediaServerId,
  175. }
  176. }).then(function (res) {
  177. if (res.data.code === 0) {
  178. that.total = res.data.data.total;
  179. that.pushList = res.data.data.list;
  180. }
  181. }).catch(function (error) {
  182. console.error(error);
  183. }).finally(()=>{
  184. this.loading = false;
  185. })
  186. },
  187. playPush: function (row) {
  188. let that = this;
  189. this.getListLoading = true;
  190. this.$axios({
  191. method: 'get',
  192. url: '/api/push/start',
  193. params: {
  194. id: row.id
  195. }
  196. }).then(function (res) {
  197. that.getListLoading = false;
  198. if (res.data.code === 0 ) {
  199. that.$refs.devicePlayer.openDialog("streamPlay", null, null, {
  200. streamInfo: res.data.data,
  201. hasAudio: true
  202. });
  203. }else {
  204. that.$message.error(res.data.msg);
  205. }
  206. }).catch(function (error) {
  207. console.error(error);
  208. that.getListLoading = false;
  209. });
  210. },
  211. deletePush: function (id) {
  212. this.$confirm(`确定删除通道?`, '提示', {
  213. confirmButtonText: '确定',
  214. cancelButtonText: '取消',
  215. type: 'warning'
  216. }).then(() => {
  217. this.loading = true;
  218. this.$axios({
  219. method: "post",
  220. url: "/api/push/remove",
  221. params: {
  222. id: id,
  223. }
  224. }).then((res) => {
  225. if (res.data.code === 0) {
  226. this.initData()
  227. }
  228. }).catch(function (error) {
  229. console.error(error);
  230. });
  231. }).catch(() => {
  232. });
  233. },
  234. edit: function (row) {
  235. this.streamPush = row
  236. },
  237. // 结束编辑
  238. closeEdit: function (){
  239. this.streamPush = null
  240. this.getPushList()
  241. },
  242. removeFromGB: function (row) {
  243. let that = this;
  244. that.$axios({
  245. method: "delete",
  246. url: "/api/push/remove_form_gb",
  247. data: row
  248. }).then((res) => {
  249. if (res.data.code === 0) {
  250. that.initData()
  251. }
  252. }).catch(function (error) {
  253. console.error(error);
  254. });
  255. },
  256. queryCloudRecords: function (row) {
  257. this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
  258. },
  259. importChannel: function () {
  260. this.$refs.importChannel.openDialog(() => {
  261. })
  262. },
  263. addStream: function (){
  264. // this.$refs.addStreamTOGB.openDialog(null, this.initData);
  265. this.streamPush = {}
  266. },
  267. batchDel: function () {
  268. this.$confirm(`确定删除选中的${this.multipleSelection.length}个通道?`, '提示', {
  269. confirmButtonText: '确定',
  270. cancelButtonText: '取消',
  271. type: 'warning'
  272. }).then(() => {
  273. let ids = []
  274. for (let i = 0; i < this.multipleSelection.length; i++) {
  275. ids.push(this.multipleSelection[i].id)
  276. }
  277. let that = this;
  278. that.$axios({
  279. method: "delete",
  280. url: "/api/push/batchRemove",
  281. data: {
  282. ids: ids
  283. }
  284. }).then((res) => {
  285. this.initData();
  286. this.$refs.pushListTable.clearSelection();
  287. }).catch(function (error) {
  288. console.error(error);
  289. });
  290. }).catch(() => {
  291. });
  292. },
  293. handleSelectionChange: function (val) {
  294. this.multipleSelection = val;
  295. },
  296. refresh: function () {
  297. this.initData();
  298. },
  299. }
  300. };
  301. </script>
  302. <style>
  303. .videoList {
  304. display: flex;
  305. flex-wrap: wrap;
  306. align-content: flex-start;
  307. }
  308. .video-item {
  309. position: relative;
  310. width: 15rem;
  311. height: 10rem;
  312. margin-right: 1rem;
  313. background-color: #000000;
  314. }
  315. .video-item-img {
  316. position: absolute;
  317. top: 0;
  318. bottom: 0;
  319. left: 0;
  320. right: 0;
  321. margin: auto;
  322. width: 100%;
  323. height: 100%;
  324. }
  325. .video-item-img:after {
  326. content: "";
  327. display: inline-block;
  328. position: absolute;
  329. z-index: 2;
  330. top: 0;
  331. bottom: 0;
  332. left: 0;
  333. right: 0;
  334. margin: auto;
  335. width: 3rem;
  336. height: 3rem;
  337. background-image: url("../assets/loading.png");
  338. background-size: cover;
  339. background-color: #000000;
  340. }
  341. .video-item-title {
  342. position: absolute;
  343. bottom: 0;
  344. color: #000000;
  345. background-color: #ffffff;
  346. line-height: 1.5rem;
  347. padding: 0.3rem;
  348. width: 14.4rem;
  349. }
  350. </style>