control.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. <template>
  2. <div id="app">
  3. <el-container>
  4. <el-header>
  5. <uiHeader></uiHeader>
  6. </el-header>
  7. <el-main>
  8. <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;">
  9. <span style="font-size: 1rem; font-weight: bold;">控制台</span>
  10. <div style="position: absolute; right: 17rem; top: 0.3rem;">
  11. 节点选择: <el-select size="mini" @change="chooseMediaChange" style="width: 18rem; margin-right: 8rem;" v-model="mediaServerChoose" placeholder="请选择" default-first-option>
  12. <el-option
  13. v-for="item in mediaServerList"
  14. :key="item.id"
  15. :label="item.id + '( ' + item.streamIp + ' )'"
  16. :value="item.id">
  17. </el-option>
  18. </el-select>
  19. <span >{{loadCount}}</span>
  20. </div>
  21. <div style="position: absolute; right: 1rem; top: 0.3rem;">
  22. <el-popover placement="bottom" width="750" height="300" trigger="click">
  23. <div style="height: 600px;overflow:auto;">
  24. <table class="table-c" cellspacing="0">
  25. <tr v-for="(value, key, index) in serverConfig">
  26. <td style="width: 18rem; text-align: right;">{{ key }}</td>
  27. <td style="width: 33rem; text-align:left">{{ value }}</td>
  28. </tr>
  29. </table>
  30. </div>
  31. <el-button type="primary" slot="reference" size="mini" @click="getServerConfig()">媒体服务器配置</el-button>
  32. </el-popover>
  33. <el-popover placement="bottom" width="750" height="300" trigger="click">
  34. <div style="height: 600px;overflow:auto;">
  35. <div v-for="(value, key, index) in wvpServerConfig">
  36. {{ key }}:
  37. <table v-if="key != 'server.port'" class="table-c" cellspacing="0">
  38. <tr v-for="(subValue, subKey, subIndex) in value">
  39. <td style="width: 18rem; text-align: right;">{{ subKey }}</td>
  40. <td style="width: 33rem; text-align:left">{{ subValue }}</td>
  41. </tr>
  42. </table>
  43. <span v-if="key == 'server.port'">{{ value }}</span>
  44. </div>
  45. <div style="margin-top: 1rem">
  46. 版本信息:
  47. <table class="table-c" cellspacing="0">
  48. <tr v-for="(value, key, index) in wvpServerVersion">
  49. <td style="width: 18rem; text-align: right;">{{ key }}</td>
  50. <td style="width: 33rem; text-align:left">{{ value }}</td>
  51. </tr>
  52. </table>
  53. </div>
  54. </div>
  55. <el-button type="primary" slot="reference" size="mini" @click="getWVPServerConfig()">信令服务器配置</el-button>
  56. </el-popover>
  57. <el-button style="margin-left: 1rem;" type="danger" size="mini" @click="reStartServer()">重启媒体服务器</el-button>
  58. </div>
  59. </div>
  60. <el-row :gutter="30">
  61. <el-col :span="12">
  62. <div class="control-table" id="ThreadsLoad">table1</div>
  63. </el-col>
  64. <el-col :span="12">
  65. <div class="control-table" id="WorkThreadsLoad">table2</div>
  66. </el-col>
  67. </el-row>
  68. <el-table :data="allSessionData" style="margin-top: 1rem;">
  69. <el-table-column prop="peer_ip" label="远端"></el-table-column>
  70. <el-table-column prop="local_ip" label="本地"></el-table-column>
  71. <el-table-column prop="typeid" label="类型"></el-table-column>
  72. <el-table-column align="right">
  73. <template slot="header" slot-scope="scope">
  74. <el-button icon="el-icon-refresh-right" circle @click="getAllSession()"></el-button>
  75. </template>
  76. <template slot-scope="scope">
  77. <el-button @click.native.prevent="deleteRow(scope.$index, allSessionData)" type="text" size="small">移除</el-button>
  78. </template>
  79. </el-table-column>
  80. </el-table>
  81. </el-main>
  82. <!-- <el-footer style="position: absolute; bottom: 0; width: 100%;">ZLMediaKit-VUE_UI v1</el-footer> -->
  83. </el-container>
  84. </div>
  85. </template>
  86. <script>
  87. import uiHeader from './UiHeader.vue'
  88. import MediaServer from './service/MediaServer'
  89. import echarts from 'echarts';
  90. export default {
  91. name: 'app',
  92. components: {
  93. echarts,
  94. uiHeader
  95. },
  96. data() {
  97. return {
  98. tableOption: {
  99. // legend: {},
  100. xAxis: {},
  101. yAxis: {},
  102. label: {},
  103. tooltip: {},
  104. dataZoom: [],
  105. series: []
  106. },
  107. table1Option: {
  108. // legend: {},
  109. xAxis: {},
  110. yAxis: {},
  111. label: {},
  112. tooltip: {},
  113. series: []
  114. },
  115. mChart: null,
  116. mChart1: null,
  117. charZoomStart: 0,
  118. charZoomEnd: 100,
  119. chartInterval: 0, //更新图表统计图定时任务标识
  120. allSessionData: [],
  121. visible: false,
  122. wvpVisible: false,
  123. serverConfig: {},
  124. wvpServerConfig: {},
  125. wvpServerVersion: {},
  126. mediaServer : new MediaServer(),
  127. mediaServerChoose : null,
  128. loadCount : 0,
  129. mediaServerList : []
  130. };
  131. },
  132. mounted() {
  133. this.initTable();
  134. this.chartInterval = setInterval(this.updateData, 3000);
  135. this.mediaServer.getOnlineMediaServerList((data)=>{
  136. this.mediaServerList = data.data;
  137. if (this.mediaServerList && this.mediaServerList.length > 0) {
  138. this.mediaServerChoose = this.mediaServerList[0].id
  139. this.loadCount = this.mediaServerList[0].count;
  140. this.updateData();
  141. }
  142. })
  143. },
  144. destroyed() {
  145. clearInterval(this.chartInterval); //释放定时任务
  146. },
  147. methods: {
  148. chooseMediaChange: function (val) {
  149. this.loadCount = 0
  150. this.initTable()
  151. this.updateData();
  152. },
  153. updateData: function () {
  154. this.getThreadsLoad();
  155. this.getLoadCount();
  156. this.getAllSession();
  157. },
  158. /**
  159. * 获取线程状态
  160. */
  161. getThreadsLoad: function () {
  162. let that = this;
  163. if (that.mediaServerChoose != null) {
  164. this.$axios({
  165. method: 'get',
  166. url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
  167. }).then(function (res) {
  168. if (res.data.code == 0) {
  169. that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  170. hour12: false
  171. }));
  172. that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  173. hour12: false
  174. }));
  175. for (var i = 0; i < res.data.data.length; i++) {
  176. if (that.tableOption.series[i] === undefined) {
  177. let data = {
  178. data: [],
  179. type: 'line'
  180. };
  181. let data1 = {
  182. data: [],
  183. type: 'line'
  184. };
  185. data.data.push(res.data.data[i].delay);
  186. data1.data.push(res.data.data[i].load);
  187. that.tableOption.series.push(data);
  188. that.table1Option.series.push(data1);
  189. } else {
  190. that.tableOption.series[i].data.push(res.data.data[i].delay);
  191. that.table1Option.series[i].data.push(res.data.data[i].load);
  192. }
  193. }
  194. that.tableOption.dataZoom[0].start = that.charZoomStart;
  195. that.tableOption.dataZoom[0].end = that.charZoomEnd;
  196. that.table1Option.dataZoom[0].start = that.charZoomStart;
  197. that.table1Option.dataZoom[0].end = that.charZoomEnd;
  198. //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
  199. that.myChart.setOption(that.tableOption, true);
  200. // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
  201. that.myChart1.setOption(that.table1Option, true);
  202. }
  203. });
  204. }
  205. },
  206. getLoadCount: function (){
  207. let that = this;
  208. if (that.mediaServerChoose != null) {
  209. that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
  210. if (data.code == 0) {
  211. that.loadCount = data.data.count
  212. }
  213. })
  214. }
  215. },
  216. initTable: function () {
  217. let that = this;
  218. this.tableOption.xAxis = {
  219. type: 'category',
  220. data: [], // x轴数据
  221. name: '时间', // x轴名称
  222. // x轴名称样式
  223. nameTextStyle: {
  224. fontWeight: 300,
  225. fontSize: 15
  226. }
  227. };
  228. this.tableOption.yAxis = {
  229. type: 'value',
  230. name: '延迟率', // y轴名称
  231. boundaryGap: [0, '100%'],
  232. max: 100,
  233. axisLabel: {
  234. show: true,
  235. interval: 'auto',
  236. formatter: '{value} %'
  237. },
  238. // y轴名称样式
  239. nameTextStyle: {
  240. fontWeight: 300,
  241. fontSize: 15
  242. }
  243. };
  244. this.tableOption.dataZoom = [{
  245. show: true,
  246. start: this.charZoomStart,
  247. end: this.charZoomEnd
  248. }];
  249. this.myChart = echarts.init(document.getElementById('ThreadsLoad'));
  250. this.myChart.setOption(this.tableOption);
  251. this.myChart.on('dataZoom', function (event) {
  252. if (event.batch) {
  253. that.charZoomStart = event.batch[0].start;
  254. that.charZoomEnd = event.batch[0].end;
  255. } else {
  256. that.charZoomStart = event.start;
  257. that.charZoomEnd = event.end;
  258. }
  259. });
  260. this.table1Option.xAxis = {
  261. type: 'category',
  262. data: [], // x轴数据
  263. name: '时间', // x轴名称
  264. // x轴名称样式
  265. nameTextStyle: {
  266. fontWeight: 300,
  267. fontSize: 15
  268. }
  269. };
  270. this.table1Option.yAxis = {
  271. type: 'value',
  272. name: '负载率', // y轴名称
  273. boundaryGap: [0, '100%'],
  274. max: 100,
  275. axisLabel: {
  276. show: true,
  277. interval: 'auto',
  278. formatter: '{value} %'
  279. },
  280. // y轴名称样式
  281. nameTextStyle: {
  282. fontWeight: 300,
  283. fontSize: 15
  284. }
  285. };
  286. this.table1Option.dataZoom = [{
  287. show: true,
  288. start: this.charZoomStart,
  289. end: this.charZoomEnd
  290. }];
  291. this.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
  292. this.myChart1.setOption(this.table1Option);
  293. this.myChart1.on('dataZoom', function (event) {
  294. if (event.batch) {
  295. that.charZoomStart = event.batch[0].start;
  296. that.charZoomEnd = event.batch[0].end;
  297. } else {
  298. that.charZoomStart = event.start;
  299. that.charZoomEnd = event.end;
  300. }
  301. });
  302. },
  303. getAllSession: function () {
  304. let that = this;
  305. that.allSessionData = [];
  306. this.$axios({
  307. method: 'get',
  308. url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
  309. }).then(function (res) {
  310. res.data.data.forEach(item => {
  311. let data = {
  312. peer_ip: item.peer_ip,
  313. local_ip: item.local_ip,
  314. typeid: item.typeid,
  315. id: item.id
  316. };
  317. that.allSessionData.push(data);
  318. });
  319. });
  320. },
  321. getServerConfig: function () {
  322. let that = this;
  323. this.$axios({
  324. method: 'get',
  325. url: '/zlm/' + that.mediaServerChoose +'/index/api/getServerConfig'
  326. }).then(function (res) {
  327. that.serverConfig = res.data.data[0];
  328. that.visible = true;
  329. });
  330. },
  331. getWVPServerConfig: function () {
  332. let that = this;
  333. this.$axios({
  334. method: 'get',
  335. url: '/api/server/config'
  336. }).then(function (res) {
  337. console.log(res)
  338. that.wvpServerConfig = res.data.data;
  339. that.wvpVisible = true;
  340. });
  341. this.$axios({
  342. method: 'get',
  343. url: '/api/server/version'
  344. }).then(function (res) {
  345. console.log(res)
  346. that.wvpServerVersion = res.data.data;
  347. that.wvpVisible = true;
  348. });
  349. },
  350. reStartServer: function () {
  351. let that = this;
  352. this.$confirm('此操作将重启媒体服务器, 是否继续?', '提示', {
  353. confirmButtonText: '确定',
  354. cancelButtonText: '取消',
  355. type: 'warning'
  356. }).then(() => {
  357. let that = this;
  358. this.$axios({
  359. method: 'get',
  360. url: '/zlm/index/api/restartServer'
  361. }).then(function (res) {
  362. that.getAllSession();
  363. if (res.data.code == 0) {
  364. that.$message({
  365. type: 'success',
  366. message: '操作完成'
  367. });
  368. }
  369. });
  370. });
  371. },
  372. deleteRow: function (index, tabledata) {
  373. let that = this;
  374. this.$confirm('此操作将断开该通信链路, 是否继续?', '提示', {
  375. confirmButtonText: '确定',
  376. cancelButtonText: '取消',
  377. type: 'warning'
  378. })
  379. .then(() => {
  380. that.deleteSession(tabledata[index].id);
  381. })
  382. .catch(() => {
  383. console.log('id:' + JSON.stringify(tabledata[index]));
  384. this.$message({
  385. type: 'info',
  386. message: '已取消删除'
  387. });
  388. });
  389. console.log(JSON.stringify(tabledata[index]));
  390. },
  391. deleteSession: function (id) {
  392. let that = this;
  393. this.$axios({
  394. method: 'get',
  395. url: '/zlm/index/api/kick_session&id=' + id
  396. }).then(function (res) {
  397. that.getAllSession();
  398. that.$message({
  399. type: 'success',
  400. message: '删除成功!'
  401. });
  402. });
  403. }
  404. }
  405. };
  406. </script>
  407. <style>
  408. #app {
  409. height: 100%;
  410. }
  411. .control-table {
  412. background-color: #ffffff;
  413. height: 25rem;
  414. }
  415. .table-c {
  416. border-right: 1px solid #dcdcdc;
  417. border-bottom: 1px solid #dcdcdc;
  418. }
  419. .table-c td {
  420. border-left: 1px solid #dcdcdc;
  421. border-top: 1px solid #dcdcdc;
  422. padding: 0.2rem;
  423. }
  424. .el-table {
  425. width: 99.9% !important;
  426. }
  427. </style>