@linyjs/plugin-docs 0.1.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 (252) hide show
  1. package/README.md +97 -0
  2. package/docs/api-reference/index.md +341 -0
  3. package/docs/best-practices/error-handling.md +462 -0
  4. package/docs/best-practices/naming-conventions.md +495 -0
  5. package/docs/best-practices/performance.md +532 -0
  6. package/docs/best-practices/security.md +620 -0
  7. package/docs/faq.md +323 -0
  8. package/docs/getting-started/first-plugin.md +358 -0
  9. package/docs/getting-started/installation.md +244 -0
  10. package/docs/getting-started/quick-start.md +174 -0
  11. package/docs/guides/client-module.md +598 -0
  12. package/docs/guides/data-persistence.md +536 -0
  13. package/docs/guides/permissions.md +440 -0
  14. package/docs/guides/server-module.md +371 -0
  15. package/docs/guides/ui-slots.md +475 -0
  16. package/docs/migration/v0-to-v1.md +354 -0
  17. package/examples/analytics-plugin/README.md +416 -0
  18. package/examples/analytics-plugin/dist/client/index.d.ts +36 -0
  19. package/examples/analytics-plugin/dist/client/index.js +173 -0
  20. package/examples/analytics-plugin/dist/index.d.ts +64 -0
  21. package/examples/analytics-plugin/dist/index.js +72 -0
  22. package/examples/analytics-plugin/dist/server/index.d.ts +119 -0
  23. package/examples/analytics-plugin/dist/server/index.js +313 -0
  24. package/examples/analytics-plugin/package.json +28 -0
  25. package/examples/analytics-plugin/src/client/index.tsx +410 -0
  26. package/examples/analytics-plugin/src/index.ts +71 -0
  27. package/examples/analytics-plugin/src/server/index.ts +348 -0
  28. package/examples/analytics-plugin/tsconfig.json +21 -0
  29. package/examples/blog-plugin/README.md +316 -0
  30. package/examples/blog-plugin/dist/client/index.d.ts +22 -0
  31. package/examples/blog-plugin/dist/client/index.js +197 -0
  32. package/examples/blog-plugin/dist/server/index.d.ts +5 -0
  33. package/examples/blog-plugin/dist/server/index.js +220 -0
  34. package/examples/blog-plugin/package.json +24 -0
  35. package/examples/blog-plugin/src/client/index.tsx +405 -0
  36. package/examples/blog-plugin/src/server/index.ts +240 -0
  37. package/examples/blog-plugin/tsconfig.json +16 -0
  38. package/examples/hello-world/README.md +101 -0
  39. package/examples/hello-world/dist/client/index.d.ts +5 -0
  40. package/examples/hello-world/dist/client/index.js +80 -0
  41. package/examples/hello-world/dist/server/index.d.ts +5 -0
  42. package/examples/hello-world/dist/server/index.js +38 -0
  43. package/examples/hello-world/node_modules/.package-lock.json +61 -0
  44. package/examples/hello-world/node_modules/@linyjs/client-module-interface/HOOKS_USAGE.md +281 -0
  45. package/examples/hello-world/node_modules/@linyjs/client-module-interface/IMPLEMENTATION_SUMMARY.md +166 -0
  46. package/examples/hello-world/node_modules/@linyjs/client-module-interface/QUICK_REFERENCE.md +130 -0
  47. package/examples/hello-world/node_modules/@linyjs/client-module-interface/README.md +214 -0
  48. package/examples/hello-world/node_modules/@linyjs/client-module-interface/package.json +26 -0
  49. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/application.ts +50 -0
  50. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/comparison-example.tsx +229 -0
  51. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/di.ts +127 -0
  52. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/domain.ts +52 -0
  53. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/hooks-example.tsx +275 -0
  54. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/hooks.ts +175 -0
  55. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/index.ts +87 -0
  56. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/interfaces.ts +117 -0
  57. package/examples/hello-world/node_modules/@linyjs/client-module-interface/src/router.ts +49 -0
  58. package/examples/hello-world/node_modules/@linyjs/client-module-interface/tsconfig.json +10 -0
  59. package/examples/hello-world/node_modules/@linyjs/server-module-interface/package.json +21 -0
  60. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/application.ts +21 -0
  61. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/di.ts +127 -0
  62. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/domain.ts +75 -0
  63. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/index.ts +55 -0
  64. package/examples/hello-world/node_modules/@linyjs/server-module-interface/src/interfaces.ts +58 -0
  65. package/examples/hello-world/node_modules/@linyjs/server-module-interface/tsconfig.json +8 -0
  66. package/examples/hello-world/node_modules/@types/react/LICENSE +21 -0
  67. package/examples/hello-world/node_modules/@types/react/README.md +15 -0
  68. package/examples/hello-world/node_modules/@types/react/canary.d.ts +129 -0
  69. package/examples/hello-world/node_modules/@types/react/compiler-runtime.d.ts +4 -0
  70. package/examples/hello-world/node_modules/@types/react/experimental.d.ts +184 -0
  71. package/examples/hello-world/node_modules/@types/react/global.d.ts +166 -0
  72. package/examples/hello-world/node_modules/@types/react/index.d.ts +4369 -0
  73. package/examples/hello-world/node_modules/@types/react/jsx-dev-runtime.d.ts +33 -0
  74. package/examples/hello-world/node_modules/@types/react/jsx-runtime.d.ts +24 -0
  75. package/examples/hello-world/node_modules/@types/react/package.json +210 -0
  76. package/examples/hello-world/node_modules/@types/react/ts5.0/canary.d.ts +129 -0
  77. package/examples/hello-world/node_modules/@types/react/ts5.0/experimental.d.ts +184 -0
  78. package/examples/hello-world/node_modules/@types/react/ts5.0/global.d.ts +166 -0
  79. package/examples/hello-world/node_modules/@types/react/ts5.0/index.d.ts +4356 -0
  80. package/examples/hello-world/node_modules/@types/react/ts5.0/jsx-dev-runtime.d.ts +33 -0
  81. package/examples/hello-world/node_modules/@types/react/ts5.0/jsx-runtime.d.ts +24 -0
  82. package/examples/hello-world/node_modules/csstype/LICENSE +19 -0
  83. package/examples/hello-world/node_modules/csstype/README.md +291 -0
  84. package/examples/hello-world/node_modules/csstype/index.d.ts +22569 -0
  85. package/examples/hello-world/node_modules/csstype/index.js.flow +6863 -0
  86. package/examples/hello-world/node_modules/csstype/package.json +70 -0
  87. package/examples/hello-world/node_modules/react/LICENSE +21 -0
  88. package/examples/hello-world/node_modules/react/README.md +37 -0
  89. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.development.js +24 -0
  90. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.production.js +16 -0
  91. package/examples/hello-world/node_modules/react/cjs/react-compiler-runtime.profiling.js +16 -0
  92. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.development.js +338 -0
  93. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.production.js +14 -0
  94. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.profiling.js +14 -0
  95. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.react-server.development.js +370 -0
  96. package/examples/hello-world/node_modules/react/cjs/react-jsx-dev-runtime.react-server.production.js +40 -0
  97. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.development.js +352 -0
  98. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.production.js +34 -0
  99. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.profiling.js +34 -0
  100. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.react-server.development.js +370 -0
  101. package/examples/hello-world/node_modules/react/cjs/react-jsx-runtime.react-server.production.js +40 -0
  102. package/examples/hello-world/node_modules/react/cjs/react.development.js +1284 -0
  103. package/examples/hello-world/node_modules/react/cjs/react.production.js +542 -0
  104. package/examples/hello-world/node_modules/react/cjs/react.react-server.development.js +848 -0
  105. package/examples/hello-world/node_modules/react/cjs/react.react-server.production.js +423 -0
  106. package/examples/hello-world/node_modules/react/compiler-runtime.js +14 -0
  107. package/examples/hello-world/node_modules/react/index.js +7 -0
  108. package/examples/hello-world/node_modules/react/jsx-dev-runtime.js +7 -0
  109. package/examples/hello-world/node_modules/react/jsx-dev-runtime.react-server.js +7 -0
  110. package/examples/hello-world/node_modules/react/jsx-runtime.js +7 -0
  111. package/examples/hello-world/node_modules/react/jsx-runtime.react-server.js +7 -0
  112. package/examples/hello-world/node_modules/react/package.json +51 -0
  113. package/examples/hello-world/node_modules/react/react.react-server.js +7 -0
  114. package/examples/hello-world/node_modules/typescript/LICENSE.txt +55 -0
  115. package/examples/hello-world/node_modules/typescript/README.md +50 -0
  116. package/examples/hello-world/node_modules/typescript/SECURITY.md +41 -0
  117. package/examples/hello-world/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
  118. package/examples/hello-world/node_modules/typescript/bin/tsc +2 -0
  119. package/examples/hello-world/node_modules/typescript/bin/tsserver +2 -0
  120. package/examples/hello-world/node_modules/typescript/lib/_tsc.js +133818 -0
  121. package/examples/hello-world/node_modules/typescript/lib/_tsserver.js +659 -0
  122. package/examples/hello-world/node_modules/typescript/lib/_typingsInstaller.js +222 -0
  123. package/examples/hello-world/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
  124. package/examples/hello-world/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
  125. package/examples/hello-world/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
  126. package/examples/hello-world/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
  127. package/examples/hello-world/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
  128. package/examples/hello-world/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
  129. package/examples/hello-world/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
  130. package/examples/hello-world/node_modules/typescript/lib/lib.d.ts +22 -0
  131. package/examples/hello-world/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
  132. package/examples/hello-world/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
  133. package/examples/hello-world/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
  134. package/examples/hello-world/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
  135. package/examples/hello-world/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
  136. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
  137. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
  138. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
  139. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
  140. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
  141. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
  142. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
  143. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
  144. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
  145. package/examples/hello-world/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
  146. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
  147. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
  148. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
  149. package/examples/hello-world/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
  150. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
  151. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
  152. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
  153. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
  154. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
  155. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
  156. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
  157. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
  158. package/examples/hello-world/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
  159. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
  160. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
  161. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
  162. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
  163. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
  164. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
  165. package/examples/hello-world/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
  166. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
  167. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
  168. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
  169. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
  170. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
  171. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
  172. package/examples/hello-world/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
  173. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
  174. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
  175. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
  176. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
  177. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
  178. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
  179. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
  180. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
  181. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
  182. package/examples/hello-world/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
  183. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
  184. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
  185. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
  186. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
  187. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
  188. package/examples/hello-world/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
  189. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
  190. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
  191. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
  192. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
  193. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
  194. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
  195. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
  196. package/examples/hello-world/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
  197. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
  198. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
  199. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
  200. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
  201. package/examples/hello-world/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
  202. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
  203. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
  204. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
  205. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
  206. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
  207. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
  208. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
  209. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
  210. package/examples/hello-world/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
  211. package/examples/hello-world/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
  212. package/examples/hello-world/node_modules/typescript/lib/lib.es6.d.ts +23 -0
  213. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
  214. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
  215. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
  216. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
  217. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
  218. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
  219. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
  220. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
  221. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
  222. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
  223. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
  224. package/examples/hello-world/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
  225. package/examples/hello-world/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
  226. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
  227. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
  228. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
  229. package/examples/hello-world/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
  230. package/examples/hello-world/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
  231. package/examples/hello-world/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
  232. package/examples/hello-world/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
  233. package/examples/hello-world/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
  234. package/examples/hello-world/node_modules/typescript/lib/tsc.js +8 -0
  235. package/examples/hello-world/node_modules/typescript/lib/tsserver.js +8 -0
  236. package/examples/hello-world/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
  237. package/examples/hello-world/node_modules/typescript/lib/tsserverlibrary.js +21 -0
  238. package/examples/hello-world/node_modules/typescript/lib/typesMap.json +497 -0
  239. package/examples/hello-world/node_modules/typescript/lib/typescript.d.ts +11437 -0
  240. package/examples/hello-world/node_modules/typescript/lib/typescript.js +200276 -0
  241. package/examples/hello-world/node_modules/typescript/lib/typingsInstaller.js +8 -0
  242. package/examples/hello-world/node_modules/typescript/lib/watchGuard.js +53 -0
  243. package/examples/hello-world/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
  244. package/examples/hello-world/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
  245. package/examples/hello-world/node_modules/typescript/package.json +120 -0
  246. package/examples/hello-world/package-lock.json +74 -0
  247. package/examples/hello-world/package.json +23 -0
  248. package/examples/hello-world/src/client/index.tsx +110 -0
  249. package/examples/hello-world/src/server/index.ts +42 -0
  250. package/examples/hello-world/tsconfig.json +16 -0
  251. package/package.json +42 -0
  252. package/src/cli.ts +321 -0
@@ -0,0 +1,416 @@
1
+ # Analytics Plugin Example
2
+
3
+ 这是一个功能完整的分析插件示例,展示如何在 Linyjs 框架中构建数据分析系统。
4
+
5
+ ## ✨ 功能特点
6
+
7
+ - **📊 实时数据统计** - 在线用户数、事件计数、系统状态
8
+ - **📈 热门事件分析** - 追踪和统计用户行为事件
9
+ - **🔄 定时数据聚合** - 每小时自动聚合分析数据
10
+ - **👥 用户留存分析** - 分析用户激活和流失率
11
+ - **🎨 响应式仪表盘** - 美观的数据可视化界面
12
+ - **🛰️ 实时更新** - 自动刷新实时统计数据
13
+ - **📅 多时间段分析** - 支持自定义时间范围的数据查询
14
+
15
+ ## 🏗️ 技术架构
16
+
17
+ ### 服务端组件
18
+
19
+ - **AnalyticsService** - 核心分析逻辑,包括:
20
+ - 事件追踪和记录
21
+ - 数据聚合和分析
22
+ - 用户留存率计算
23
+ - 实时统计生成
24
+
25
+ - **AnalyticsController** - REST API 接口,提供:
26
+ - `POST /api/analytics/track` - 事件追踪
27
+ - `GET /api/analytics/summary` - 分析摘要
28
+ - `GET /api/analytics/realtime` - 实时统计
29
+ - `GET /api/analytics/retention` - 留存分析
30
+ - `POST /api/analytics/aggregate` - 手动聚合
31
+
32
+ - **AnalyticsCronService** - 定时任务服务:
33
+ - 后台每小时自动运行数据聚合
34
+ - 支持启动/停止生命周期管理
35
+ - 模拟生产环境下的定时任务
36
+
37
+ ### 客户端组件
38
+
39
+ - **AnalyticsDashboard** - 主要仪表盘界面:
40
+ - 实时统计卡片展示
41
+ - 标签页式导航(概览 / 留存分析)
42
+ - 自动数据刷新
43
+ - 响应式布局设计
44
+
45
+ - **AnalyticsTracker** - 事件追踪器组件:
46
+ - 可包装任意的点击元素
47
+ - 自动生成匿名用户 ID(未登录时)
48
+ - 支持自定义事件数据
49
+
50
+ - **Charts & Visualization** - 数据可视化组件:
51
+ - SimpleChart - 简单的条形图组件
52
+ - StatsCard - 统计卡片组件
53
+ - RetentionChart - 留存分析图表
54
+
55
+ ## 🚀 快速开始
56
+
57
+ ### 安装依赖
58
+
59
+ ```bash
60
+ npm install @linyjs/server-module-interface @linyjs/client-module-interface
61
+ npm install --save-dev @linyjs/server-module-interface @linyjs/client-module-interface
62
+ ```
63
+
64
+ ### 注册插件
65
+
66
+ 在你的 Linyjs 应用中:
67
+
68
+ ```typescript
69
+ // src/server.ts
70
+ import { analyticsServerModule } from '@linyjs/example-analytics-plugin';
71
+
72
+ const serverConfig = {
73
+ plugins: [
74
+ // ... 其他插件
75
+ analyticsServerModule
76
+ ]
77
+ };
78
+ ```
79
+
80
+ ```typescript
81
+ // src/client.ts
82
+ import { analyticsClientModule } from '@linyjs/example-analytics-plugin';
83
+
84
+ const clientConfig = {
85
+ plugins: [
86
+ // ... 其他插件
87
+ analyticsClientModule
88
+ ]
89
+ };
90
+ ```
91
+
92
+ ### 追踪事件
93
+
94
+ ```javascript
95
+ // 追踪页面访问
96
+ fetch('/api/analytics/track', {
97
+ method: 'POST',
98
+ headers: { 'Content-Type': 'application/json' },
99
+ body: JSON.stringify({
100
+ eventName: 'page_view',
101
+ userId: getCurrentUserId(), // 或从 cookie/localStorage 获取
102
+ data: {
103
+ page: '/products',
104
+ referrer: document.referrer,
105
+ sessionId: getSessionId()
106
+ }
107
+ })
108
+ });
109
+
110
+ // 追踪用户操作
111
+ fetch('/api/analytics/track', {
112
+ method: 'POST',
113
+ headers: { 'Content-Type': 'application/json' },
114
+ body: JSON.stringify({
115
+ eventName: 'product_click',
116
+ userId: getCurrentUserId(),
117
+ data: {
118
+ productId: 'ABC123',
119
+ category: 'electronics',
120
+ source: 'product_list'
121
+ }
122
+ })
123
+ });
124
+ ```
125
+
126
+ ### 使用追踪器组件
127
+
128
+ ```jsx
129
+ import { AnalyticsTracker } from '@linyjs/example-analytics-plugin';
130
+
131
+ function ProductCard({ product }) {
132
+ return (
133
+ <AnalyticsTracker
134
+ eventName="product_view"
135
+ userId={currentUserId}
136
+ >
137
+ <div className="product-card">
138
+ <h3>{product.name}</h3>
139
+ <p>{product.description}</p>
140
+ <button>查看详情</button>
141
+ </div>
142
+ </AnalyticsTracker>
143
+ );
144
+ }
145
+ ```
146
+
147
+ ### 访问仪表盘
148
+
149
+ 启动应用后,在浏览器中访问:
150
+
151
+ ```
152
+ http://localhost:3000/analytics
153
+ ```
154
+
155
+ ## 📊 API 文档
156
+
157
+ ### 追踪事件 (POST /api/analytics/track)
158
+
159
+ ```typescript
160
+ interface TrackEventRequest {
161
+ eventName: string;
162
+ userId: string;
163
+ data: {
164
+ // 任意自定义数据
165
+ timestamp?: string;
166
+ [key: string]: any;
167
+ };
168
+ }
169
+ ```
170
+
171
+ **状态码:**
172
+ - `200 OK` - 事件追踪成功
173
+ - `400 Bad Request` - 缺少必要参数
174
+ - `500 Internal Server Error` - 服务器错误
175
+
176
+ ### 获取分析摘要 (GET /api/analytics/summary)
177
+
178
+ ```typescript
179
+ // 查询参数
180
+ {
181
+ start?: string; // ISO 日期时间,默认 7 天前
182
+ end?: string; // ISO 日期时间,默认当前时间
183
+ }
184
+ ```
185
+
186
+ **返回数据:**
187
+ ```typescript
188
+ {
189
+ totalEvents: number;
190
+ eventsByDay: { [date: string]: number };
191
+ eventTypes: { [eventName: string]: number };
192
+ activeUsers: number;
193
+ topEvents: { name: string; count: number }[];
194
+ }
195
+ ```
196
+
197
+ ### 获取实时统计 (GET /api/analytics/realtime)
198
+
199
+ **返回数据:**
200
+ ```typescript
201
+ {
202
+ onlineUsers: number;
203
+ currentEvents: number;
204
+ serverTime: string;
205
+ }
206
+ ```
207
+
208
+ ### 用户留存分析 (GET /api/analytics/retention)
209
+
210
+ ```typescript
211
+ // 查询参数
212
+ {
213
+ days?: number; // 天数,默认 7 天
214
+ }
215
+ ```
216
+
217
+ **返回数据:**
218
+ ```typescript
219
+ {
220
+ dayIntervals: string[]; // 日期数组
221
+ newUsers: number[]; // 每日新用户
222
+ returningUsers: number[]; // 每日回访用户
223
+ retentionRates: string[]; // 每日留存率
224
+ }
225
+ ```
226
+
227
+ ## 🏃‍♂️ 使用场景示例
228
+
229
+ ### 1. 电商网站分析
230
+
231
+ ```javascript
232
+ // 用户浏览商品
233
+ trackEvent('product_view', userId, { productId: 'ABC123' });
234
+
235
+ // 用户加入购物车
236
+ trackEvent('add_to_cart', userId, {
237
+ productId: 'ABC123',
238
+ quantity: 2,
239
+ value: 19.99
240
+ });
241
+
242
+ // 用户完成购买
243
+ trackEvent('purchase', userId, {
244
+ orderId: 'ORD123',
245
+ value: 99.99,
246
+ items: 3
247
+ });
248
+ ```
249
+
250
+ ### 2. SaaS 应用监控
251
+
252
+ ```javascript
253
+ // 功能使用频次
254
+ trackEvent('feature_used', userId, { feature: 'export_data' });
255
+
256
+ // 页面停留时间
257
+ trackEvent('page_duration', userId, {
258
+ page: '/dashboard',
259
+ duration: 45000 // 毫秒
260
+ });
261
+
262
+ // 错误追踪
263
+ trackEvent('error_occurred', userId, {
264
+ errorType: 'validation',
265
+ page: '/form',
266
+ message: 'Email format invalid'
267
+ });
268
+ ```
269
+
270
+ ## 🔧 自定义扩展
271
+
272
+ ### 添加新的分析指标
273
+
274
+ ```typescript
275
+ // 在 AnalyticsService 中添加新方法
276
+ class CustomAnalyticsService extends AnalyticsService {
277
+
278
+ // 计算平均会话时长
279
+ async getAverageSessionDuration() {
280
+ const events = this.getAllEvents();
281
+ // 实现计算逻辑...
282
+ return averageDuration;
283
+ }
284
+
285
+ // 分析漏斗转化率
286
+ async getFunnelConversion(funnelSteps: string[]) {
287
+ // 实现漏斗分析逻辑...
288
+ return conversionRates;
289
+ }
290
+ }
291
+ ```
292
+
293
+ ### 集成外部数据源
294
+
295
+ ```typescript
296
+ // 添加外部数据聚合
297
+ class ExternalDataSource {
298
+
299
+ async integrateWithGoogleAnalytics() {
300
+ // 集成 Google Analytics 数据
301
+ }
302
+
303
+ async integrateWithMixpanel() {
304
+ // 集成 Mixpanel 数据
305
+ }
306
+ }
307
+ ```
308
+
309
+ ## 🗄️ 生产环境配置
310
+
311
+ ### 数据库集成
312
+
313
+ 在生产环境中,建议将分析数据存储在数据库中:
314
+
315
+ ```typescript
316
+ // 使用 MongoDB
317
+ class MongoAnalyticsService extends AnalyticsService {
318
+
319
+ async saveEvent(event) {
320
+ const collection = db.collection('events');
321
+ await collection.insertOne(event);
322
+ }
323
+
324
+ async aggregateEvents(start, end) {
325
+ const collection = db.collection('events');
326
+ return await collection.aggregate([ /* 聚合管道 */ ]);
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### Redis 缓存优化
332
+
333
+ ```typescript
334
+ class CachedAnalyticsService {
335
+
336
+ async getRealtimeStats() {
337
+ // 从 Redis 获取缓存的实时数据
338
+ let stats = await redis.get('analytics:realtime');
339
+
340
+ if (!stats) {
341
+ stats = await this.generateRealtimeStats();
342
+ await redis.setex('analytics:realtime', 60, JSON.stringify(stats));
343
+ }
344
+
345
+ return JSON.parse(stats);
346
+ }
347
+ }
348
+ ```
349
+
350
+ ## 🧪 测试指南
351
+
352
+ ```typescript
353
+ // 单元测试示例
354
+ describe('AnalyticsService', () => {
355
+ let service: AnalyticsService;
356
+
357
+ beforeEach(() => {
358
+ service = new AnalyticsService();
359
+ });
360
+
361
+ it('should track events correctly', async () => {
362
+ const result = await service.trackEvent('test', 'user123', { value: 1 });
363
+ expect(result.success).toBe(true);
364
+ expect(result.eventId).toBeDefined();
365
+ });
366
+
367
+ it('should calculate analytics correctly', async () => {
368
+ await service.trackEvent('click', 'user1', {});
369
+ await service.trackEvent('click', 'user2', {});
370
+
371
+ const stats = await service.getAnalytics(startDate, endDate);
372
+ expect(stats.totalEvents).toBe(2);
373
+ expect(stats.eventTypes['click']).toBe(2);
374
+ });
375
+ });
376
+ ```
377
+
378
+ ## 📈 性能优化建议
379
+
380
+ 1. **批量写入** - 使用批量插入减少数据库操作
381
+ 2. **数据采样** - 对大量事件进行采样处理
382
+ 3. **异步处理** - 使用消息队列异步处理事件追踪
383
+ 4. **缓存策略** - 对常用查询结果进行缓存
384
+ 5. **索引优化** - 为数据库字段建立合适的索引
385
+
386
+ ## 🔒 安全和隐私
387
+
388
+ - 用户数据匿名化
389
+ - 敏感信息脱敏
390
+ - 数据访问权限控制
391
+ - 合规性检查(GDPR、CCPA)
392
+ - 日志审计追踪
393
+
394
+ ## 📚 相关资源
395
+
396
+ - [Linyjs 插件开发文档](../../docs/plugin-development.md)
397
+ - [React 文档](https://react.dev/)
398
+ - [TypeScript 文档](https://www.typescriptlang.org/)
399
+ - [REST API 设计最佳实践](https://restfulapi.net/)
400
+
401
+ ## 🤝 贡献指南
402
+
403
+ 欢迎提交 Issue 和 Pull Request。请确保:
404
+
405
+ 1. 代码遵循项目编码规范
406
+ 2. 添加相应的测试用例
407
+ 3. 更新相关文档
408
+ 4. 说明修改的原因和影响
409
+
410
+ ---
411
+
412
+ **示例受到以下工具和服务启发:**
413
+ - Google Analytics
414
+ - Mixpanel
415
+ - Amplitude
416
+ - Matomo
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import type { IModule } from '@linyjs/client-module-interface';
3
+ /**
4
+ * 实时统计卡片组件
5
+ */
6
+ declare function StatsCard({ title, value, unit, description }: {
7
+ title: string;
8
+ value: React.ReactNode;
9
+ unit?: string;
10
+ description?: string;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ /**
13
+ * 图表组件 (简化版)
14
+ */
15
+ declare function SimpleChart({ data, title, type }: {
16
+ data: any[];
17
+ title: string;
18
+ type?: 'line' | 'bar';
19
+ }): import("react/jsx-runtime").JSX.Element;
20
+ /**
21
+ * 分析仪表盘主组件
22
+ */
23
+ declare function AnalyticsDashboard(): import("react/jsx-runtime").JSX.Element;
24
+ /**
25
+ * 分析事件追踪组件(可嵌入其他页面)
26
+ */
27
+ declare function AnalyticsTracker({ eventName, userId, children }: {
28
+ eventName: string;
29
+ userId?: string;
30
+ children: React.ReactNode;
31
+ }): import("react/jsx-runtime").JSX.Element;
32
+ /**
33
+ * 客户端模块
34
+ */
35
+ export declare const analyticsClientModule: IModule;
36
+ export { AnalyticsDashboard, AnalyticsTracker, StatsCard, SimpleChart };
@@ -0,0 +1,173 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.analyticsClientModule = void 0;
7
+ exports.AnalyticsDashboard = AnalyticsDashboard;
8
+ exports.AnalyticsTracker = AnalyticsTracker;
9
+ exports.StatsCard = StatsCard;
10
+ exports.SimpleChart = SimpleChart;
11
+ const jsx_runtime_1 = require("react/jsx-runtime");
12
+ const react_1 = __importDefault(require("react"));
13
+ const API_BASE = '/api/analytics';
14
+ /**
15
+ * 实时统计卡片组件
16
+ */
17
+ function StatsCard({ title, value, unit = '', description }) {
18
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-white p-6 rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-sm font-medium text-gray-500 mb-2", children: title }), (0, jsx_runtime_1.jsxs)("div", { className: "flex items-baseline mb-2", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-3xl font-bold text-gray-900", children: value }), unit && (0, jsx_runtime_1.jsx)("span", { className: "text-lg text-gray-500 ml-1", children: unit })] }), description && (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-600", children: description })] }));
19
+ }
20
+ /**
21
+ * 图表组件 (简化版)
22
+ */
23
+ function SimpleChart({ data, title, type = 'line' }) {
24
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-white p-6 rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: title }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2 max-h-64 overflow-y-auto", children: data.map((item, index) => {
25
+ if (typeof item === 'object' && item.name && typeof item.count === 'number') {
26
+ const maxCount = Math.max(...data.map(d => d.count || 1));
27
+ const widthPercent = (item.count / maxCount) * 100;
28
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "flex items-center space-x-2", children: [(0, jsx_runtime_1.jsx)("div", { className: "w-24 text-sm text-gray-600 truncate", children: item.name }), (0, jsx_runtime_1.jsx)("div", { className: "flex-1 bg-gray-200 rounded-full h-4", children: (0, jsx_runtime_1.jsx)("div", { className: "bg-blue-600 h-4 rounded-full", style: { width: `${widthPercent}%` } }) }), (0, jsx_runtime_1.jsx)("div", { className: "w-12 text-sm text-gray-900 font-medium", children: item.count })] }, index));
29
+ }
30
+ return null;
31
+ }) })] }));
32
+ }
33
+ /**
34
+ * 留存分析组件
35
+ */
36
+ function RetentionChart({ data }) {
37
+ var _a, _b, _c;
38
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "bg-white p-6 rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: "\u7528\u6237\u7559\u5B58\u5206\u6790" }), (0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-2 gap-4 mb-4", children: [(0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-medium text-gray-900 mb-2", children: "\u65B0\u7528\u6237" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: (_a = data.newUsers) === null || _a === void 0 ? void 0 : _a.map((count, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-sm", children: [(0, jsx_runtime_1.jsx)("span", { children: data.dayIntervals[index] }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: count })] }, index))) })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-medium text-gray-900 mb-2", children: "\u56DE\u8BBF\u7528\u6237" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: (_b = data.returningUsers) === null || _b === void 0 ? void 0 : _b.map((count, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-sm", children: [(0, jsx_runtime_1.jsx)("span", { children: data.dayIntervals[index] }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: count })] }, index))) })] })] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("h4", { className: "font-medium text-gray-900 mb-2", children: "\u7559\u5B58\u7387" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-1", children: (_c = data.retentionRates) === null || _c === void 0 ? void 0 : _c.map((rate, index) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between text-sm", children: [(0, jsx_runtime_1.jsx)("span", { children: data.dayIntervals[index] }), (0, jsx_runtime_1.jsxs)("span", { className: parseFloat(rate) > 60 ? 'text-green-600' : parseFloat(rate) > 30 ? 'text-yellow-600' : 'text-red-500', children: [rate, "%"] })] }, index))) })] })] }));
39
+ }
40
+ /**
41
+ * 分析仪表盘主组件
42
+ */
43
+ function AnalyticsDashboard() {
44
+ const [stats, setStats] = react_1.default.useState(null);
45
+ const [realtimeStats, setRealtimeStats] = react_1.default.useState(null);
46
+ const [retentionData, setRetentionData] = react_1.default.useState(null);
47
+ const [loading, setLoading] = react_1.default.useState(true);
48
+ const [activeTab, setActiveTab] = react_1.default.useState('overview');
49
+ react_1.default.useEffect(() => {
50
+ loadAnalytics();
51
+ // 实时数据每30秒更新一次
52
+ const interval = setInterval(loadRealTimeStats, 30000);
53
+ loadRealTimeStats();
54
+ return () => clearInterval(interval);
55
+ }, []);
56
+ const loadAnalytics = async () => {
57
+ try {
58
+ setLoading(true);
59
+ const response = await fetch(`${API_BASE}/summary`);
60
+ const data = await response.json();
61
+ setStats(data);
62
+ }
63
+ catch (error) {
64
+ console.error('加载分析数据失败:', error);
65
+ }
66
+ finally {
67
+ setLoading(false);
68
+ }
69
+ };
70
+ const loadRealTimeStats = async () => {
71
+ try {
72
+ const response = await fetch(`${API_BASE}/realtime`);
73
+ const data = await response.json();
74
+ setRealtimeStats(data);
75
+ }
76
+ catch (error) {
77
+ console.error('加载实时数据失败:', error);
78
+ }
79
+ };
80
+ const loadRetentionData = async () => {
81
+ try {
82
+ const response = await fetch(`${API_BASE}/retention`);
83
+ const data = await response.json();
84
+ setRetentionData(data);
85
+ }
86
+ catch (error) {
87
+ console.error('加载留存数据失败:', error);
88
+ }
89
+ };
90
+ react_1.default.useEffect(() => {
91
+ if (activeTab === 'retention' && !retentionData) {
92
+ loadRetentionData();
93
+ }
94
+ }, [activeTab, retentionData]);
95
+ if (loading) {
96
+ return ((0, jsx_runtime_1.jsx)("div", { className: "min-h-screen bg-gray-50 flex items-center justify-center", children: (0, jsx_runtime_1.jsxs)("div", { className: "text-center", children: [(0, jsx_runtime_1.jsx)("div", { className: "animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto mb-4" }), (0, jsx_runtime_1.jsx)("p", { className: "text-gray-600", children: "\u52A0\u8F7D\u5206\u6790\u6570\u636E\u4E2D..." })] }) }));
97
+ }
98
+ return ((0, jsx_runtime_1.jsxs)("div", { className: "min-h-screen bg-gray-50", children: [(0, jsx_runtime_1.jsx)("nav", { className: "bg-white shadow-sm border-b", children: (0, jsx_runtime_1.jsx)("div", { className: "max-w-7xl mx-auto px-4", children: (0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center py-4", children: [(0, jsx_runtime_1.jsx)("h1", { className: "text-2xl font-bold text-gray-900", children: "\u5206\u6790\u4EEA\u8868\u76D8" }), (0, jsx_runtime_1.jsx)("button", { onClick: loadAnalytics, className: "px-4 py-2 text-sm border border-gray-300 rounded-md hover:bg-gray-50", children: "\u5237\u65B0\u6570\u636E" })] }) }) }), (0, jsx_runtime_1.jsxs)("div", { className: "max-w-7xl mx-auto px-4 py-6", children: [(0, jsx_runtime_1.jsxs)("div", { className: "flex space-x-1 mb-6", children: [(0, jsx_runtime_1.jsx)("button", { onClick: () => setActiveTab('overview'), className: `px-4 py-2 text-sm font-medium rounded-md ${activeTab === 'overview'
99
+ ? 'bg-blue-600 text-white'
100
+ : 'text-gray-500 hover:text-gray-700'}`, children: "\u6982\u89C8" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setActiveTab('retention'), className: `px-4 py-2 text-sm font-medium rounded-md ${activeTab === 'retention'
101
+ ? 'bg-blue-600 text-white'
102
+ : 'text-gray-500 hover:text-gray-700'}`, children: "\u7559\u5B58\u5206\u6790" })] }), activeTab === 'overview' ? (
103
+ /* 概览页面 */
104
+ (0, jsx_runtime_1.jsxs)("div", { className: "space-y-6", children: [realtimeStats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6 mb-8", children: [(0, jsx_runtime_1.jsx)(StatsCard, { title: "\u5F53\u524D\u5728\u7EBF\u7528\u6237", value: realtimeStats.onlineUsers || 0, description: "\u5B9E\u65F6\u6D3B\u8DC3\u7528\u6237\u6570" }), (0, jsx_runtime_1.jsx)(StatsCard, { title: "\u5F53\u524D\u4E8B\u4EF6\u6570", value: realtimeStats.currentEvents || 0, description: "\u6BCF\u5206\u949F\u5904\u7406\u7684\u4E8B\u4EF6" }), (0, jsx_runtime_1.jsx)(StatsCard, { title: "\u670D\u52A1\u5668\u65F6\u95F4", value: new Date(realtimeStats.serverTime).toLocaleTimeString(), description: "\u6570\u636E\u66F4\u65B0\u65F6\u95F4" })] })), stats && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: [(0, jsx_runtime_1.jsx)(StatsCard, { title: "\u603B\u4E8B\u4EF6\u6570", value: stats.totalEvents || 0, description: "\u8FC7\u53BB7\u5929\u4E8B\u4EF6\u603B\u6570" }), (0, jsx_runtime_1.jsx)(StatsCard, { title: "\u6D3B\u8DC3\u7528\u6237\u6570", value: stats.activeUsers || 0, description: "\u8FC7\u53BB7\u5929\u6D3B\u8DC3\u7528\u6237" }), (0, jsx_runtime_1.jsx)(StatsCard, { title: "\u4E8B\u4EF6\u7C7B\u578B\u6570", value: Object.keys(stats.eventTypes || {}).length, description: "\u4E0D\u540C\u7C7B\u578B\u7684\u4E8B\u4EF6" })] })), stats && stats.topEvents && ((0, jsx_runtime_1.jsxs)("div", { className: "grid grid-cols-1 lg:grid-cols-2 gap-6", children: [(0, jsx_runtime_1.jsx)(SimpleChart, { data: stats.topEvents, title: "\u70ED\u95E8\u4E8B\u4EF6\u5206\u6790" }), (0, jsx_runtime_1.jsxs)("div", { className: "bg-white p-6 rounded-lg shadow-md", children: [(0, jsx_runtime_1.jsx)("h3", { className: "text-lg font-semibold mb-4", children: "\u4E8B\u4EF6\u7C7B\u578B\u5206\u5E03" }), (0, jsx_runtime_1.jsx)("div", { className: "space-y-2", children: Object.entries(stats.eventTypes || {}).map(([name, count]) => ((0, jsx_runtime_1.jsxs)("div", { className: "flex justify-between items-center", children: [(0, jsx_runtime_1.jsx)("span", { className: "text-sm text-gray-600", children: name }), (0, jsx_runtime_1.jsx)("span", { className: "font-medium", children: count })] }, name))) })] })] }))] })) : (
105
+ /* 留存分析页面 */
106
+ retentionData ? ((0, jsx_runtime_1.jsx)("div", { className: "grid grid-cols-1 gap-6", children: (0, jsx_runtime_1.jsx)(RetentionChart, { data: retentionData }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "text-center py-12", children: (0, jsx_runtime_1.jsx)("button", { onClick: loadRetentionData, className: "px-6 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700", children: "\u52A0\u8F7D\u7559\u5B58\u6570\u636E" }) }))), !loading && !stats && ((0, jsx_runtime_1.jsxs)("div", { className: "text-center py-12", children: [(0, jsx_runtime_1.jsx)("p", { className: "text-gray-500 mb-4", children: "\u6682\u65E0\u5206\u6790\u6570\u636E" }), (0, jsx_runtime_1.jsx)("p", { className: "text-sm text-gray-400", children: "\u5F00\u59CB\u6536\u96C6\u5E94\u7528\u4F7F\u7528\u6570\u636E\u540E\uFF0C\u8FD9\u91CC\u5C06\u663E\u793A\u8BE6\u7EC6\u7684\u5206\u6790\u62A5\u544A" })] }))] })] }));
107
+ }
108
+ /**
109
+ * 分析事件追踪组件(可嵌入其他页面)
110
+ */
111
+ function AnalyticsTracker({ eventName, userId, children }) {
112
+ const trackEvent = async () => {
113
+ try {
114
+ await fetch(`${API_BASE}/track`, {
115
+ method: 'POST',
116
+ headers: { 'Content-Type': 'application/json' },
117
+ body: JSON.stringify({
118
+ eventName,
119
+ userId: userId || 'anonymous-' + Date.now(),
120
+ data: { timestamp: new Date().toISOString() }
121
+ })
122
+ });
123
+ }
124
+ catch (error) {
125
+ console.error('追踪事件失败:', error);
126
+ }
127
+ };
128
+ return ((0, jsx_runtime_1.jsx)("div", { onClick: trackEvent, children: children }));
129
+ }
130
+ /**
131
+ * 客户端模块
132
+ */
133
+ exports.analyticsClientModule = {
134
+ name: 'analyticsClient',
135
+ serviceDefs: [
136
+ {
137
+ serviceTag: 'analyticsRoute',
138
+ serviceImpl: class AnalyticsRouteService {
139
+ constructor() {
140
+ this.basePath = '/analytics';
141
+ }
142
+ getRoutes() {
143
+ return [
144
+ {
145
+ path: '/',
146
+ component: AnalyticsDashboard,
147
+ key: 'analytics-dashboard',
148
+ meta: {
149
+ title: '分析仪表盘 - linyjs分析插件',
150
+ description: '查看应用使用统计和用户行为分析'
151
+ }
152
+ }
153
+ ];
154
+ }
155
+ },
156
+ meta: { usageType: 'route' }
157
+ },
158
+ {
159
+ serviceTag: 'analyticsComponent',
160
+ serviceImpl: class AnalyticsComponentService {
161
+ getComponents() {
162
+ return {
163
+ AnalyticsDashboard,
164
+ AnalyticsTracker,
165
+ StatsCard,
166
+ SimpleChart
167
+ };
168
+ }
169
+ },
170
+ meta: { usageType: 'component' }
171
+ }
172
+ ]
173
+ };
@@ -0,0 +1,64 @@
1
+ export { analyticsServerModule } from './server';
2
+ export { analyticsClientModule } from './client';
3
+ declare const analyticsPlugin: {
4
+ server: import("@linyjs/server-module-interface", { with: { "resolution-mode": "import" } }).IModule;
5
+ client: import("@linyjs/client-module-interface", { with: { "resolution-mode": "import" } }).IModule;
6
+ };
7
+ export default analyticsPlugin;
8
+ /**
9
+ * @module @linyjs/example-analytics-plugin
10
+ *
11
+ * Analytics Plugin Example
12
+ * ===============
13
+ *
14
+ * Features:
15
+ * - 📊 Real-time analytics dashboard
16
+ * - 📈 User behavior tracking
17
+ * - 🔄 Hourly data aggregation (cron job)
18
+ * - 📈 User retention analysis
19
+ * - 🌊 Live metrics monitoring
20
+ * - 📱 Responsive web interface
21
+ *
22
+ * Server-side:
23
+ * - AnalyticsService: Core analytics logic
24
+ * - AnalyticsController: REST API endpoints
25
+ * - AnalyticsCronService: Background aggregation task
26
+ *
27
+ * Client-side:
28
+ * - AnalyticsDashboard: Main dashboard UI
29
+ * - AnalyticsTracker: Event tracking utility
30
+ * - Visual charts and metrics display
31
+ *
32
+ * API Endpoints:
33
+ * - POST /api/analytics/track - Track events
34
+ * - GET /api/analytics/summary - Get analytics summary
35
+ * - GET /api/analytics/realtime - Get real-time stats
36
+ * - GET /api/analytics/retention - Get user retention
37
+ * - POST /api/analytics/aggregate - Manual aggregation
38
+ *
39
+ * Usage:
40
+ *
41
+ * 1. Include in your Linyjs app:
42
+ * ```typescript
43
+ * import { analyticsServerModule } from '@linyjs/example-analytics-plugin';
44
+ *
45
+ * // In server config
46
+ * plugins: [analyticsServerModule]
47
+ * ```
48
+ *
49
+ * 2. Track events from client:
50
+ * ```javascript
51
+ * fetch('/api/analytics/track', {
52
+ * method: 'POST',
53
+ * headers: { 'Content-Type': 'application/json' },
54
+ * body: JSON.stringify({
55
+ * eventName: 'page_view',
56
+ * userId: 'user123',
57
+ * data: { page: '/home' }
58
+ * })
59
+ * });
60
+ * ```
61
+ *
62
+ * 3. View analytics dashboard:
63
+ * Access at `/analytics` route in your app
64
+ */