control.vue 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584
  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="900" height="300" trigger="click">
  23. <div style="height: 600px; overflow:auto; padding: 20px">
  24. <el-descriptions v-for="(value, key, index) in serverConfig" :key="key" border :column="1" style="margin-bottom: 1rem">
  25. <template slot="title">
  26. {{key}}
  27. </template>
  28. <el-descriptions-item v-for="(value1, key1, index1) in serverConfig[key]" :key="key1">
  29. <template slot="label" >
  30. {{ getMediaKeyNameFromKey(key1) }}
  31. </template>
  32. {{ value1 }}
  33. </el-descriptions-item>
  34. </el-descriptions>
  35. </div>
  36. <el-button type="primary" slot="reference" size="mini" @click="getServerConfig()">媒体服务器配置</el-button>
  37. </el-popover>
  38. <el-popover placement="bottom" width="900" height="300" trigger="click">
  39. <div style="height: 600px;overflow:auto; padding: 20px">
  40. <el-descriptions title="国标配置" border :column="1">
  41. <template slot="extra">
  42. <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerConfig.sip)|| ''" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
  43. </template>
  44. <el-descriptions-item v-for="(value, key, index) in wvpServerConfig.sip">
  45. <template slot="label">
  46. {{ getNameFromKey(key) }}
  47. </template>
  48. {{ value }}
  49. </el-descriptions-item>
  50. </el-descriptions>
  51. <div style="margin-top: 1rem">
  52. <el-descriptions title="基础配置" border :column="1">
  53. <template slot="extra">
  54. <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerConfig.base)|| ''" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
  55. </template>
  56. <el-descriptions-item v-for="(value, key, index) in wvpServerConfig.base" :key="key">
  57. <template slot="label" >
  58. {{ getNameFromKey(key) }}
  59. </template>
  60. <div v-if="key === 'interfaceAuthenticationExcludes'">
  61. <el-dropdown>
  62. <span class="el-dropdown-link">
  63. 查看<i class="el-icon-arrow-down el-icon--right"></i>
  64. </span>
  65. <el-dropdown-menu slot="dropdown">
  66. <el-dropdown-item v-for="(value, key, index) in wvpServerConfig.base.interfaceAuthenticationExcludes" :key="key">{{value}}</el-dropdown-item>
  67. </el-dropdown-menu>
  68. </el-dropdown>
  69. </div>
  70. <div v-if="key !== 'interfaceAuthenticationExcludes'">
  71. <div v-if="value === true">
  72. 已启用
  73. </div>
  74. <div v-if="value === false">
  75. 未启用
  76. </div>
  77. <div v-if="value !== true && value !== false">
  78. {{ value }}
  79. </div>
  80. </div>
  81. </el-descriptions-item>
  82. </el-descriptions>
  83. </div>
  84. <div style="margin-top: 1rem">
  85. <el-descriptions title="版本信息" border :column="1">
  86. <template slot="extra">
  87. <el-button style="float: right;" type="primary" size="mini" icon="el-icon-document-copy" title="点击拷贝" v-clipboard="JSON.stringify(wvpServerVersion) || ''" @success="$message({type:'success', message:'成功拷贝到粘贴板'})"></el-button>
  88. </template>
  89. <el-descriptions-item v-for="(value, key, index) in wvpServerVersion" :key="key">
  90. <template slot="label">
  91. {{ getNameFromKey(key) }}
  92. </template>
  93. {{ value }}
  94. </el-descriptions-item>
  95. </el-descriptions>
  96. </div>
  97. </div>
  98. <el-button type="primary" slot="reference" size="mini" @click="getWVPServerConfig()">信令服务器配置</el-button>
  99. </el-popover>
  100. <el-button style="margin-left: 1rem;" type="danger" size="mini" @click="reStartServer()">重启媒体服务器</el-button>
  101. </div>
  102. </div>
  103. <el-row :gutter="30">
  104. <el-col :span="12">
  105. <div class="control-table" id="ThreadsLoad">table1</div>
  106. </el-col>
  107. <el-col :span="12">
  108. <div class="control-table" id="WorkThreadsLoad">table2</div>
  109. </el-col>
  110. </el-row>
  111. <el-table :data="allSessionData" style="margin-top: 1rem;">
  112. <el-table-column prop="peer_ip" label="远端"></el-table-column>
  113. <el-table-column prop="local_ip" label="本地"></el-table-column>
  114. <el-table-column prop="typeid" label="类型"></el-table-column>
  115. <el-table-column align="right">
  116. <template slot="header" slot-scope="scope">
  117. <el-button icon="el-icon-refresh-right" circle @click="getAllSession()"></el-button>
  118. </template>
  119. <template slot-scope="scope">
  120. <el-button @click.native.prevent="deleteRow(scope.$index, allSessionData)" type="text" size="small">移除</el-button>
  121. </template>
  122. </el-table-column>
  123. </el-table>
  124. </el-main>
  125. <!-- <el-footer style="position: absolute; bottom: 0; width: 100%;">ZLMediaKit-VUE_UI v1</el-footer> -->
  126. </el-container>
  127. </div>
  128. </template>
  129. <script>
  130. import uiHeader from './UiHeader.vue'
  131. import MediaServer from './service/MediaServer'
  132. import echarts from 'echarts';
  133. export default {
  134. name: 'app',
  135. components: {
  136. echarts,
  137. uiHeader
  138. },
  139. data() {
  140. return {
  141. tableOption: {
  142. // legend: {},
  143. xAxis: {},
  144. yAxis: {},
  145. label: {},
  146. tooltip: {},
  147. dataZoom: [],
  148. series: []
  149. },
  150. table1Option: {
  151. // legend: {},
  152. xAxis: {},
  153. yAxis: {},
  154. label: {},
  155. tooltip: {},
  156. series: []
  157. },
  158. mChart: null,
  159. mChart1: null,
  160. charZoomStart: 0,
  161. charZoomEnd: 100,
  162. chartInterval: 0, //更新图表统计图定时任务标识
  163. allSessionData: [],
  164. visible: false,
  165. wvpVisible: false,
  166. serverConfig: {},
  167. wvpServerConfig: {},
  168. wvpServerVersion: {},
  169. mediaServer : new MediaServer(),
  170. mediaServerChoose : null,
  171. loadCount : 0,
  172. mediaServerList : []
  173. };
  174. },
  175. mounted() {
  176. this.initTable();
  177. this.chartInterval = setInterval(this.updateData, 3000);
  178. this.mediaServer.getOnlineMediaServerList((data)=>{
  179. this.mediaServerList = data.data;
  180. if (this.mediaServerList && this.mediaServerList.length > 0) {
  181. this.mediaServerChoose = this.mediaServerList[0].id
  182. this.loadCount = this.mediaServerList[0].count;
  183. this.updateData();
  184. }
  185. })
  186. },
  187. destroyed() {
  188. clearInterval(this.chartInterval); //释放定时任务
  189. },
  190. methods: {
  191. chooseMediaChange: function (val) {
  192. this.loadCount = 0
  193. this.initTable()
  194. this.updateData();
  195. },
  196. updateData: function () {
  197. this.getThreadsLoad();
  198. this.getLoadCount();
  199. this.getAllSession();
  200. },
  201. /**
  202. * 获取线程状态
  203. */
  204. getThreadsLoad: function () {
  205. let that = this;
  206. if (that.mediaServerChoose != null) {
  207. this.$axios({
  208. method: 'get',
  209. url: '/zlm/' + that.mediaServerChoose +'/index/api/getThreadsLoad'
  210. }).then(function (res) {
  211. if (res.data.code == 0) {
  212. that.tableOption.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  213. hour12: false
  214. }));
  215. that.table1Option.xAxis.data.push(new Date().toLocaleTimeString('chinese', {
  216. hour12: false
  217. }));
  218. for (var i = 0; i < res.data.data.length; i++) {
  219. if (that.tableOption.series[i] === undefined) {
  220. let data = {
  221. data: [],
  222. type: 'line'
  223. };
  224. let data1 = {
  225. data: [],
  226. type: 'line'
  227. };
  228. data.data.push(res.data.data[i].delay);
  229. data1.data.push(res.data.data[i].load);
  230. that.tableOption.series.push(data);
  231. that.table1Option.series.push(data1);
  232. } else {
  233. that.tableOption.series[i].data.push(res.data.data[i].delay);
  234. that.table1Option.series[i].data.push(res.data.data[i].load);
  235. }
  236. }
  237. that.tableOption.dataZoom[0].start = that.charZoomStart;
  238. that.tableOption.dataZoom[0].end = that.charZoomEnd;
  239. that.table1Option.dataZoom[0].start = that.charZoomStart;
  240. that.table1Option.dataZoom[0].end = that.charZoomEnd;
  241. //that.myChart = echarts.init(document.getElementById('ThreadsLoad'));
  242. that.myChart.setOption(that.tableOption, true);
  243. // that.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
  244. that.myChart1.setOption(that.table1Option, true);
  245. }
  246. });
  247. }
  248. },
  249. getLoadCount: function (){
  250. let that = this;
  251. if (that.mediaServerChoose != null) {
  252. that.mediaServer.getMediaServer(that.mediaServerChoose, (data)=>{
  253. if (data.code == 0) {
  254. that.loadCount = data.data.count
  255. }
  256. })
  257. }
  258. },
  259. initTable: function () {
  260. let that = this;
  261. this.tableOption.xAxis = {
  262. type: 'category',
  263. data: [], // x轴数据
  264. name: '时间', // x轴名称
  265. // x轴名称样式
  266. nameTextStyle: {
  267. fontWeight: 300,
  268. fontSize: 15
  269. }
  270. };
  271. this.tableOption.yAxis = {
  272. type: 'value',
  273. name: '延迟率', // y轴名称
  274. boundaryGap: [0, '100%'],
  275. max: 100,
  276. axisLabel: {
  277. show: true,
  278. interval: 'auto',
  279. formatter: '{value} %'
  280. },
  281. // y轴名称样式
  282. nameTextStyle: {
  283. fontWeight: 300,
  284. fontSize: 15
  285. }
  286. };
  287. this.tableOption.dataZoom = [{
  288. show: true,
  289. start: this.charZoomStart,
  290. end: this.charZoomEnd
  291. }];
  292. this.myChart = echarts.init(document.getElementById('ThreadsLoad'));
  293. this.myChart.setOption(this.tableOption);
  294. this.myChart.on('dataZoom', function (event) {
  295. if (event.batch) {
  296. that.charZoomStart = event.batch[0].start;
  297. that.charZoomEnd = event.batch[0].end;
  298. } else {
  299. that.charZoomStart = event.start;
  300. that.charZoomEnd = event.end;
  301. }
  302. });
  303. this.table1Option.xAxis = {
  304. type: 'category',
  305. data: [], // x轴数据
  306. name: '时间', // x轴名称
  307. // x轴名称样式
  308. nameTextStyle: {
  309. fontWeight: 300,
  310. fontSize: 15
  311. }
  312. };
  313. this.table1Option.yAxis = {
  314. type: 'value',
  315. name: '负载率', // y轴名称
  316. boundaryGap: [0, '100%'],
  317. max: 100,
  318. axisLabel: {
  319. show: true,
  320. interval: 'auto',
  321. formatter: '{value} %'
  322. },
  323. // y轴名称样式
  324. nameTextStyle: {
  325. fontWeight: 300,
  326. fontSize: 15
  327. }
  328. };
  329. this.table1Option.dataZoom = [{
  330. show: true,
  331. start: this.charZoomStart,
  332. end: this.charZoomEnd
  333. }];
  334. this.myChart1 = echarts.init(document.getElementById('WorkThreadsLoad'));
  335. this.myChart1.setOption(this.table1Option);
  336. this.myChart1.on('dataZoom', function (event) {
  337. if (event.batch) {
  338. that.charZoomStart = event.batch[0].start;
  339. that.charZoomEnd = event.batch[0].end;
  340. } else {
  341. that.charZoomStart = event.start;
  342. that.charZoomEnd = event.end;
  343. }
  344. });
  345. },
  346. getAllSession: function () {
  347. let that = this;
  348. that.allSessionData = [];
  349. this.$axios({
  350. method: 'get',
  351. url: '/zlm/' + that.mediaServerChoose +'/index/api/getAllSession'
  352. }).then(function (res) {
  353. res.data.data.forEach(item => {
  354. let data = {
  355. peer_ip: item.peer_ip,
  356. local_ip: item.local_ip,
  357. typeid: item.typeid,
  358. id: item.id
  359. };
  360. that.allSessionData.push(data);
  361. });
  362. });
  363. },
  364. getServerConfig: function () {
  365. let that = this;
  366. this.$axios({
  367. method: 'get',
  368. url: '/zlm/' + that.mediaServerChoose +'/index/api/getServerConfig'
  369. }).then(function (res) {
  370. let info = res.data.data[0];
  371. let serverInfo = {}
  372. for (let i = 0; i < Object.keys(info).length; i++) {
  373. let key = Object.keys(info)[i];
  374. let group = key.substring(0, key.indexOf("."))
  375. let itemKey = key.substring(key.indexOf(".") + 1)
  376. if (!serverInfo[group]) serverInfo[group] = {}
  377. serverInfo[group][itemKey] = info[key]
  378. }
  379. that.serverConfig = serverInfo;
  380. that.visible = true;
  381. });
  382. },
  383. getWVPServerConfig: function () {
  384. let that = this;
  385. this.$axios({
  386. method: 'get',
  387. url: '/api/server/config'
  388. }).then(function (res) {
  389. console.log(res)
  390. that.wvpServerConfig = res.data.data;
  391. that.wvpVisible = true;
  392. });
  393. this.$axios({
  394. method: 'get',
  395. url: '/api/server/version'
  396. }).then(function (res) {
  397. console.log(res)
  398. that.wvpServerVersion = res.data.data;
  399. that.wvpVisible = true;
  400. });
  401. },
  402. reStartServer: function () {
  403. let that = this;
  404. this.$confirm('此操作将重启媒体服务器, 是否继续?', '提示', {
  405. confirmButtonText: '确定',
  406. cancelButtonText: '取消',
  407. type: 'warning'
  408. }).then(() => {
  409. let that = this;
  410. this.$axios({
  411. method: 'get',
  412. url: '/zlm/' + that.mediaServerChoose +'/index/api/restartServer'
  413. }).then(function (res) {
  414. that.getAllSession();
  415. if (res.data.code == 0) {
  416. that.$message({
  417. type: 'success',
  418. message: '操作完成'
  419. });
  420. }
  421. });
  422. });
  423. },
  424. deleteRow: function (index, tabledata) {
  425. let that = this;
  426. this.$confirm('此操作将断开该通信链路, 是否继续?', '提示', {
  427. confirmButtonText: '确定',
  428. cancelButtonText: '取消',
  429. type: 'warning'
  430. })
  431. .then(() => {
  432. that.deleteSession(tabledata[index].id);
  433. })
  434. .catch(() => {
  435. console.log('id:' + JSON.stringify(tabledata[index]));
  436. this.$message({
  437. type: 'info',
  438. message: '已取消删除'
  439. });
  440. });
  441. console.log(JSON.stringify(tabledata[index]));
  442. },
  443. deleteSession: function (id) {
  444. let that = this;
  445. this.$axios({
  446. method: 'get',
  447. url: '/zlm/' + that.mediaServerChoose +'/index/api/kick_session&id=' + id
  448. }).then(function (res) {
  449. that.getAllSession();
  450. that.$message({
  451. type: 'success',
  452. message: '删除成功!'
  453. });
  454. });
  455. },
  456. getNameFromKey: function(key) {
  457. let nameData = {
  458. "waitTrack": "等待编码信息",
  459. "interfaceAuthenticationExcludes": "不进行鉴权的接口",
  460. "playTimeout": "点播超时时间",
  461. "autoApplyPlay": "自动点播",
  462. "recordPushLive": "推流录像",
  463. "redisConfig": "自动配置redis",
  464. "thirdPartyGBIdReg": "stream信息正则",
  465. "savePositionHistory": "保存轨迹信息",
  466. "interfaceAuthentication": "接口鉴权",
  467. "serverId": "服务ID",
  468. "logInDatebase": "日志存储进数据库",
  469. "seniorSdp": "扩展SDP",
  470. "password": "密码",
  471. "port": "端口号",
  472. "keepaliveTimeOut": "心跳超时",
  473. "domain": "国标域",
  474. "ip": "IP地址",
  475. "monitorIp": "监听IP",
  476. "alarm": "存储报警信息",
  477. "ptzSpeed": "云台控制速度",
  478. "id": "国标ID",
  479. "registerTimeInterval": "注册间隔",
  480. "artifactId": "模块名称",
  481. "version": "版本",
  482. "project": "工程",
  483. "git_Revision": "GIT修订版本",
  484. "git_BRANCH": "GIT分支",
  485. "git_URL": "GIT地址",
  486. "build_DATE": "构建时间",
  487. "create_By": "作者",
  488. "git_Revision_SHORT": "GIT修订版本(短)",
  489. "build_Jdk": "构建用JDK",
  490. };
  491. console.log(key + ": " + nameData[key])
  492. if (nameData[key]) {
  493. return nameData[key]
  494. }else {
  495. return key;
  496. }
  497. },
  498. getMediaKeyNameFromKey: function(key) {
  499. let nameData = {
  500. "waitTrack": "等待编码信息",
  501. "interfaceAuthenticationExcludes": "不进行鉴权的接口",
  502. "playTimeout": "点播超时时间",
  503. "autoApplyPlay": "自动点播",
  504. "recordPushLive": "推流录像",
  505. "redisConfig": "自动配置redis",
  506. "thirdPartyGBIdReg": "stream信息正则",
  507. "savePositionHistory": "保存轨迹信息",
  508. "interfaceAuthentication": "接口鉴权",
  509. "serverId": "服务ID",
  510. "logInDatebase": "日志存储进数据库",
  511. "seniorSdp": "扩展SDP",
  512. "password": "密码",
  513. "port": "端口号",
  514. "keepaliveTimeOut": "心跳超时",
  515. "domain": "国标域",
  516. "ip": "IP地址",
  517. "monitorIp": "监听IP",
  518. "alarm": "存储报警信息",
  519. "ptzSpeed": "云台控制速度",
  520. "id": "国标ID",
  521. "registerTimeInterval": "注册间隔",
  522. "artifactId": "模块名称",
  523. "version": "版本",
  524. "project": "工程",
  525. "git_Revision": "GIT修订版本",
  526. "git_BRANCH": "GIT分支",
  527. "git_URL": "GIT地址",
  528. "build_DATE": "构建时间",
  529. "create_By": "作者",
  530. "git_Revision_SHORT": "GIT修订版本(短)",
  531. "build_Jdk": "构建用JDK",
  532. };
  533. console.log(key + ": " + nameData[key])
  534. if (nameData[key]) {
  535. return nameData[key]
  536. }else {
  537. return key;
  538. }
  539. }
  540. }
  541. };
  542. </script>
  543. <style>
  544. #app {
  545. height: 100%;
  546. }
  547. .control-table {
  548. background-color: #ffffff;
  549. height: 25rem;
  550. }
  551. .table-c {
  552. border-right: 1px solid #dcdcdc;
  553. border-bottom: 1px solid #dcdcdc;
  554. }
  555. .table-c td {
  556. border-left: 1px solid #dcdcdc;
  557. border-top: 1px solid #dcdcdc;
  558. padding: 0.2rem;
  559. }
  560. .el-table {
  561. width: 99.9% !important;
  562. }
  563. </style>