人民医院前端

debuggerBox.vue 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. <template>
  2. <view :class="'debugger-box'+(isFromWindow?' window':'')" :style="{top:`${top}px`}">
  3. <view v-if="!isFromWindow" class="debugger-title">
  4. <text class="text">调试输出窗口</text>
  5. <view class="tool">
  6. <button class="tool-button" style="width:180rpx;" @touchstart="isDragging=true" @touchmove="onDraggingHeight" @touchend="isDragging=false">调整高度</button>
  7. <button class="close tool-button" @click="$emit('close')">关闭</button>
  8. </view>
  9. </view>
  10. <view :class="'debugger-tab'+(isFromWindow?' full':'')">
  11. <view class="debugger-tab-tabs">
  12. <view v-for="(item,index) in tabs" :key="index" :class="'tab'+(tab==item.id?' active':'')" @click="tab=item.id">
  13. <text class="text">{{item.text}}</text>
  14. </view>
  15. </view>
  16. <view class="debugger-tab-area">
  17. <!--日志页面-->
  18. <scroll-view v-if="tab=='console'" class="view" :scroll-x="true" :scroll-y="true">
  19. <view class="head-area">
  20. <button class="tool-button" @click="onClearLogs">清空</button>
  21. <text class="head-text" style="margin-left:8rpx">共 {{logList.length}} 条日志, 点击时间可复制信息</text>
  22. </view>
  23. <view v-for="(item,index) in logList" :key="index" :class="'console-item '+item.type">
  24. <text class="time" @click="onCopy(item.str)">{{item.time}}</text>
  25. <jsObjectText v-for="(ixx,kxx) in item.solvedObjs" :key="kxx" :obj="ixx" :messageType="item.type" style="margin-right:8rpx" />
  26. </view>
  27. </scroll-view>
  28. <!--请求页面-->
  29. <scroll-view v-if="tab=='network'" class="view" :scroll-x="true" :scroll-y="true">
  30. <view class="head-area">
  31. <button class="tool-button" @click="onClearNetworkLogs">清空</button>
  32. <text class="head-text" style="margin-left:8rpx">共 {{networkList.length}} 条请求数据</text>
  33. </view>
  34. <requestItem v-for="(item,index) in networkList" :key="index" :data="item" />
  35. </scroll-view>
  36. <!--错误信息-->
  37. <scroll-view v-if="tab=='error'" class="view" :scroll-x="true" :scroll-y="true">
  38. <view class="head-area">
  39. <button class="tool-button" @click="onClearErrorLogs">清空</button>
  40. <text class="head-text" style="margin-left:8rpx">共 {{errorList.length}} 条错误信息, 点击圆点可复制信息</text>
  41. </view>
  42. <view v-for="(item,index) in errorList" :key="index" :class="'console-item '+item.type">
  43. <errtItem :data="item">
  44. <view class="round red" @click.stop="onCopy(item.str)"></view>
  45. </errtItem>
  46. </view>
  47. </scroll-view>
  48. <!--存储-->
  49. <scroll-view v-if="tab=='storage'" class="view" :scroll-x="true" :scroll-y="true">
  50. <view class="head-area">
  51. <button class="tool-button" @click="loadStorageList">刷新</button>
  52. <button class="tool-button" @click="onClearCache">清空</button>
  53. <text class="head-text" style="margin-left:8rpx">共 {{storageList.length}} 条数据, 长按键可复制JSON</text>
  54. </view>
  55. <view v-for="(item,index) in storageList" :key="index" :class="'console-item '+item.type">
  56. <text class="time" @longpress="onCopy(item.str)">{{item.key}}</text>
  57. <jsObjectText :obj="item.obj" />
  58. </view>
  59. </scroll-view>
  60. <!--设置-->
  61. <scroll-view v-if="tab=='set'" class="view">
  62. <button class="tool-button" style="width:400rpx" @click="onCloseToolBar(false)">隐藏悬浮窗(本次)</button>
  63. <button class="tool-button" style="width:400rpx" @click="onCloseToolBar(true)">隐藏悬浮窗(永久)</button>
  64. </scroll-view>
  65. </view>
  66. </view>
  67. </view>
  68. </template>
  69. <script>
  70. import jsObjectText from './jsObjectText.vue'
  71. import requestItem from './requestItem.vue'
  72. import errtItem from './errtItem.vue'
  73. import { setClipboardText } from '../../common/clipboard.js'
  74. export default {
  75. data() {
  76. return {
  77. tab: 'console',
  78. tabs: [
  79. {id:'console', text: 'Console'},
  80. {id:'network', text: 'Network'},
  81. {id:'error', text: 'Error'},
  82. {id:'storage', text: 'Storage'},
  83. {id:'set', text: 'Settings'},
  84. ],
  85. logList: [],
  86. errorList: [],
  87. networkList: [],
  88. storageList: [],
  89. screenHeight: 0,
  90. isDragging: false,
  91. top: 200,
  92. };
  93. },
  94. mounted() {
  95. this.loadLogsList();
  96. this.loadErrorList();
  97. this.loadNetworkList();
  98. this.loadStorageList();
  99. const lastTop = uni.getStorageSync('im-debuggerFloatingTop');
  100. const that = this;
  101. if(!this.isFromWindow && lastTop != "")
  102. this.top = parseInt(lastTop);
  103. else
  104. this.top = 0;
  105. uni.getSystemInfo({
  106. success(res) {
  107. that.screenHeight = res.screenHeight;
  108. }
  109. })
  110. uni.$emit('debugger-view-opened');
  111. uni.$on('debugger-refresh-network', () => {
  112. const arr = getApp().globalData.debuggerNetworkLogData;
  113. this.networkList.push(arr[arr.length - 1]);
  114. });
  115. uni.$on('debugger-refresh-app-err', () => this.loadErrorList());
  116. uni.$on('debugger-refresh-vue-err', () => this.loadErrorList());
  117. uni.$on('debugger-refresh-log', (removeFirst) => {
  118. const arr = getApp().globalData.debuggerLogData;
  119. if(removeFirst)
  120. this.logList.unshift();
  121. this.logList.push(this.solveLogItem(arr[arr.length - 1]));
  122. });
  123. },
  124. beforeDestroy() {
  125. uni.setStorageSync('im-debuggerFloatingTop', '' + this.top);
  126. uni.$emit('debugger-view-closed');
  127. uni.$off('debugger-refresh-network');
  128. uni.$off('debugger-refresh-app-err');
  129. uni.$off('debugger-refresh-vue-err');
  130. uni.$off('debugger-refresh-log');
  131. },
  132. components: {
  133. jsObjectText,
  134. requestItem,
  135. errtItem,
  136. },
  137. props: {
  138. isFromWindow: {
  139. type: Boolean,
  140. default: false,
  141. }
  142. },
  143. methods: {
  144. stop() {},
  145. solveLogItem(k) {
  146. if(!k || !k.objects)
  147. return '';
  148. const solve = (str) => {
  149. const finalArr = [];
  150. let next_speical = '';
  151. const str_arr = str.split('---');
  152. for(let i = 0; i < str_arr.length; i++) {
  153. const str_item = str_arr[i];
  154. if(str_item == 'UNDEFINED') {
  155. finalArr.push(undefined);
  156. } else if(str_item.indexOf('BEGIN:') == 0) {
  157. next_speical = str_item.substr(6);
  158. } else if(str_item.indexOf('END:') == 0) {
  159. if(next_speical == str_item.substr(4)) {
  160. next_speical = '';
  161. }
  162. } else {
  163. switch(next_speical) {
  164. case 'BOOLEAN':
  165. finalArr.push(new Boolean(str_item) ? true : false);
  166. break;
  167. case 'NUMBER':
  168. finalArr.push(parseFloat(str_item));
  169. break;
  170. case 'JSON':
  171. finalArr.push(JSON.parse(str_item));
  172. break;
  173. default:
  174. finalArr.push(str_item);
  175. break;
  176. }
  177. }
  178. }
  179. return finalArr
  180. };
  181. k.str = k.objects.toString();
  182. const obj_arr = k.str.split('---COMMA---');
  183. if(obj_arr.length > 1) {
  184. k.solvedObjs = [];
  185. for (let i = 0; i < obj_arr.length; i++)
  186. solve(obj_arr[i]).forEach(l => k.solvedObjs.push(l))
  187. }
  188. else k.solvedObjs = [ ...solve(obj_arr[0]) ];
  189. return k;
  190. },
  191. loadLogsList() {
  192. const data = getApp().globalData.debuggerLogData;
  193. data.forEach((k) => this.solveLogItem(k))
  194. this.logList = data;
  195. },
  196. loadErrorList() { this.errorList = getApp().globalData.debuggerErrLogData; },
  197. loadNetworkList() { this.networkList = getApp().globalData.debuggerNetworkLogData; },
  198. loadStorageList() {
  199. const that = this;
  200. this.storageList = [];
  201. uni.getStorageInfo({
  202. success(res) {
  203. res.keys.forEach(item => {
  204. that.storageList.push({
  205. key: item,
  206. obj: uni.getStorageSync(item)
  207. })
  208. })
  209. }
  210. })
  211. },
  212. onDraggingHeight(e) {
  213. if(e.touches.length > 0) {
  214. let top = e.touches[0].clientY - 40;
  215. if(top > this.screenHeight - 200)
  216. top = this.screenHeight - 200;
  217. if(top < 0)
  218. top = 0;
  219. this.top = top;
  220. }
  221. e.stopPropagation();
  222. },
  223. onClearNetworkLogs() {
  224. getApp().globalData.debuggerNetworkLogData = [];
  225. this.networkList = [];
  226. },
  227. onClearErrorLogs() {
  228. getApp().globalData.debuggerErrLogData = [];
  229. this.errorList = [];
  230. },
  231. onClearLogs() {
  232. getApp().globalData.debuggerLogData = [];
  233. this.logList = [];
  234. },
  235. onCloseToolBar(forever) {
  236. if(forever) {
  237. uni.showModal({
  238. title: '提示',
  239. content: '是否要隐藏调试悬浮窗? 永久隐藏后,可以卸载再安装以显示悬浮窗',
  240. success(res) {
  241. if(res.confirm) {
  242. uni.setStorageSync('im-noNorDebuggerFloating', 'yes')
  243. uni.$emit('debugger-view-close');
  244. uni.navigateBack()
  245. }
  246. },
  247. })
  248. } else {
  249. uni.$emit('debugger-view-close');
  250. uni.navigateBack()
  251. }
  252. },
  253. onClearCache() {
  254. const that = this;
  255. uni.showModal({
  256. title: '提示',
  257. content: '是否要清除缓存?',
  258. success(res) {
  259. if(res.confirm) {
  260. uni.clearStorageSync();
  261. uni.showToast({
  262. icon: 'success',
  263. title: '已清除!',
  264. });
  265. that.loadStorageList();
  266. }
  267. },
  268. })
  269. },
  270. onCopy(str) {
  271. setClipboardText(str);
  272. uni.showToast({
  273. icon: 'none',
  274. title: '已复制!',
  275. })
  276. },
  277. },
  278. }
  279. </script>
  280. <style lang="scss">
  281. .debugger-box {
  282. display: flex;
  283. flex-direction: column;
  284. border-top: 1px solid #f6f6f6;
  285. position: fixed;
  286. bottom: 0;
  287. left: 0;
  288. right: 0;
  289. background-color: #fff;
  290. &.window {
  291. position: absolute;
  292. top: 0;
  293. bottom: 0;
  294. left: 0;
  295. right: 0;
  296. }
  297. }
  298. .debugger-title {
  299. display: flex;
  300. width: 750rpx;
  301. flex-direction: row;
  302. justify-content: space-between;
  303. align-items: center;
  304. padding: 2px 15rpx;
  305. height: 80rpx;
  306. border-bottom: 1px solid #f6f6f6;
  307. > .text {
  308. font-size: 40rpx;
  309. font-weight: bold;
  310. color: #333232;
  311. }
  312. .tool {
  313. display: flex;
  314. flex-direction: row;
  315. align-items: center;
  316. }
  317. }
  318. .debugger-tab {
  319. position: absolute;
  320. top: 80rpx;
  321. right: 0;
  322. bottom: 0;
  323. left: 0;
  324. display: flex;
  325. flex-direction: column;
  326. &.full {
  327. top: 0;
  328. }
  329. }
  330. .debugger-tab-tabs {
  331. position: relative;
  332. display: flex;
  333. flex-direction: row;
  334. align-items: center;
  335. border-bottom: 1px solid #f6f6f6;
  336. height: 70rpx;
  337. .tab {
  338. padding: 6rpx 12rpx;
  339. border-right: 1px solid #f1f1f1;
  340. &.active {
  341. .text {
  342. font-weight: bold;
  343. color: #007AFF;
  344. }
  345. }
  346. .text {
  347. font-size: 34rpx;
  348. }
  349. }
  350. }
  351. .debugger-tab-area {
  352. position: absolute;
  353. top: 70rpx;
  354. right: 0;
  355. bottom: 0;
  356. left: 0;
  357. .view {
  358. position: absolute;
  359. top: 0;
  360. right: 0;
  361. bottom: 0;
  362. left: 0;
  363. }
  364. }
  365. .head-area {
  366. display: flex;
  367. padding: 10rpx;
  368. flex-direction: row;
  369. align-items: center;
  370. justify-content: flex-start;
  371. }
  372. .head-text {
  373. font-size: 28rpx;
  374. }
  375. .tool-button {
  376. width: 130rpx;
  377. height: 60rpx;
  378. font-size: 26rpx;
  379. margin-left: 10rpx;
  380. }
  381. .console-item {
  382. display: flex;
  383. flex-direction: row;
  384. flex-wrap: wrap;
  385. align-items: center;
  386. border-bottom: 1px solid #f6f6f6;
  387. padding: 0rpx 10rpx;
  388. .time {
  389. font-size: 30rpx;
  390. color: #999;
  391. margin-right: 10rpx;
  392. }
  393. }
  394. .round {
  395. width: 32rpx;
  396. height: 32rpx;
  397. border-radius: 16rpx;
  398. margin-right: 10rpx;
  399. &.red, &.error {
  400. background-color: #f96800;
  401. }
  402. &.warning {
  403. background-color: #f9c802;
  404. }
  405. &.success {
  406. background-color: #64ca10;
  407. }
  408. }
  409. </style>