index.html 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. <html lang="zh">
  2. <head>
  3. <meta charset="utf-8">
  4. <title>Grasscutters 网页控制台</title>
  5. <meta name="viewport" content="width=device-width">
  6. <meta name="apple-mobile-web-app-capable" content="yes">
  7. <meta name="apple-mobile-web-app-status-bar-style" content="black">
  8. <meta name="viewport"
  9. content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=5,user-scalable=yes"/>
  10. <link rel="stylesheet" href="css/mui.min.css">
  11. <script src="js/mui.min.js"></script>
  12. <script type="text/javascript" src="js/qrcode.min.js"></script>
  13. <header class="mui-bar mui-bar-nav">
  14. <h1 class="mui-title">Grasscutters 网页控制台</h1>
  15. </header>
  16. </head>
  17. <body>
  18. <div class="mui-content">
  19. <div class="mui-card" style="margin-bottom: 35px;">
  20. <div class="mui-card-header">扫描二维码也可以打开这个页面
  21. <a type="button" data-loading-text="请稍后" class="mui-btn"
  22. href="https://wmn1525.github.io/grasscutterTools/dist/index.html#/start/login">使用@wmn1525的面板</a>
  23. </div>
  24. <div id="qrcode"></div>
  25. </div>
  26. <div class="mui-card">
  27. <div class="mui-card-header">运行状态</div>
  28. <div class="mui-card-content">
  29. <div class="mui-card-content-inner">
  30. <div class="mui-text-center">
  31. <h5 id="id-uptime-title">系统运行时长:</h5>
  32. </div>
  33. </div>
  34. <div class="mui-card-content-inner">
  35. <div class="mui-text-center">
  36. <h5 id="id-player-num-title">在线玩家数量:</h5>
  37. </div>
  38. </div>
  39. <div class="mui-card-content-inner">
  40. <div class="mui-text-center">
  41. <h5 id="id-tick-time-title">Tick耗时:</h5>
  42. </div>
  43. </div>
  44. <div class="mui-card-content-inner">
  45. <div class="mui-text-center">
  46. <h5 id="id-memory-title">内存占用:0/0</h5>
  47. <p id="id-memory-progressbar" class="mui-progressbar mui-progressbar-in"><span
  48. style="transform: translate3d(-90%, 0px, 0px);"></span></p>
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. <div class="mui-card">
  54. <div class="mui-card-header">系统信息</div>
  55. <div class="mui-card-content">
  56. <div class="mui-card-content-inner" id="id-BaseData">
  57. </div>
  58. </div>
  59. </div>
  60. <div class="mui-card">
  61. <div class="mui-card-header">控制台</div>
  62. <div class="mui-card-content">
  63. <div class="mui-input-row" contenteditable="true" style="margin: 10px 5px;">
  64. <textarea id="cmd_msg-textarea" readonly="readonly" rows="10" placeholder=""></textarea>
  65. </div>
  66. </div>
  67. <div class="mui-card-footer">
  68. <label>命令:</label>
  69. <input id="id-cmd-input" type="text" style="width: 80%" placeholder="在这里输入命令,不要带/">
  70. <button class="mui-btn mui-btn-primary" type="button" data-loading-text="请稍后" onclick="do_cmd()">执行</button>
  71. </div>
  72. </div>
  73. <div class="mui-card" style="margin-bottom: 35px;">
  74. <div class="mui-card-header">在线玩家
  75. <button type="button" data-loading-text="请稍后" class="mui-btn" onclick="updatePlayerList()">刷新</button>
  76. </div>
  77. <ul class="mui-table-view" id="id-player-list">
  78. </ul>
  79. </div>
  80. </div>
  81. <script>
  82. mui.init();
  83. function getQueryVariable(variable) {
  84. const query = window.location.search.substring(1);
  85. const vars = query.split("&");
  86. for (let i = 0; i < vars.length; i++) {
  87. const pair = vars[i].split("=");
  88. if (pair[0] === variable) {
  89. return pair[1];
  90. }
  91. }
  92. return false;
  93. }
  94. let ServerAddress = getQueryVariable("server");
  95. if (ServerAddress !== false) {
  96. //URL解码
  97. ServerAddress = decodeURIComponent(ServerAddress);
  98. }
  99. if (ServerAddress === false) {
  100. mui.prompt("请输入服务器连接地址", "服务器连接地址", "提示", ["连接"], ContentServer);
  101. } else {
  102. ContentServer({value: ServerAddress});
  103. }
  104. var ws;
  105. function updatePlayerList() {
  106. ws.send("{\"type\":\"Player\",\"data\":\"0\"}");
  107. }
  108. function ContentServer(value) {
  109. const server_address = value.value;
  110. console.log(server_address);
  111. if (server_address.indexOf("ws://") < 0 && server_address.indexOf("wss://") < 0) {
  112. mui.alert("服务器地址不正确", "连接失败", "刷新", function () {
  113. location.reload();
  114. });
  115. return;
  116. }
  117. try {
  118. //判断server_address是否是一个有效的websocket地址
  119. ws = new WebSocket(server_address);
  120. ws.onopen = function () {
  121. new QRCode(document.getElementById("qrcode"), {
  122. text: "https://liujiaqi7998.github.io/GrasscuttersWebDashboard/index.html?server=" + ServerAddress,
  123. width: 180,
  124. height: 180,
  125. //居中
  126. colorDark: "#000000",
  127. colorLight: "#ffffff",
  128. correctLevel: QRCode.CorrectLevel.H
  129. });
  130. console.log("连接成功");
  131. mui.toast("连接成功");
  132. ws.send("{\"type\":\"State\",\"data\":\"0\"}");
  133. ws.send("{\"type\":\"Player\",\"data\":\"0\"}");
  134. }
  135. } catch (e) {
  136. mui.alert(e.toString(), "连接失败", "刷新", function () {
  137. location.reload();
  138. });
  139. return;
  140. }
  141. ws.onmessage = function (event) {
  142. const server_msg = JSON.parse(event.data);
  143. switch (server_msg['eventName']) {
  144. case 'error':
  145. mui.alert(server_msg['data'], "错误", "刷新", function () {
  146. });
  147. break;
  148. case 'BaseData':
  149. const base_data = server_msg['data'];
  150. const str_temp = "服务器名称:" + base_data['ServerName'] + "<br/>\n" +
  151. " 系统:" + base_data['SystemVersion'] + "<br/>\n" +
  152. " 服务器地址:" + base_data['IP'] + "<br/>\n" +
  153. " JAVA版本:" + base_data['JavaVersion'] + "<br/>\n" +
  154. " 插件版本:" + base_data['GrVersion'];
  155. document.getElementById("id-BaseData").innerHTML = str_temp;
  156. break;
  157. case 'cmd_msg':
  158. const cmd_msg = server_msg['data'];
  159. document.getElementById("cmd_msg-textarea").value += cmd_msg + "\n";
  160. break;
  161. case 'tick':
  162. const tick_data = server_msg['data'];
  163. const memory_used = tick_data['getAllocatedMemory'] - tick_data['getFreeMemory'];
  164. mui("#id-memory-progressbar").progressbar().setProgress(memory_used / tick_data['getAllocatedMemory'] * 100);
  165. document.getElementById("id-memory-title").innerHTML = "内存占用:" + memory_used + "/" + tick_data['getAllocatedMemory'];
  166. document.getElementById("id-uptime-title").innerHTML = "系统运行时长:" + formatSecToStr(Math.ceil(tick_data['serverUptime'] / 1000));
  167. document.getElementById("id-player-num-title").innerHTML = "在线玩家数量:" + tick_data['playerCount'];
  168. document.getElementById("id-tick-time-title").innerHTML = "Tick耗时:" + tick_data['tickTimeElapsed'];
  169. break;
  170. case 'PlayerList':
  171. const player_list = server_msg['data'];
  172. //遍历玩家列表
  173. let player_list_html = "";
  174. for (let i = 0; i < player_list.length; i++) {
  175. const player_data = player_list[i];
  176. player_list_html += "<li class=\"mui-table-view-cell\">\n" +
  177. " <div class=\"mui-slider-cell\">\n" +
  178. " <div class=\"mui-slider-cell-right\">\n" +
  179. " <p class=\"mui-ellipsis\">UID:" + player_data['uid'] + "</p>\n" +
  180. " <p class=\"mui-ellipsis\">昵称:" + player_data['nickname'] + "</p>\n" +
  181. " <p class=\"mui-ellipsis\">签名:" + player_data['signature'] + "</p>\n" +
  182. " <p class=\"mui-ellipsis\">等级:" + player_data['Level'] + "级</p>\n" +
  183. " <p class=\"mui-ellipsis\">世界等级:" + player_data['worldLevel'] + "级</p>\n" +
  184. " <p class=\"mui-ellipsis\">等级:" + player_data['Level'] + "级</p>\n" +
  185. " <p class=\"mui-ellipsis\">坐标:" + player_data['pos'] + "</p>\n" +
  186. " <p class=\"mui-ellipsis\">场景:" + player_data['SceneId'] + "</p>\n" +
  187. " </div>\n" +
  188. " </div>\n" +
  189. " </li>";
  190. }
  191. document.getElementById("id-player-list").innerHTML = player_list_html;
  192. break;
  193. default:
  194. break;
  195. }
  196. }
  197. ws.onclose = function () {
  198. console.log("连接关闭");
  199. mui.alert("与服务器断开连接", "连接失败", "刷新", function () {
  200. location.reload();
  201. });
  202. }
  203. }
  204. function do_cmd(e) {
  205. const send_msg = {
  206. "type": "CMD",
  207. "data": document.getElementById("id-cmd-input").value
  208. };
  209. const send_msg_str = JSON.stringify(send_msg);
  210. ws.send(send_msg_str);
  211. }
  212. function formatSecToStr(seconds) {
  213. let daySec = 24 * 60 * 60;
  214. let hourSec = 60 * 60;
  215. let minuteSec = 60;
  216. let dd = Math.floor(seconds / daySec);
  217. let hh = Math.floor((seconds % daySec) / hourSec);
  218. let mm = Math.floor((seconds % hourSec) / minuteSec);
  219. let ss = seconds % minuteSec;
  220. if (dd > 0) {
  221. return dd + "天" + hh + "小时" + mm + "分钟" + ss + "秒";
  222. } else if (hh > 0) {
  223. return hh + "小时" + mm + "分钟" + ss + "秒";
  224. } else if (mm > 0) {
  225. return mm + "分钟" + ss + "秒";
  226. } else {
  227. return ss + "秒";
  228. }
  229. }
  230. </script>
  231. </body>
  232. </html>