vite-uni-dev-tool 0.0.48 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/README.md +20 -0
  2. package/dist/const.cjs +1 -0
  3. package/dist/const.d.ts +78 -161
  4. package/dist/const.d.ts.map +1 -1
  5. package/dist/const.js +1 -47
  6. package/dist/core-shared.d.ts +44 -0
  7. package/dist/core-shared.d.ts.map +1 -0
  8. package/dist/core-shared.js +1 -0
  9. package/dist/core.d.ts +2 -40
  10. package/dist/core.d.ts.map +1 -1
  11. package/dist/core.js +4 -159
  12. package/dist/i18n/index.cjs +1 -0
  13. package/dist/i18n/index.d.ts +9 -0
  14. package/dist/i18n/index.d.ts.map +1 -0
  15. package/dist/i18n/index.js +1 -0
  16. package/dist/i18n/instance.cjs +1 -0
  17. package/dist/i18n/instance.d.ts +15 -0
  18. package/dist/i18n/instance.d.ts.map +1 -0
  19. package/dist/i18n/instance.js +1 -0
  20. package/dist/i18n/locales/en.cjs +1 -0
  21. package/dist/i18n/locales/en.d.ts +470 -0
  22. package/dist/i18n/locales/en.d.ts.map +1 -0
  23. package/dist/i18n/locales/en.js +1 -0
  24. package/dist/i18n/locales/zh-Hans.cjs +1 -0
  25. package/dist/i18n/locales/zh-Hans.d.ts +476 -0
  26. package/dist/i18n/locales/zh-Hans.d.ts.map +1 -0
  27. package/dist/i18n/locales/zh-Hans.js +1 -0
  28. package/dist/index.cjs +1 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +1 -1
  31. package/dist/modules/devConsole/index.cjs +4 -0
  32. package/dist/{devConsole → modules/devConsole}/index.d.ts +1 -1
  33. package/dist/modules/devConsole/index.d.ts.map +1 -0
  34. package/dist/modules/devConsole/index.js +4 -0
  35. package/dist/modules/devEvent/index.cjs +5 -0
  36. package/dist/modules/devEvent/index.d.ts +115 -0
  37. package/dist/modules/devEvent/index.d.ts.map +1 -0
  38. package/dist/modules/devEvent/index.js +5 -0
  39. package/dist/modules/devIntercept/index.cjs +13 -0
  40. package/dist/modules/devIntercept/index.d.ts +71 -0
  41. package/dist/modules/devIntercept/index.d.ts.map +1 -0
  42. package/dist/modules/devIntercept/index.js +13 -0
  43. package/dist/modules/devStore/index.cjs +1 -0
  44. package/dist/modules/devStore/index.d.ts +159 -0
  45. package/dist/modules/devStore/index.d.ts.map +1 -0
  46. package/dist/modules/devStore/index.js +1 -0
  47. package/dist/modules/devToolInfo/index.cjs +1 -0
  48. package/dist/modules/devToolInfo/index.d.ts +27 -0
  49. package/dist/modules/devToolInfo/index.d.ts.map +1 -0
  50. package/dist/modules/devToolInfo/index.js +1 -0
  51. package/dist/plugins/uniDevTool/transform/transformApp.cjs +44 -0
  52. package/dist/plugins/uniDevTool/transform/transformApp.d.ts.map +1 -1
  53. package/dist/plugins/uniDevTool/transform/transformApp.js +17 -17
  54. package/dist/plugins/uniDevTool/transform/transformMain.cjs +3 -0
  55. package/dist/plugins/uniDevTool/transform/transformMain.d.ts.map +1 -1
  56. package/dist/plugins/uniDevTool/transform/transformMain.js +3 -3
  57. package/dist/plugins/uniDevTool/transform/transformVue.cjs +41 -0
  58. package/dist/plugins/uniDevTool/transform/transformVue.d.ts +1 -2
  59. package/dist/plugins/uniDevTool/transform/transformVue.d.ts.map +1 -1
  60. package/dist/plugins/uniDevTool/transform/transformVue.js +32 -19
  61. package/dist/plugins/uniDevTool/uniDevTool.cjs +5 -0
  62. package/dist/plugins/uniDevTool/uniDevTool.d.ts +3 -11
  63. package/dist/plugins/uniDevTool/uniDevTool.d.ts.map +1 -1
  64. package/dist/plugins/uniDevTool/uniDevTool.js +3 -3
  65. package/dist/plugins/uniGlobalComponents/uniGlobalComponents.cjs +19 -0
  66. package/dist/plugins/uniGlobalComponents/uniGlobalComponents.d.ts.map +1 -1
  67. package/dist/plugins/uniGlobalComponents/uniGlobalComponents.js +11 -19
  68. package/dist/plugins/uniParseStock/index.d.ts +10 -0
  69. package/dist/plugins/uniParseStock/index.d.ts.map +1 -0
  70. package/dist/plugins/utils/index.cjs +2 -0
  71. package/dist/plugins/utils/index.d.ts +1 -3
  72. package/dist/plugins/utils/index.d.ts.map +1 -1
  73. package/dist/plugins/utils/index.js +2 -2
  74. package/dist/shims-uni.d.ts +140 -0
  75. package/dist/type.d.ts +174 -16
  76. package/dist/type.d.ts.map +1 -1
  77. package/dist/utils/array.cjs +1 -0
  78. package/dist/utils/array.d.ts.map +1 -1
  79. package/dist/utils/array.js +1 -12
  80. package/dist/utils/date.cjs +1 -0
  81. package/dist/utils/date.d.ts.map +1 -1
  82. package/dist/utils/date.js +1 -59
  83. package/dist/utils/file.cjs +1 -0
  84. package/dist/utils/file.d.ts.map +1 -1
  85. package/dist/utils/file.js +1 -85
  86. package/dist/utils/function.cjs +1 -0
  87. package/dist/utils/function.d.ts +13 -0
  88. package/dist/utils/function.d.ts.map +1 -1
  89. package/dist/utils/function.js +1 -68
  90. package/dist/utils/index.cjs +1 -0
  91. package/dist/utils/index.d.ts.map +1 -1
  92. package/dist/utils/index.js +1 -63
  93. package/dist/utils/ip.cjs +1 -0
  94. package/dist/utils/ip.d.ts +1 -1
  95. package/dist/utils/ip.d.ts.map +1 -1
  96. package/dist/utils/ip.js +1 -45
  97. package/dist/utils/language.cjs +1 -0
  98. package/dist/utils/language.d.ts +2 -1
  99. package/dist/utils/language.d.ts.map +1 -1
  100. package/dist/utils/language.js +1 -63
  101. package/dist/utils/object.cjs +1 -0
  102. package/dist/utils/object.d.ts +4 -5
  103. package/dist/utils/object.d.ts.map +1 -1
  104. package/dist/utils/object.js +1 -136
  105. package/dist/utils/openLink.cjs +1 -0
  106. package/dist/utils/openLink.d.ts.map +1 -1
  107. package/dist/utils/openLink.js +1 -28
  108. package/dist/utils/page.cjs +1 -0
  109. package/dist/utils/page.d.ts.map +1 -1
  110. package/dist/utils/page.js +1 -7
  111. package/dist/utils/platform.cjs +1 -0
  112. package/dist/utils/platform.d.ts.map +1 -1
  113. package/dist/utils/platform.js +1 -17
  114. package/dist/utils/string.cjs +1 -0
  115. package/dist/utils/string.d.ts.map +1 -1
  116. package/dist/utils/string.js +1 -114
  117. package/dist/utils/utils.cjs +1 -0
  118. package/dist/utils/utils.d.ts +1 -1
  119. package/dist/utils/utils.d.ts.map +1 -1
  120. package/dist/utils/utils.js +1 -126
  121. package/dist/v3/AppTransition/index.vue +170 -0
  122. package/dist/v3/AutoSizer/index.vue +4 -5
  123. package/dist/v3/AutoSizer/index1.vue +4 -6
  124. package/dist/v3/AutoSizer/utils.ts +1 -1
  125. package/dist/v3/CaptureScreen/index.vue +19 -8
  126. package/dist/v3/CircularButton/index.vue +64 -13
  127. package/dist/v3/ConsoleList/ConsoleItem.vue +56 -5
  128. package/dist/v3/ConsoleList/RunJSInput.vue +10 -6
  129. package/dist/v3/ConsoleList/index.vue +51 -35
  130. package/dist/v3/CustomSwiper/CustomSwiperItem.vue +49 -0
  131. package/dist/v3/CustomSwiper/index.vue +104 -0
  132. package/dist/v3/DevTool/fps-collector.render.ts +148 -0
  133. package/dist/v3/DevTool/index.vue +209 -102
  134. package/dist/v3/DevToolButton/index.vue +40 -59
  135. package/dist/v3/DevToolTitle/index.vue +4 -1
  136. package/dist/v3/DevToolWindow/DevToolOverlay.vue +182 -0
  137. package/dist/v3/DevToolWindow/const.ts +47 -69
  138. package/dist/v3/DevToolWindow/hooks/dataUtils.ts +48 -0
  139. package/dist/v3/DevToolWindow/hooks/useDevToolData.ts +338 -0
  140. package/dist/v3/DevToolWindow/hooks/useDevToolHandlers.ts +549 -0
  141. package/dist/v3/DevToolWindow/hooks/useDevToolOverlay.ts +184 -0
  142. package/dist/v3/DevToolWindow/index.css +89 -0
  143. package/dist/v3/DevToolWindow/index.vue +800 -1450
  144. package/dist/v3/DraggableContainer/index.vue +456 -0
  145. package/dist/v3/ElEvent/ElEventItem.vue +4 -3
  146. package/dist/v3/ElEvent/index.vue +26 -9
  147. package/dist/v3/Empty/index.vue +1 -0
  148. package/dist/v3/FilterInput/index.vue +8 -22
  149. package/dist/v3/FilterSelect/index.vue +37 -24
  150. package/dist/v3/Instance/components/InstanceTreeNode.vue +265 -0
  151. package/dist/v3/Instance/flatten.ts +226 -0
  152. package/dist/v3/Instance/index.vue +94 -0
  153. package/dist/v3/Instance/registry.ts +49 -0
  154. package/dist/v3/Instance/transformTree.ts +375 -0
  155. package/dist/v3/Instance/transformTreeCtx.ts +268 -0
  156. package/dist/v3/{InstanceTree → Instance}/typing.d.ts +15 -2
  157. package/dist/v3/InstanceDetail/index.vue +433 -44
  158. package/dist/v3/JsonDetail/index.vue +12 -8
  159. package/dist/v3/JsonPretty/components/Brackets/index.vue +1 -0
  160. package/dist/v3/JsonPretty/components/Carets/index.vue +2 -1
  161. package/dist/v3/JsonPretty/components/CheckController/index.vue +26 -15
  162. package/dist/v3/JsonPretty/components/TreeNode/index.vue +42 -20
  163. package/dist/v3/JsonPretty/index.vue +60 -37
  164. package/dist/v3/JsonPretty/utils/index.ts +41 -44
  165. package/dist/v3/MovableContainer/index.vue +89 -0
  166. package/dist/v3/NFCList/NFCItem.vue +14 -14
  167. package/dist/v3/NFCList/NFCTool.vue +99 -81
  168. package/dist/v3/NFCList/index.vue +14 -10
  169. package/dist/v3/NetworkList/InterceptConfig.vue +154 -364
  170. package/dist/v3/NetworkList/InterceptItem.vue +14 -6
  171. package/dist/v3/NetworkList/NetworkDetail.vue +34 -29
  172. package/dist/v3/NetworkList/NetworkIntercept.vue +11 -8
  173. package/dist/v3/NetworkList/NetworkItem.vue +27 -11
  174. package/dist/v3/NetworkList/NetworkSend.vue +132 -290
  175. package/dist/v3/NetworkList/hooks/useNetworkForm.ts +86 -0
  176. package/dist/v3/NetworkList/index.vue +32 -24
  177. package/dist/v3/NetworkList/utils.ts +101 -0
  178. package/dist/v3/Performance/index.vue +495 -0
  179. package/dist/v3/Performance/modules/PerformanceMetrics.vue +153 -0
  180. package/dist/v3/Performance/modules/PerformanceWidget.vue +249 -0
  181. package/dist/v3/Performance/modules/usePerformanceChart.ts +460 -0
  182. package/dist/v3/Performance/modules/usePerformanceData.ts +258 -0
  183. package/dist/v3/Pick/index.vue +322 -0
  184. package/dist/v3/PiniaList/index.vue +38 -17
  185. package/dist/v3/RouteList/index.vue +32 -15
  186. package/dist/v3/RunJS/index.vue +30 -10
  187. package/dist/v3/ScanCodeList/ScanCodeItem.vue +2 -9
  188. package/dist/v3/ScanCodeList/index.vue +12 -9
  189. package/dist/v3/SettingButton/index.vue +45 -0
  190. package/dist/v3/SettingList/index.css +120 -0
  191. package/dist/v3/SettingList/index.vue +96 -537
  192. package/dist/v3/SettingList/modules/SettingDevTool.vue +208 -0
  193. package/dist/v3/SettingList/modules/SettingInfo.vue +119 -0
  194. package/dist/v3/SettingList/modules/SettingLanguage.vue +74 -0
  195. package/dist/v3/SettingList/modules/SettingLog.vue +230 -0
  196. package/dist/v3/SettingList/modules/SettingNetwork.vue +120 -0
  197. package/dist/v3/SettingList/modules/SettingTheme.vue +312 -0
  198. package/dist/v3/SourceCode/Line.vue +15 -2
  199. package/dist/v3/SourceCode/index.vue +25 -24
  200. package/dist/v3/SourceCode/parseCode.ts +114 -56
  201. package/dist/v3/StorageList/index.vue +33 -33
  202. package/dist/v3/Tabs/index.vue +31 -28
  203. package/dist/v3/Tag/index.vue +39 -20
  204. package/dist/v3/TransferList/TransferDetail.vue +268 -0
  205. package/dist/v3/TransferList/TransferItem.vue +125 -0
  206. package/dist/v3/TransferList/index.vue +181 -0
  207. package/dist/v3/UniEvent/UniEventItem.vue +1 -0
  208. package/dist/v3/UniEvent/index.vue +28 -29
  209. package/dist/v3/{VirtualListPro → VirtualList}/AutoSize.vue +1 -1
  210. package/dist/v3/VirtualList/index.vue +382 -82
  211. package/dist/v3/VuexList/index.vue +38 -17
  212. package/dist/v3/WebSocket/WebSocketDetail.vue +142 -80
  213. package/dist/v3/WebSocket/WebSocketItem.vue +10 -4
  214. package/dist/v3/WebSocket/index.vue +44 -30
  215. package/dist/v3/hooks/useNFC/index.ts +6 -6
  216. package/dist/v3/hooks/useNFC/typing.d.ts +2 -2
  217. package/dist/v3/hooks/useNFC/useNFCAndroid.ts +215 -626
  218. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.ts +54 -85
  219. package/dist/v3/hooks/useNFC/utils.ts +3 -3
  220. package/dist/v3/hooks/useRequest/index.ts +2 -2
  221. package/dist/v3/hooks/useScanCode/index.ts +10 -8
  222. package/dist/v3/styles/theme.css +290 -0
  223. package/dist/v3/styles/theme.ts +12 -0
  224. package/package.json +25 -5
  225. package/dist/devConsole/index.d.ts.map +0 -1
  226. package/dist/devConsole/index.js +0 -273
  227. package/dist/devEvent/index.d.ts +0 -328
  228. package/dist/devEvent/index.d.ts.map +0 -1
  229. package/dist/devEvent/index.js +0 -697
  230. package/dist/devEventBus/index.d.ts +0 -42
  231. package/dist/devEventBus/index.d.ts.map +0 -1
  232. package/dist/devEventBus/index.js +0 -70
  233. package/dist/devIntercept/index.d.ts +0 -281
  234. package/dist/devIntercept/index.d.ts.map +0 -1
  235. package/dist/devIntercept/index.js +0 -949
  236. package/dist/devRunJS/index.d.ts +0 -67
  237. package/dist/devRunJS/index.d.ts.map +0 -1
  238. package/dist/devStore/index.d.ts +0 -199
  239. package/dist/devStore/index.d.ts.map +0 -1
  240. package/dist/devStore/index.js +0 -562
  241. package/dist/devToolInfo/index.d.ts +0 -17
  242. package/dist/devToolInfo/index.d.ts.map +0 -1
  243. package/dist/devToolInfo/index.js +0 -15
  244. package/dist/v3/AutoSizer/utils.d.ts +0 -5
  245. package/dist/v3/AutoSizer/utils.d.ts.map +0 -1
  246. package/dist/v3/ConsoleList/staticTips.d.ts +0 -13
  247. package/dist/v3/ConsoleList/staticTips.d.ts.map +0 -1
  248. package/dist/v3/DevToolWindow/const.d.ts +0 -46
  249. package/dist/v3/DevToolWindow/const.d.ts.map +0 -1
  250. package/dist/v3/InstanceTree/components/InstanceTreeNode.vue +0 -81
  251. package/dist/v3/InstanceTree/flatten.d.ts +0 -10
  252. package/dist/v3/InstanceTree/flatten.d.ts.map +0 -1
  253. package/dist/v3/InstanceTree/flatten.ts +0 -75
  254. package/dist/v3/InstanceTree/index.vue +0 -51
  255. package/dist/v3/InstanceTree/transformTree.d.ts +0 -17
  256. package/dist/v3/InstanceTree/transformTree.d.ts.map +0 -1
  257. package/dist/v3/InstanceTree/transformTree.ts +0 -237
  258. package/dist/v3/JsonPretty/hooks/useClipboard.d.ts +0 -4
  259. package/dist/v3/JsonPretty/hooks/useClipboard.d.ts.map +0 -1
  260. package/dist/v3/JsonPretty/hooks/useError.d.ts +0 -8
  261. package/dist/v3/JsonPretty/hooks/useError.d.ts.map +0 -1
  262. package/dist/v3/JsonPretty/type.d.ts +0 -94
  263. package/dist/v3/JsonPretty/type.d.ts.map +0 -1
  264. package/dist/v3/JsonPretty/utils/index.d.ts +0 -10
  265. package/dist/v3/JsonPretty/utils/index.d.ts.map +0 -1
  266. package/dist/v3/NFCList/const.d.ts +0 -13
  267. package/dist/v3/NFCList/const.d.ts.map +0 -1
  268. package/dist/v3/NetworkList/const.d.ts +0 -5
  269. package/dist/v3/NetworkList/const.d.ts.map +0 -1
  270. package/dist/v3/SourceCode/parseCode.d.ts +0 -27
  271. package/dist/v3/SourceCode/parseCode.d.ts.map +0 -1
  272. package/dist/v3/UploadList/UploadDetail.vue +0 -255
  273. package/dist/v3/UploadList/UploadItem.vue +0 -122
  274. package/dist/v3/UploadList/index.vue +0 -125
  275. package/dist/v3/VirtualListPro/index.vue +0 -229
  276. package/dist/v3/hooks/useContainerStyle.d.ts +0 -15
  277. package/dist/v3/hooks/useContainerStyle.d.ts.map +0 -1
  278. package/dist/v3/hooks/useNFC/index.d.ts +0 -5
  279. package/dist/v3/hooks/useNFC/index.d.ts.map +0 -1
  280. package/dist/v3/hooks/useNFC/useNFCAndroid.d.ts +0 -2
  281. package/dist/v3/hooks/useNFC/useNFCAndroid.d.ts.map +0 -1
  282. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.d.ts +0 -2
  283. package/dist/v3/hooks/useNFC/useNFCMpWeiXin.d.ts.map +0 -1
  284. package/dist/v3/hooks/useNFC/utils.d.ts +0 -95
  285. package/dist/v3/hooks/useNFC/utils.d.ts.map +0 -1
  286. package/dist/v3/hooks/useRequest/index.d.ts +0 -126
  287. package/dist/v3/hooks/useRequest/index.d.ts.map +0 -1
  288. package/dist/v3/hooks/useRequest/utils.d.ts +0 -35
  289. package/dist/v3/hooks/useRequest/utils.d.ts.map +0 -1
  290. package/dist/v3/hooks/useScanCode/index.d.ts +0 -36
  291. package/dist/v3/hooks/useScanCode/index.d.ts.map +0 -1
  292. /package/dist/v3/{VirtualListPro → VirtualList}/readme.md +0 -0
@@ -0,0 +1,258 @@
1
+ import { ref } from 'vue';
2
+ import { MSG_TYPE } from '../../../const';
3
+ import { raf, caf } from '../../../utils';
4
+
5
+ const fps = ref(0);
6
+ const cpuLoad = ref(0);
7
+ const memory = ref(0);
8
+
9
+ const fpsHistory = ref<number[]>([]);
10
+ const cpuHistory = ref<number[]>([]);
11
+ const memoryHistory = ref<number[]>([]);
12
+ const timeHistory = ref<number[]>([]); // 记录时间戳
13
+ const longTasksHistory = ref<{ ts: number; duration: number; type?: string }[]>(
14
+ [],
15
+ ); // 记录长任务记录
16
+ const displayMaxScale = ref(60);
17
+ const lastUpdateTs = ref(Date.now()); // 记录最后一次更新时间点
18
+ let animationId: number | null = null;
19
+ let logicMonitorTimer: any = null;
20
+
21
+ let heartbeatTimer: any = null;
22
+ let metricsHandler: any = null;
23
+
24
+ const performanceMonitorEnabled = ref(false);
25
+
26
+ export function usePerformanceData() {
27
+ function clearData() {
28
+ fpsHistory.value = [];
29
+ cpuHistory.value = [];
30
+ memoryHistory.value = [];
31
+ timeHistory.value = [];
32
+ longTasksHistory.value = [];
33
+ lastUpdateTs.value = Date.now();
34
+ }
35
+
36
+ // 逻辑线程监测
37
+ function startLogicMonitor() {
38
+ if (logicMonitorTimer) return;
39
+ let lastTime = Date.now();
40
+ logicMonitorTimer = setInterval(() => {
41
+ const now = Date.now();
42
+ const delta = now - lastTime;
43
+
44
+ // 这里的 20ms 是预期周期。如果有偏差,说明逻辑线程繁忙
45
+ // 1. 计算负载估算 (0-100)
46
+ // 偏差超过 5ms 开始计算负载,超过 80ms 认为 100% 负载
47
+ const drift = Math.max(0, delta - 20);
48
+ const estimatedLoad = Math.min(100, Math.round((drift / 60) * 100));
49
+ // 平滑处理
50
+ cpuLoad.value = Math.round(cpuLoad.value * 0.7 + estimatedLoad * 0.3);
51
+
52
+ // 2. 这里的 100ms 实际上包含了 20ms 的采样周期,如果偏差超过 80ms 则认为逻辑线程阻塞
53
+ if (delta > 100) {
54
+ longTasksHistory.value = [
55
+ ...longTasksHistory.value,
56
+ { ts: now, duration: delta, type: 'Logic' },
57
+ ].slice(-20);
58
+ }
59
+ lastTime = now;
60
+ }, 20); // 高频采样以获得更好精度
61
+ }
62
+
63
+ function stopLogicMonitor() {
64
+ if (logicMonitorTimer) {
65
+ clearInterval(logicMonitorTimer);
66
+ logicMonitorTimer = null;
67
+ }
68
+ }
69
+
70
+ function initData(points: number) {
71
+ const now = Date.now();
72
+ // 如果已经有数据且长度足够,不需要重复初始化
73
+ if (fpsHistory.value.length >= points) return;
74
+
75
+ const needed = points - fpsHistory.value.length;
76
+
77
+ // 如果是第一次初始化,填充过去的虚拟时间点
78
+ if (fpsHistory.value.length === 0) {
79
+ fpsHistory.value = new Array(points).fill(0);
80
+ cpuHistory.value = new Array(points).fill(0);
81
+ memoryHistory.value = new Array(points).fill(0);
82
+ timeHistory.value = Array.from(
83
+ { length: points },
84
+ (_, i) => now - (points - 1 - i) * 1000,
85
+ );
86
+ } else {
87
+ // 如果是扩容,向前(左侧)追加 0 点数据
88
+ const fillFps = new Array(needed).fill(0);
89
+ const fillCpu = new Array(needed).fill(0);
90
+ const fillMem = new Array(needed).fill(0);
91
+ const firstTs = timeHistory.value[0];
92
+ const fillTime = Array.from(
93
+ { length: needed },
94
+ (_, i) => firstTs - (needed - i) * 1000,
95
+ );
96
+
97
+ fpsHistory.value = [...fillFps, ...fpsHistory.value];
98
+ cpuHistory.value = [...fillCpu, ...cpuHistory.value];
99
+ memoryHistory.value = [...fillMem, ...memoryHistory.value];
100
+ timeHistory.value = [...fillTime, ...timeHistory.value];
101
+ }
102
+
103
+ lastUpdateTs.value = now;
104
+ }
105
+
106
+ function startScaleAnimation(target: number) {
107
+ if (animationId) {
108
+ caf(animationId);
109
+ }
110
+
111
+ const animate = () => {
112
+ const diff = target - displayMaxScale.value;
113
+ if (Math.abs(diff) < 0.5) {
114
+ displayMaxScale.value = target;
115
+ animationId = null;
116
+ return;
117
+ }
118
+ displayMaxScale.value += diff * 0.15;
119
+ animationId = raf(animate);
120
+ };
121
+ animate();
122
+ }
123
+
124
+ function updateMetrics(
125
+ data:
126
+ | {
127
+ fps: number;
128
+ load: number;
129
+ longTasks?: { ts: number; duration: number; type?: string }[];
130
+ }
131
+ | {
132
+ fps: number;
133
+ load: number;
134
+ longTasks?: { ts: number; duration: number; type?: string }[];
135
+ }[],
136
+ ) {
137
+ const items = Array.isArray(data) ? data : [data];
138
+ if (items.length === 0) return;
139
+
140
+ const now = Date.now();
141
+ lastUpdateTs.value = now;
142
+
143
+ items.forEach((item, index) => {
144
+ fps.value = item.fps;
145
+ cpuLoad.value = item.load;
146
+
147
+ // 如果有长任务,记录下来(保持最近 20 条)
148
+ if (item.longTasks && item.longTasks.length > 0) {
149
+ longTasksHistory.value = [
150
+ ...longTasksHistory.value,
151
+ ...item.longTasks,
152
+ ].slice(-20);
153
+ }
154
+
155
+ // 安全访问 performance 对象(安卓平台可能不存在)
156
+ let mem = 0;
157
+ if (typeof performance !== 'undefined' && (performance as any).memory) {
158
+ mem = Math.round(
159
+ (performance as any).memory.usedJSHeapSize / 1024 / 1024,
160
+ );
161
+ memory.value = mem;
162
+ }
163
+
164
+ fpsHistory.value.shift();
165
+ fpsHistory.value.push(item.fps);
166
+ cpuHistory.value.shift();
167
+ cpuHistory.value.push(item.load);
168
+ memoryHistory.value.shift();
169
+ memoryHistory.value.push(mem);
170
+
171
+ // 优先级:由于 renderjs 传来的采样点自带时间戳,优先使用它
172
+ // 如果没有,则使用 logic 层当前生成的 now 向前平摊
173
+ const eventTs = (item as any).ts;
174
+ const ts =
175
+ eventTs !== undefined
176
+ ? Math.min(now, eventTs)
177
+ : now - (items.length - 1 - index) * 1000;
178
+
179
+ timeHistory.value.shift();
180
+ timeHistory.value.push(ts);
181
+ });
182
+
183
+ const maxVal = Math.max(...fpsHistory.value, 0);
184
+ let targetScale = 60;
185
+ if (maxVal > 144) targetScale = 240;
186
+ else if (maxVal > 120) targetScale = 144;
187
+ else if (maxVal > 90) targetScale = 120;
188
+ else if (maxVal > 60) targetScale = 100;
189
+
190
+ startScaleAnimation(targetScale);
191
+ }
192
+
193
+ function startHeartbeat() {
194
+ if (metricsHandler || heartbeatTimer) return;
195
+
196
+ metricsHandler = (data: any) => updateMetrics(data);
197
+
198
+ uni.$on(MSG_TYPE.PERF_METRICS, metricsHandler);
199
+ startLogicMonitor(); // 启动逻辑层监测
200
+
201
+ heartbeatTimer = setInterval(() => {
202
+ const now = Date.now();
203
+ // 如果超过 2 秒没收到外部(renderjs)数据,说明处于非 H5/App 环境,切换到降级模式
204
+ if (now - lastUpdateTs.value > 2000) {
205
+ // 估算逻辑层负载:我们没有真实的渲染 FPS,但可以展示逻辑层的心跳健康度
206
+ // 这在小程序等平台非常有意义
207
+ updateMetrics({
208
+ fps: 0, // 非 H5 无法获取准确渲染帧率
209
+ load: cpuLoad.value || 0, // 这里的 load 会由 startLogicMonitor 的逻辑更新(如果有的化)
210
+ });
211
+ }
212
+
213
+ if (timeHistory.value.length > 0) {
214
+ if (now - lastUpdateTs.value < 800) return;
215
+ updateMetrics({ fps: fps.value, load: cpuLoad.value });
216
+ }
217
+ }, 1000);
218
+ }
219
+
220
+ function stopHeartbeat() {
221
+ if (metricsHandler) {
222
+ uni.$off(MSG_TYPE.PERF_METRICS, metricsHandler);
223
+ metricsHandler = null;
224
+ }
225
+ stopLogicMonitor(); // 停止逻辑层监测
226
+ if (heartbeatTimer) {
227
+ clearInterval(heartbeatTimer);
228
+ heartbeatTimer = null;
229
+ }
230
+ // clean animation
231
+ if (animationId) {
232
+ caf(animationId);
233
+ animationId = null;
234
+ }
235
+ clearData();
236
+ }
237
+
238
+ return {
239
+ fps,
240
+ cpuLoad,
241
+ memory,
242
+ fpsHistory,
243
+ cpuHistory,
244
+ memoryHistory,
245
+ timeHistory,
246
+ longTasksHistory,
247
+ displayMaxScale,
248
+ lastUpdateTs,
249
+ performanceMonitorEnabled,
250
+ initData,
251
+ updateMetrics,
252
+ startHeartbeat,
253
+ stopHeartbeat,
254
+ startLogicMonitor,
255
+ stopLogicMonitor,
256
+ clearData,
257
+ };
258
+ }
@@ -0,0 +1,322 @@
1
+ <template>
2
+ <view class="pick-wrapper" :style="customStyle">
3
+ <!-- Trigger Area -->
4
+ <view
5
+ :class="`pick-trigger ${!modelValue ? 'pick-trigger-placeholder' : ''}`"
6
+ @click="onOpenPick">
7
+ <text class="pick-trigger-text">
8
+ {{ label || placeholder || '请选择' }}
9
+ </text>
10
+ <view class="pick-handle">
11
+ <view
12
+ v-if="allowClear && modelValue"
13
+ class="pick-clear"
14
+ @click.stop="onClear">
15
+ ×
16
+ </view>
17
+ <view :class="['pick-arrow', isActive ? 'pick-arrow-active' : '']">
18
+ >
19
+ </view>
20
+ </view>
21
+ </view>
22
+
23
+ <!-- Popup Modal -->
24
+ <view class="pick-mask" v-if="isActive" @click="onClosePick">
25
+ <view class="pick-modal" @click.stop>
26
+ <!-- Header -->
27
+ <view class="pick-header">
28
+ <text class="pick-title">{{ placeholder || '请选择' }}</text>
29
+ <view class="pick-close" @click="onClosePick">×</view>
30
+ </view>
31
+
32
+ <!-- Search -->
33
+ <view class="pick-search" v-if="!readonly">
34
+ <input
35
+ class="pick-search-input"
36
+ :value="searchText"
37
+ placeholder="搜索..."
38
+ @input="debounceInput"
39
+ :focus="isActive" />
40
+ </view>
41
+
42
+ <!-- List -->
43
+ <scroll-view scroll-y class="pick-list">
44
+ <view
45
+ v-for="item in filteredOptions"
46
+ :key="item.value"
47
+ :class="[
48
+ 'pick-item',
49
+ item.value === modelValue ? 'pick-item-active' : '',
50
+ ]"
51
+ @click="onSelect(item)">
52
+ <text class="pick-item-text">{{ item.label }}</text>
53
+ <text v-if="item.value === modelValue" class="pick-item-check">
54
+
55
+ </text>
56
+ </view>
57
+ <view v-if="filteredOptions.length === 0" class="pick-empty">
58
+ 暂无数据
59
+ </view>
60
+ </scroll-view>
61
+ </view>
62
+ </view>
63
+ </view>
64
+ </template>
65
+
66
+ <script lang="ts" setup>
67
+ import { debounce } from '../../utils';
68
+ import { ref, computed } from 'vue';
69
+
70
+ const props = defineProps<{
71
+ placeholder?: string;
72
+ readonly?: boolean;
73
+ allowClear?: boolean;
74
+ options?: { label: string; value: any }[];
75
+ customStyle?: Record<string, any> | string;
76
+ }>();
77
+
78
+ const modelValue = defineModel<string>('modelValue');
79
+
80
+ const emit = defineEmits<{
81
+ (e: 'search', value: string): void;
82
+ (e: 'openSearch', value: boolean): void;
83
+ (e: 'change', value: { label: string; value: any }): void;
84
+ }>();
85
+
86
+ const isActive = ref(false);
87
+ const searchText = ref('');
88
+
89
+ // Computed label for the trigger
90
+ const label = computed(() => {
91
+ return (
92
+ props.options?.find((item) => item.value === modelValue.value)?.label ??
93
+ modelValue.value
94
+ );
95
+ });
96
+
97
+ const filteredOptions = computed(() => {
98
+ if (!searchText.value) return props.options || [];
99
+ const lowerSearch = searchText.value.toLowerCase();
100
+ return (props.options || []).filter(
101
+ (item) => item.label && item.label.toLowerCase().includes(lowerSearch),
102
+ );
103
+ });
104
+
105
+ function onOpenPick() {
106
+ isActive.value = true;
107
+ searchText.value = '';
108
+ emit('openSearch', true);
109
+ }
110
+
111
+ function onClosePick() {
112
+ isActive.value = false;
113
+ emit('openSearch', false);
114
+ }
115
+
116
+ function onInput(e: any) {
117
+ const value = e.detail?.value ?? e.target?.value;
118
+ searchText.value = value;
119
+ emit('search', value);
120
+ }
121
+
122
+ const debounceInput = debounce(onInput, 300);
123
+
124
+ function onSelect(item: { label: string; value: any }) {
125
+ modelValue.value = item.value;
126
+ emit('change', item);
127
+ onClosePick();
128
+ }
129
+
130
+ function onClear() {
131
+ modelValue.value = '';
132
+ emit('search', '');
133
+ emit('change', { label: '', value: '' });
134
+ }
135
+ </script>
136
+
137
+ <style scoped>
138
+ .pick-wrapper {
139
+ position: relative;
140
+ width: 100%;
141
+ }
142
+
143
+ .pick-trigger {
144
+ display: flex;
145
+ align-items: center;
146
+ justify-content: space-between;
147
+ width: 100%;
148
+ min-width: 0;
149
+ height: 24px; /* Slightly taller for easier click */
150
+ padding: 0 10px;
151
+ border-radius: 4px;
152
+ border: 1px solid var(--dev-tool-border-color);
153
+ background-color: var(--dev-tool-bg-color);
154
+ transition: all 0.3s;
155
+ box-sizing: border-box;
156
+ cursor: pointer;
157
+ }
158
+
159
+ .pick-trigger:hover {
160
+ border-color: var(--dev-tool-active-color, #409eff);
161
+ }
162
+
163
+ .pick-trigger-placeholder .pick-trigger-text {
164
+ color: var(--dev-tool-text-color-placeholder, #999);
165
+ }
166
+
167
+ .pick-trigger-text {
168
+ flex: 1;
169
+ overflow: hidden;
170
+ text-overflow: ellipsis;
171
+ white-space: nowrap;
172
+ color: var(--dev-tool-text-color);
173
+ }
174
+
175
+ .pick-handle {
176
+ display: flex;
177
+ align-items: center;
178
+ }
179
+
180
+ .pick-arrow {
181
+ padding-left: 4px;
182
+ color: #999;
183
+ font-family: monospace;
184
+ font-weight: bold;
185
+ transform: rotate(90deg);
186
+ transition: transform 0.3s;
187
+ position: relative;
188
+ top: -1px;
189
+ }
190
+
191
+ .pick-arrow-active {
192
+ transform: rotate(-90deg);
193
+ }
194
+
195
+ .pick-clear {
196
+ padding-left: 8px;
197
+ font-size: 16px;
198
+ color: #999;
199
+ }
200
+
201
+ .pick-mask {
202
+ position: fixed;
203
+ inset: 0;
204
+ background-color: rgb(0 0 0 / 40%);
205
+ z-index: 10000;
206
+ display: flex;
207
+ align-items: center;
208
+ justify-content: center;
209
+ backdrop-filter: blur(2px);
210
+ }
211
+
212
+ .pick-modal {
213
+ width: 80%;
214
+ max-width: 400px;
215
+ height: 60vh;
216
+ max-height: 500px;
217
+ background-color: var(--dev-tool-bg-color);
218
+ border-radius: 12px;
219
+ box-shadow: 0 8px 24px rgb(0 0 0 / 15%);
220
+ display: flex;
221
+ flex-direction: column;
222
+ overflow: hidden;
223
+ animation: pick-pop-in 0.2s ease-out;
224
+ }
225
+
226
+ @keyframes pick-pop-in {
227
+ from {
228
+ opacity: 0;
229
+ transform: scale(0.95);
230
+ }
231
+
232
+ to {
233
+ opacity: 1;
234
+ transform: scale(1);
235
+ }
236
+ }
237
+
238
+ .pick-header {
239
+ display: flex;
240
+ align-items: center;
241
+ justify-content: space-between;
242
+ padding: 12px 16px;
243
+ border-bottom: 1px solid var(--dev-tool-border-color);
244
+ }
245
+
246
+ .pick-title {
247
+ font-weight: 600;
248
+ color: var(--dev-tool-text-color);
249
+ }
250
+
251
+ .pick-close {
252
+ font-size: 20px;
253
+ color: #999;
254
+ padding: 4px;
255
+ cursor: pointer;
256
+ }
257
+
258
+ .pick-search {
259
+ padding: 10px 16px;
260
+ border-bottom: 1px solid var(--dev-tool-border-color);
261
+ }
262
+
263
+ .pick-search-input {
264
+ width: 100%;
265
+ height: 36px;
266
+ padding: 0 12px;
267
+ border-radius: 6px;
268
+ background-color: var(--dev-tool-bg2-color, #f5f5f5);
269
+ border: 1px solid transparent;
270
+ box-sizing: border-box;
271
+ color: var(--dev-tool-text-color);
272
+ }
273
+
274
+ .pick-search-input:focus {
275
+ border-color: var(--dev-tool-active-color, #409eff);
276
+ background-color: var(--dev-tool-bg-color);
277
+ }
278
+
279
+ .pick-list {
280
+ flex: 1;
281
+ overflow-y: auto;
282
+ padding: 8px 0;
283
+ }
284
+
285
+ .pick-item {
286
+ display: flex;
287
+ align-items: center;
288
+ justify-content: space-between;
289
+ padding: 12px 16px;
290
+ cursor: pointer;
291
+ transition: background-color 0.2s;
292
+ }
293
+
294
+ .pick-item:hover,
295
+ .pick-item:active {
296
+ background-color: var(--dev-tool-hover-bg-color, rgb(0 0 0 / 5%));
297
+ }
298
+
299
+ .pick-item-active {
300
+ background-color: var(--dev-tool-active-bg-color, rgb(64 158 255 / 10%));
301
+ }
302
+
303
+ .pick-item-active .pick-item-text {
304
+ color: var(--dev-tool-active-color, #409eff);
305
+ font-weight: 500;
306
+ }
307
+
308
+ .pick-item-text {
309
+ color: var(--dev-tool-text-color);
310
+ }
311
+
312
+ .pick-item-check {
313
+ color: var(--dev-tool-active-color, #409eff);
314
+ font-weight: bold;
315
+ }
316
+
317
+ .pick-empty {
318
+ padding: 24px;
319
+ text-align: center;
320
+ color: #999;
321
+ }
322
+ </style>
@@ -1,26 +1,35 @@
1
1
  <template>
2
2
  <view class="pinia-content">
3
- <JsonPretty
4
- editable
5
- showLength
6
- virtual
7
- v-if="showJson"
8
- :data="piniaList"
9
- :theme="theme"
10
- :height="contentHeight - 32 - 32"
11
- :nodeSelectable="() => false"
12
- :pathCollapsible="() => false"
13
- @update:data="onUpdateData"
14
- @nodeClick="onNodeClick"
15
- />
16
- <Empty v-else />
3
+ <view class="pinia-control">
4
+ <DevToolTitle>{{ t('pinia.title') }}</DevToolTitle>
5
+ </view>
6
+ <view class="pinia-json-wrapper">
7
+ <JsonPretty
8
+ editable
9
+ showLength
10
+ virtual
11
+ v-if="showJson"
12
+ :data="piniaList"
13
+ :theme="theme"
14
+ :height="contentHeight - 32 - 32"
15
+ :nodeSelectable="() => false"
16
+ :pathCollapsible="() => false"
17
+ @update:data="onUpdateData"
18
+ @nodeClick="onNodeClick"
19
+ />
20
+ <Empty v-else />
21
+ </view>
17
22
  </view>
18
23
  </template>
19
24
  <script lang="ts" setup>
20
25
  import { computed } from 'vue';
21
26
  import JsonPretty from '../JsonPretty/index.vue';
22
27
  import Empty from '../Empty/index.vue';
28
+ import DevToolTitle from '../DevToolTitle/index.vue';
23
29
  import { getValueByPath } from '../../utils';
30
+ import { useI18n } from '../../i18n';
31
+
32
+ const { t } = useI18n();
24
33
 
25
34
  const props = defineProps<{
26
35
  piniaList: Record<string, any>;
@@ -38,7 +47,7 @@ const showJson = computed(() => {
38
47
  return false;
39
48
  }
40
49
  return true;
41
- } catch (error) {
50
+ } catch (_error) {
42
51
  return false;
43
52
  }
44
53
  });
@@ -64,10 +73,22 @@ function onNodeClick(node: any) {
64
73
  </script>
65
74
  <style scoped>
66
75
  .pinia-content {
67
- padding: 16px;
68
76
  font-size: var(--dev-tool-base-font-size);
69
77
  height: 100%;
70
78
  box-sizing: border-box;
71
- overflow: auto;
79
+ overflow: hidden;
80
+ }
81
+
82
+ .pinia-control {
83
+ display: flex;
84
+ align-items: center;
85
+ padding: 0 16px;
86
+ height: 32px;
87
+ border-bottom: 1px solid var(--dev-tool-border-color);
88
+ box-sizing: border-box;
89
+ }
90
+
91
+ .pinia-json-wrapper {
92
+ padding: 0 16px;
72
93
  }
73
94
  </style>