You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

308 lines
10 KiB

12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
12 months ago
11 months ago
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <title>消毒API测试页面</title>
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  7. <script src="./vue.global.js"></script>
  8. <script src="./dayjs/dayjs.min.js"></script>
  9. <script src="./dayjs/plugin/customParseFormat.js"></script>
  10. <script src="./dayjs/plugin/weekday.js"></script>
  11. <script src="./dayjs/plugin/localeData.js"></script>
  12. <script src="./dayjs/plugin/weekOfYear.js"></script>
  13. <script src="./dayjs/plugin/weekYear.js"></script>
  14. <script src="./dayjs/plugin/advancedFormat.js"></script>
  15. <script src="./dayjs/plugin/quarterOfYear.js"></script>
  16. <script src="./ant-design-vue/antd.min.js"></script>
  17. <link href="./ant-design-vue/reset.min.css" rel="stylesheet">
  18. <script src="./virtual-keyboard.js"></script>
  19. </head>
  20. <body>
  21. <div id="app" class="h-full">
  22. <a-row class="h-full">
  23. <a-col :span="6">
  24. <div style="display:flex;padding:5px;">
  25. <a-input v-model:value="wsUrl" style="margin-right:5px;"></a-input>
  26. <a-button v-if="null === ws" @click="actionConnect">连接</a-button>
  27. <a-button v-else @click="actionDisconnect">断开</a-button>
  28. </div>
  29. <a-menu mode="inline" :items="actionMenuItems" @click="actionGroupMenuItemClick"></a-menu>
  30. </a-col>
  31. <!-- -->
  32. <a-col :span="12" style="background-color: #f1f1f1;display:flex;flex-direction: column;">
  33. <div v-if="null !== actionActiveGroup"
  34. style="height:0;flex-grow: 1;overflow-y: auto;margin-bottom: 10px;padding: 10px;">
  35. <div v-for="item in actionActiveGroup.items" class="action"
  36. style="margin-bottom: 5px;background:white;padding:5px;border-radius: 5px;">
  37. <div style="margin-right:5px;padding: 8px;">
  38. {{item.fnName}}
  39. </div>
  40. <div v-for="param in item.params">
  41. <a-select v-if="item.paramInfoMap[param].isEnum" v-model:value="item.values[param]" :placeholder="param"
  42. :dropdownMatchSelectWidth="false">
  43. <a-select-option v-for="enumValue in item.paramInfoMap[param].enumValues" :key="enumValue"
  44. :value="enumValue">{{enumValue}}</a-select-option>
  45. </a-select>
  46. <!-- 点击输入框后弹出键盘 -->
  47. <a-input v-else v-model:value="item.values[param]" :placeholder="param"
  48. @click="showKeyboard(item.values, param)"></a-input>
  49. </div>
  50. <a-button style="margin-left:5px;" @click="actionActionExecute(item)">执行</a-button>
  51. </div>
  52. </div>
  53. <!-- <div style="padding:10px;">
  54. <a-textarea v-model:value="rawRequestContent" style="margin-bottom: 5px;height: 300px;"></a-textarea>
  55. <div>
  56. <a-button @click="actionSendRawRequest">发送</a-button>
  57. </div>
  58. </div> -->
  59. </a-col>
  60. <a-col :span="6" style="height: 100%;display: flex;flex-direction: column;">
  61. <div style="text-align: right; padding:10px;">
  62. <a-button @click="actionClearLogs">清空日志</a-button>
  63. </div>
  64. <div style="height:0;flex-grow:1;overflow-y: auto;">
  65. <a-collapse>
  66. <a-collapse-panel v-for="(entry,index) in logs" :key="index" :header="entry.title">
  67. <div style="white-space: pre-wrap;">
  68. {{entry.content}}
  69. </div>
  70. </a-collapse-panel>
  71. </a-collapse>
  72. </div>
  73. <div style="padding:10px;">
  74. <div style="margin-bottom: 5px;height: 600px; overflow-y: auto;">
  75. <a-collapse>
  76. <a-collapse-panel v-for="(entry,index) in reports" :key="index" :header="entry.title">
  77. <div style="white-space: pre-wrap;">
  78. {{entry.content}}
  79. </div>
  80. </a-collapse-panel>
  81. </a-collapse>
  82. </div>
  83. </div>
  84. </a-col>
  85. </a-row>
  86. </div>
  87. <script>
  88. const { createApp } = Vue
  89. createApp({
  90. data() {
  91. return {
  92. actions: [],
  93. actionActiveGroup: null,
  94. rawRequestContent: '',
  95. logs: [],
  96. reports: [],
  97. wsUrl: "ws://" + window.location.hostname + ":19001",
  98. ws: null,
  99. wsMessageIndex: 0,
  100. requests: {},
  101. reportId: 0,
  102. map: new Map(),
  103. counter: 0
  104. }
  105. },
  106. computed: {
  107. actionMenuItems() {
  108. return this.actions.map(i => ({ key: i.key, label: i.key }));
  109. }
  110. },
  111. mounted() {
  112. },
  113. methods: {
  114. // connect
  115. getReportId(str) {
  116. // 如果字符串已存在,返回已存储的id
  117. if (this.map.has(str)) {
  118. return this.map.get(str);
  119. }
  120. // 否则,生成一个新的ID
  121. const id = this.counter++;
  122. this.map.set(str, id);
  123. return id;
  124. },
  125. actionConnect() {
  126. this.ws = new WebSocket(this.wsUrl);
  127. this.ws.onclose = () => this.ws = null;
  128. this.ws.onmessage = event => {
  129. let data = JSON.parse(event.data);
  130. let responseEntry = {};
  131. responseEntry.title = `${data.fromClass}.${data.fromFn}`;
  132. responseEntry.content = JSON.stringify(data, null, 2);
  133. if ('Ack' === data.messageType && 'FNScheduler' === data.fromClass && 'geFnList' === data.fromFn) {
  134. this.actionListReload(data);
  135. }
  136. if ('Ack' === data.messageType) {
  137. this.logs.push(responseEntry);
  138. }
  139. if ('Report' === data.messageType) {
  140. let reportuuid = data.fromClass + '.' + data.fromFn;
  141. let reportId = this.getReportId(reportuuid);
  142. // this.reports.unshift(reportId,responseEntry);
  143. this.reports[reportId] = responseEntry;
  144. }
  145. };
  146. this.ws.onopen = () => {
  147. this.wsMessageIndex++;
  148. let request = {};
  149. request.messageId = this.wsMessageIndex;
  150. request.timeStamp = Math.floor(Date.now() / 1000);
  151. request.messageType = 'Command';
  152. request.className = 'FNScheduler';
  153. request.fnName = 'geFnList';
  154. request.params = {};
  155. this.wsCall(request);
  156. }
  157. },
  158. // disconnect
  159. actionDisconnect() {
  160. this.ws.close();
  161. },
  162. // clear logs
  163. actionClearLogs() {
  164. this.logs = [];
  165. },
  166. showKeyboard(values, param) {
  167. // const inputElement = document.querySelector(`input[placeholder="${param}"]`);
  168. // if (inputElement) {
  169. // VirtualKeyboard.show(inputElement);
  170. // this.updateDisplayContainer(inputElement);
  171. // }
  172. },
  173. updateDisplayContainer(inputElement) {
  174. const displayContainer = document.querySelector('.virtual-keyboard-display');
  175. if (displayContainer) {
  176. inputElement.addEventListener('input', () => {
  177. displayContainer.textContent = inputElement.value;
  178. });
  179. }
  180. },
  181. // action list reload
  182. actionListReload(response) {
  183. let data = response.rely;
  184. if (undefined === data) {
  185. return;
  186. }
  187. this.actions = [];
  188. for (let action of data.fnlist) {
  189. let group = this.actions.find(i => i.key === action.className);
  190. if (undefined === group) {
  191. group = { key: action.className, items: [] };
  192. this.actions.push(group);
  193. }
  194. item = JSON.parse(JSON.stringify(action)); // Replace structuredClone with JSON.parse(JSON.stringify())
  195. item.values = {};
  196. item.paramInfoMap = {};
  197. for (let i = 0; i < item.paramsTypeInfo.length; i++) {
  198. let typeName = item.paramsTypeInfo[i];
  199. let info = data.typeInfoList.find(p => p.typeName === typeName);
  200. let name = item.params[i];
  201. item.paramInfoMap[name] = info;
  202. }
  203. group.items.push(item);
  204. }
  205. },
  206. // action group menu item click
  207. actionGroupMenuItemClick(event) {
  208. this.actionActiveGroup = this.actions.find(i => i.key === event.key);
  209. },
  210. // action execute
  211. actionActionExecute(item) {
  212. this.wsMessageIndex++;
  213. let request = {};
  214. request.messageId = this.wsMessageIndex;
  215. request.timeStamp = Math.floor(Date.now() / 1000);
  216. request.messageType = 'Command';
  217. request.className = item.className;
  218. request.fnName = item.fnName;
  219. request.params = {};
  220. for (let i = 0; i < item.params.length; i++) {
  221. let param = item.params[i];
  222. let type = item.paramsTypeInfo[i];
  223. let value = item.values[param];
  224. switch (type) {
  225. case 'json':
  226. case 'vector<bool>':
  227. case 'vector<json>':
  228. case 'vector<double>':
  229. case 'vector<int32_t>':
  230. case 'vector<string>': value = JSON.parse(value); break;
  231. case 'bool': value = '1' === value ? true : false; break;
  232. case 'float':
  233. case 'double':
  234. case 'int': value *= 1; break;
  235. case 'string': /* nothing to do here */ break;
  236. default: /* throw an exception is required. */
  237. }
  238. request.params[param] = value;
  239. }
  240. this.logs = [];
  241. this.wsCall(request);
  242. },
  243. // raw request send
  244. actionSendRawRequest() {
  245. let request = JSON.parse(this.rawRequestContent);
  246. this.wsCall(request);
  247. },
  248. // ws call
  249. wsCall(request) {
  250. if (null === this.ws) {
  251. return;
  252. }
  253. let requestEntry = {};
  254. requestEntry.title = `${request.messageType} : ${request.className}.${request.fnName}`;
  255. requestEntry.content = JSON.stringify(request, null, 2);
  256. this.logs.push(requestEntry);
  257. this.ws.send(JSON.stringify(request));
  258. },
  259. },
  260. })
  261. .use(antd)
  262. .mount('#app');
  263. </script>
  264. <style>
  265. .h-full {
  266. height: 100%;
  267. }
  268. .action {
  269. display: flex;
  270. flex-direction: row;
  271. }
  272. </style>
  273. </body>
  274. </html>