cancan-microstack 0.0.1__py3-none-any.whl

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 (440) hide show
  1. cancan_microstack/__init__.py +14 -0
  2. cancan_microstack/__version__.py +10 -0
  3. cancan_microstack/assets/__init__.py +6 -0
  4. cancan_microstack/assets/builds/caddy/Caddyfile +187 -0
  5. cancan_microstack/assets/builds/caddy/DEPLOYMENT.md +303 -0
  6. cancan_microstack/assets/builds/caddy/Dockerfile +46 -0
  7. cancan_microstack/assets/builds/caddy/README.md +343 -0
  8. cancan_microstack/assets/builds/caddy/geoip/README.md +5 -0
  9. cancan_microstack/assets/builds/caddy/start.sh +78 -0
  10. cancan_microstack/assets/builds/caddy/waf/coraza.conf +179 -0
  11. cancan_microstack/assets/builds/service/Dockerfile +59 -0
  12. cancan_microstack/assets/builds/service/README.md +13 -0
  13. cancan_microstack/assets/ddl/create_db.sql +22 -0
  14. cancan_microstack/assets/ddl/infra/execution_log_tbl.sql +46 -0
  15. cancan_microstack/assets/ddl/infra/node_instance_tbl.sql +56 -0
  16. cancan_microstack/assets/ddl/infra/service_action_log_tbl.sql +36 -0
  17. cancan_microstack/assets/ddl/infra/service_config_tbl.sql +26 -0
  18. cancan_microstack/assets/ddl/infra/service_info_tbl.sql +45 -0
  19. cancan_microstack/assets/ddl/infra/service_instance_tbl.sql +54 -0
  20. cancan_microstack/assets/ddl/infra/service_operation_tbl.sql +47 -0
  21. cancan_microstack/assets/ddl/infra/workflow_definition_tbl.sql +60 -0
  22. cancan_microstack/assets/ddl/infra/workflow_definition_version_tbl.sql +35 -0
  23. cancan_microstack/assets/ddl/infra/workflow_engine_alert_tbl.sql +34 -0
  24. cancan_microstack/assets/ddl/infra/workflow_run_tbl.sql +52 -0
  25. cancan_microstack/assets/ddl/ops/admin_user_tbl.sql +34 -0
  26. cancan_microstack/assets/ddl/ops/caddy_access_log_tbl.sql +91 -0
  27. cancan_microstack/assets/ddl/ops/caddy_certificate_tbl.sql +59 -0
  28. cancan_microstack/assets/ddl/ops/caddy_rate_limit_tbl.sql +64 -0
  29. cancan_microstack/assets/ddl/ops/caddy_route_tbl.sql +63 -0
  30. cancan_microstack/assets/ddl/ops/caddy_stats_tbl.sql +77 -0
  31. cancan_microstack/assets/ddl/trigger.sql +21 -0
  32. cancan_microstack/assets/docker/docker-compose.infra.yml +401 -0
  33. cancan_microstack/assets/scripts/README.md +195 -0
  34. cancan_microstack/assets/scripts/docker/build_images.sh +44 -0
  35. cancan_microstack/assets/scripts/docker/force_rebuild_images.sh +38 -0
  36. cancan_microstack/assets/scripts/docker/rebuild_all.sh +34 -0
  37. cancan_microstack/assets/scripts/docker/rebuild_compose.sh +61 -0
  38. cancan_microstack/assets/scripts/docker/restart.sh +35 -0
  39. cancan_microstack/assets/scripts/docker/restart_compose.sh +35 -0
  40. cancan_microstack/assets/scripts/docker/start.sh +78 -0
  41. cancan_microstack/assets/scripts/docker/start_all.sh +46 -0
  42. cancan_microstack/assets/scripts/docker/start_compose.sh +66 -0
  43. cancan_microstack/assets/scripts/docker/stop.sh +67 -0
  44. cancan_microstack/assets/scripts/docker/stop_all.sh +38 -0
  45. cancan_microstack/assets/scripts/docker/stop_compose.sh +38 -0
  46. cancan_microstack/assets/scripts/podman/build_images_podman.sh +59 -0
  47. cancan_microstack/assets/scripts/podman/cleanup_podman.sh +25 -0
  48. cancan_microstack/assets/scripts/podman/force_rebuild_images_podman.sh +56 -0
  49. cancan_microstack/assets/scripts/podman/rebuild_all_podman.sh +37 -0
  50. cancan_microstack/assets/scripts/podman/rebuild_compose_podman.sh +60 -0
  51. cancan_microstack/assets/scripts/podman/restart_compose_podman.sh +73 -0
  52. cancan_microstack/assets/scripts/podman/start_all_podman.sh +66 -0
  53. cancan_microstack/assets/scripts/podman/start_compose_podman.sh +80 -0
  54. cancan_microstack/assets/scripts/podman/start_podman.sh +91 -0
  55. cancan_microstack/assets/scripts/podman/stop.sh +73 -0
  56. cancan_microstack/assets/scripts/podman/stop_all_podman.sh +34 -0
  57. cancan_microstack/assets/scripts/podman/stop_compose_podman.sh +58 -0
  58. cancan_microstack/assets/scripts/start_controllersrv.sh +9 -0
  59. cancan_microstack/assets/scripts/utils/check_all_db_tables.sh +104 -0
  60. cancan_microstack/assets/scripts/utils/check_env.sh +177 -0
  61. cancan_microstack/assets/scripts/utils/check_service_management_deployment.sh +225 -0
  62. cancan_microstack/assets/scripts/utils/deploy_service_management.sh +176 -0
  63. cancan_microstack/assets/scripts/utils/force_reload_infrasrv.sh +52 -0
  64. cancan_microstack/assets/scripts/utils/monitor_service_management.sh +187 -0
  65. cancan_microstack/assets/scripts/utils/reset_postgres_volume.sh +68 -0
  66. cancan_microstack/assets/scripts/utils/test_async_operations.sh +141 -0
  67. cancan_microstack/assets/scripts/utils/verify_real_operations.sh +76 -0
  68. cancan_microstack/assets/service/Dockerfile +65 -0
  69. cancan_microstack/assets/www/adminops/assets/AppEmpty.vue_vue_type_script_setup_true_lang-BOKUurnM.js +1 -0
  70. cancan_microstack/assets/www/adminops/assets/ConfigManage-DKV5YOUz.js +1 -0
  71. cancan_microstack/assets/www/adminops/assets/ConfigManage-Y5bhy7wG.css +1 -0
  72. cancan_microstack/assets/www/adminops/assets/ConsoleManage-8ljYvCW2.js +1 -0
  73. cancan_microstack/assets/www/adminops/assets/ConsoleManage-BWpyqbuQ.css +1 -0
  74. cancan_microstack/assets/www/adminops/assets/DashboardNew-B9Nf1OPl.js +1 -0
  75. cancan_microstack/assets/www/adminops/assets/DashboardNew-DYWZKQ1V.css +1 -0
  76. cancan_microstack/assets/www/adminops/assets/LogSearch-CA0Jhe78.js +1 -0
  77. cancan_microstack/assets/www/adminops/assets/LogSearch-CCZfTNPF.css +1 -0
  78. cancan_microstack/assets/www/adminops/assets/LoginView-BId3kP3M.css +1 -0
  79. cancan_microstack/assets/www/adminops/assets/LoginView-BQZTV_Qy.js +1 -0
  80. cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-BdEYwqFq.js +1 -0
  81. cancan_microstack/assets/www/adminops/assets/OperationProgressDialog-D-pASR8G.css +1 -0
  82. cancan_microstack/assets/www/adminops/assets/PageContainer-Byss-yUC.js +1 -0
  83. cancan_microstack/assets/www/adminops/assets/PageContainer-C3nSZwM7.css +1 -0
  84. cancan_microstack/assets/www/adminops/assets/RateLimitManage-BDI8jLpC.css +1 -0
  85. cancan_microstack/assets/www/adminops/assets/RateLimitManage-DJY4NiF-.js +1 -0
  86. cancan_microstack/assets/www/adminops/assets/RouteManage-DaUQ4QLw.css +1 -0
  87. cancan_microstack/assets/www/adminops/assets/RouteManage-w9XCU0UA.js +1 -0
  88. cancan_microstack/assets/www/adminops/assets/ServiceCard-BFzHe6Tw.css +1 -0
  89. cancan_microstack/assets/www/adminops/assets/ServiceCard-BJUhWnA-.js +1 -0
  90. cancan_microstack/assets/www/adminops/assets/ServiceDetail-Cw24WuKp.js +1 -0
  91. cancan_microstack/assets/www/adminops/assets/ServiceDetail-Yum47zdB.css +1 -0
  92. cancan_microstack/assets/www/adminops/assets/ServiceList-C7ryvbhE.js +1 -0
  93. cancan_microstack/assets/www/adminops/assets/ServiceList-Cgd01fUx.css +1 -0
  94. cancan_microstack/assets/www/adminops/assets/ServiceLogs-COpG9H0h.js +1 -0
  95. cancan_microstack/assets/www/adminops/assets/ServiceLogs-H_Alq0cf.css +1 -0
  96. cancan_microstack/assets/www/adminops/assets/StatsOverview-D0TwMQkA.js +39 -0
  97. cancan_microstack/assets/www/adminops/assets/StatsOverview-lqAN6pqM.css +1 -0
  98. cancan_microstack/assets/www/adminops/assets/TotpBindView-CWlAmzFt.js +1 -0
  99. cancan_microstack/assets/www/adminops/assets/TotpBindView-HoQC1lhx.css +1 -0
  100. cancan_microstack/assets/www/adminops/assets/TotpVerifyView-BHN1VtX1.css +1 -0
  101. cancan_microstack/assets/www/adminops/assets/TotpVerifyView-D3w_lZk8.js +1 -0
  102. cancan_microstack/assets/www/adminops/assets/WorkflowCenter-DU_mpIA0.css +1 -0
  103. cancan_microstack/assets/www/adminops/assets/WorkflowCenter-i50rZyxN.js +1 -0
  104. cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-CnHokPL9.js +1 -0
  105. cancan_microstack/assets/www/adminops/assets/WorkflowDesigner-DaZaZpLd.css +1 -0
  106. cancan_microstack/assets/www/adminops/assets/WorkflowRuns-B09hK48c.js +1 -0
  107. cancan_microstack/assets/www/adminops/assets/WorkflowRuns-wGutKIIU.css +1 -0
  108. cancan_microstack/assets/www/adminops/assets/caddy-nnCKf8fG.js +1 -0
  109. cancan_microstack/assets/www/adminops/assets/format-Cuzxgna9.js +1 -0
  110. cancan_microstack/assets/www/adminops/assets/index-CiFlm8oc.js +64 -0
  111. cancan_microstack/assets/www/adminops/assets/index-UW0T1Dkc.css +1 -0
  112. cancan_microstack/assets/www/adminops/assets/service-BYlgGPs_.js +1 -0
  113. cancan_microstack/assets/www/adminops/assets/service-operation-6GzLw2Z1.js +1 -0
  114. cancan_microstack/assets/www/adminops/assets/style-CcIXnQ5y.css +1 -0
  115. cancan_microstack/assets/www/adminops/assets/style-lRnStdGu.js +39 -0
  116. cancan_microstack/assets/www/adminops/assets/useDebounce-BRlqfXqf.js +1 -0
  117. cancan_microstack/assets/www/adminops/assets/workflow-CUXs39Ac.js +1 -0
  118. cancan_microstack/assets/www/adminops/index.html +16 -0
  119. cancan_microstack/assets/www/adminops/vite.svg +1 -0
  120. cancan_microstack/cli/__init__.py +14 -0
  121. cancan_microstack/cli/__main__.py +9 -0
  122. cancan_microstack/cli/main.py +552 -0
  123. cancan_microstack/cmd/__init__.py +54 -0
  124. cancan_microstack/cmd/cancan/__init__.py +12 -0
  125. cancan_microstack/cmd/cancan/run.py +395 -0
  126. cancan_microstack/cmd/controllersrv/__init__.py +0 -0
  127. cancan_microstack/cmd/controllersrv/run.py +131 -0
  128. cancan_microstack/cmd/infrasrv/__init__.py +5 -0
  129. cancan_microstack/cmd/infrasrv/run.py +100 -0
  130. cancan_microstack/cmd/opsbffsrv/__init__.py +5 -0
  131. cancan_microstack/cmd/opsbffsrv/run.py +96 -0
  132. cancan_microstack/core/__init__.py +5 -0
  133. cancan_microstack/core/assets.py +123 -0
  134. cancan_microstack/core/compose_builder.py +102 -0
  135. cancan_microstack/core/doctor.py +152 -0
  136. cancan_microstack/core/microstack.py +71 -0
  137. cancan_microstack/core/runner.py +56 -0
  138. cancan_microstack/core/stack_manager.py +186 -0
  139. cancan_microstack/public/__init__.py +7 -0
  140. cancan_microstack/public/api/__init__.py +1 -0
  141. cancan_microstack/public/api/controllersrv_client.py +277 -0
  142. cancan_microstack/public/api/infrasrv_client.py +404 -0
  143. cancan_microstack/public/const/__init__.py +1 -0
  144. cancan_microstack/public/const/action_consts.py +18 -0
  145. cancan_microstack/public/const/app_consts.py +42 -0
  146. cancan_microstack/public/const/caddy_consts.py +22 -0
  147. cancan_microstack/public/const/controllersrv_consts.py +163 -0
  148. cancan_microstack/public/const/docker_consts.py +15 -0
  149. cancan_microstack/public/const/error.py +56 -0
  150. cancan_microstack/public/const/health_consts.py +52 -0
  151. cancan_microstack/public/const/hook_enums.py +56 -0
  152. cancan_microstack/public/const/logging_enums.py +13 -0
  153. cancan_microstack/public/const/metrics_enums.py +36 -0
  154. cancan_microstack/public/const/monitor_enums.py +26 -0
  155. cancan_microstack/public/const/operation_consts.py +53 -0
  156. cancan_microstack/public/const/opsbffsrv_error.py +92 -0
  157. cancan_microstack/public/const/overrides_consts.py +13 -0
  158. cancan_microstack/public/const/redis.py +17 -0
  159. cancan_microstack/public/const/service_consts.py +15 -0
  160. cancan_microstack/public/const/workflow_consts.py +65 -0
  161. cancan_microstack/public/error.py +41 -0
  162. cancan_microstack/public/logging/__init__.py +0 -0
  163. cancan_microstack/public/logging/initializer.py +109 -0
  164. cancan_microstack/public/logging/mq_handler.py +279 -0
  165. cancan_microstack/public/schemas/__init__.py +1 -0
  166. cancan_microstack/public/schemas/caddy/__init__.py +381 -0
  167. cancan_microstack/public/schemas/caddy/analysis.py +90 -0
  168. cancan_microstack/public/schemas/caddy/route.py +18 -0
  169. cancan_microstack/public/schemas/common.py +79 -0
  170. cancan_microstack/public/schemas/controllersrv/__init__.py +3 -0
  171. cancan_microstack/public/schemas/controllersrv/async_requests.py +30 -0
  172. cancan_microstack/public/schemas/controllersrv/compose_models.py +47 -0
  173. cancan_microstack/public/schemas/controllersrv/const.py +24 -0
  174. cancan_microstack/public/schemas/controllersrv/docker_models.py +45 -0
  175. cancan_microstack/public/schemas/controllersrv/docker_responses.py +104 -0
  176. cancan_microstack/public/schemas/controllersrv/requests.py +54 -0
  177. cancan_microstack/public/schemas/controllersrv/responses.py +124 -0
  178. cancan_microstack/public/schemas/controllersrv/task_models.py +102 -0
  179. cancan_microstack/public/schemas/controllersrv/validation.py +23 -0
  180. cancan_microstack/public/schemas/hook_metrics.py +124 -0
  181. cancan_microstack/public/schemas/hooks.py +39 -0
  182. cancan_microstack/public/schemas/infra/__init__.py +0 -0
  183. cancan_microstack/public/schemas/infra/cleanup.py +25 -0
  184. cancan_microstack/public/schemas/infra/container.py +74 -0
  185. cancan_microstack/public/schemas/infra/enums.py +135 -0
  186. cancan_microstack/public/schemas/infra/health_check.py +42 -0
  187. cancan_microstack/public/schemas/infra/hook_log.py +42 -0
  188. cancan_microstack/public/schemas/infra/operation.py +90 -0
  189. cancan_microstack/public/schemas/infra/overview.py +25 -0
  190. cancan_microstack/public/schemas/infra/push.py +33 -0
  191. cancan_microstack/public/schemas/infra/service_action_log.py +47 -0
  192. cancan_microstack/public/schemas/infra/service_config.py +10 -0
  193. cancan_microstack/public/schemas/infra/service_info.py +69 -0
  194. cancan_microstack/public/schemas/infra/service_instance.py +93 -0
  195. cancan_microstack/public/schemas/infra/service_management.py +152 -0
  196. cancan_microstack/public/schemas/infra/service_operation.py +79 -0
  197. cancan_microstack/public/schemas/infra/service_registry.py +158 -0
  198. cancan_microstack/public/schemas/infra/status_types.py +19 -0
  199. cancan_microstack/public/schemas/infra/workflow.py +566 -0
  200. cancan_microstack/public/schemas/logging/__init__.py +1 -0
  201. cancan_microstack/public/schemas/logging/log_event.py +121 -0
  202. cancan_microstack/public/schemas/opsbffsrv/__init__.py +1 -0
  203. cancan_microstack/public/schemas/opsbffsrv/async_ops.py +17 -0
  204. cancan_microstack/public/schemas/opsbffsrv/db_admin.py +147 -0
  205. cancan_microstack/public/schemas/opsbffsrv/db_init.py +48 -0
  206. cancan_microstack/public/schemas/opsbffsrv/service_config.py +89 -0
  207. cancan_microstack/public/schemas/opsbffsrv/service_logs.py +54 -0
  208. cancan_microstack/public/schemas/service_operation.py +24 -0
  209. cancan_microstack/public/schemas/service_registry.py +40 -0
  210. cancan_microstack/public/types/__init__.py +7 -0
  211. cancan_microstack/public/web/__init__.py +0 -0
  212. cancan_microstack/public/web/config_value.py +105 -0
  213. cancan_microstack/public/web/server.py +385 -0
  214. cancan_microstack/py.typed +0 -0
  215. cancan_microstack/runtime/__init__.py +0 -0
  216. cancan_microstack/runtime/compose_cmd.py +228 -0
  217. cancan_microstack/runtime/host_daemon.py +318 -0
  218. cancan_microstack/runtime/overrides.py +103 -0
  219. cancan_microstack/runtime/resources.py +25 -0
  220. cancan_microstack/runtime/workspace.py +94 -0
  221. cancan_microstack/services/__init__.py +0 -0
  222. cancan_microstack/services/controllersrv/__init__.py +8 -0
  223. cancan_microstack/services/controllersrv/application/__init__.py +0 -0
  224. cancan_microstack/services/controllersrv/application/docker_compose_app.py +427 -0
  225. cancan_microstack/services/controllersrv/conf/__init__.py +0 -0
  226. cancan_microstack/services/controllersrv/conf/config.py +76 -0
  227. cancan_microstack/services/controllersrv/conf/settings.py +54 -0
  228. cancan_microstack/services/controllersrv/domain/__init__.py +0 -0
  229. cancan_microstack/services/controllersrv/domain/docker_compose/__init__.py +0 -0
  230. cancan_microstack/services/controllersrv/domain/docker_compose/docker_compose_domain.py +278 -0
  231. cancan_microstack/services/controllersrv/domain/service_validator.py +327 -0
  232. cancan_microstack/services/controllersrv/domain/task/__init__.py +17 -0
  233. cancan_microstack/services/controllersrv/domain/task/task_queue.py +286 -0
  234. cancan_microstack/services/controllersrv/domain/task/task_worker.py +495 -0
  235. cancan_microstack/services/controllersrv/infrastructure/__init__.py +0 -0
  236. cancan_microstack/services/controllersrv/interface/__init__.py +0 -0
  237. cancan_microstack/services/controllersrv/interface/api/__init__.py +0 -0
  238. cancan_microstack/services/controllersrv/interface/api/docker_control_api.py +470 -0
  239. cancan_microstack/services/controllersrv/router.py +132 -0
  240. cancan_microstack/services/infrasrv/__init__.py +4 -0
  241. cancan_microstack/services/infrasrv/application/__init__.py +0 -0
  242. cancan_microstack/services/infrasrv/application/health_check_app.py +24 -0
  243. cancan_microstack/services/infrasrv/application/logging/__init__.py +1 -0
  244. cancan_microstack/services/infrasrv/application/logging/log_ingestion_service.py +183 -0
  245. cancan_microstack/services/infrasrv/application/service_config.py +22 -0
  246. cancan_microstack/services/infrasrv/application/service_logs_app.py +53 -0
  247. cancan_microstack/services/infrasrv/application/service_management_app.py +689 -0
  248. cancan_microstack/services/infrasrv/application/service_operation_tracker.py +251 -0
  249. cancan_microstack/services/infrasrv/application/service_registry.py +53 -0
  250. cancan_microstack/services/infrasrv/application/workflow/__init__.py +0 -0
  251. cancan_microstack/services/infrasrv/application/workflow/workflow_app.py +991 -0
  252. cancan_microstack/services/infrasrv/application/workflow/workflow_queue.py +302 -0
  253. cancan_microstack/services/infrasrv/application/workflow/workflow_tasks.py +46 -0
  254. cancan_microstack/services/infrasrv/application/workflow/workflow_worker_runtime.py +122 -0
  255. cancan_microstack/services/infrasrv/conf/__init__.py +0 -0
  256. cancan_microstack/services/infrasrv/conf/config.py +98 -0
  257. cancan_microstack/services/infrasrv/domain/__init__.py +0 -0
  258. cancan_microstack/services/infrasrv/domain/health_check/__init__.py +3 -0
  259. cancan_microstack/services/infrasrv/domain/health_check/health_check_domain.py +576 -0
  260. cancan_microstack/services/infrasrv/domain/hooks/__init__.py +19 -0
  261. cancan_microstack/services/infrasrv/domain/hooks/builtin_hooks.py +308 -0
  262. cancan_microstack/services/infrasrv/domain/hooks/hook_registry.py +43 -0
  263. cancan_microstack/services/infrasrv/domain/hooks/hooks_log_utils.py +275 -0
  264. cancan_microstack/services/infrasrv/domain/hooks/init.py +17 -0
  265. cancan_microstack/services/infrasrv/domain/hooks/metrics.py +205 -0
  266. cancan_microstack/services/infrasrv/domain/hooks/pre_registration_hooks.py +490 -0
  267. cancan_microstack/services/infrasrv/domain/registry/__init__.py +0 -0
  268. cancan_microstack/services/infrasrv/domain/registry/service_registry.py +509 -0
  269. cancan_microstack/services/infrasrv/domain/service_config/__init__.py +0 -0
  270. cancan_microstack/services/infrasrv/domain/service_config/service_config.py +50 -0
  271. cancan_microstack/services/infrasrv/domain/service_logs/__init__.py +0 -0
  272. cancan_microstack/services/infrasrv/domain/service_logs/service_logs_domain.py +51 -0
  273. cancan_microstack/services/infrasrv/domain/workflow/__init__.py +4 -0
  274. cancan_microstack/services/infrasrv/domain/workflow/engine.py +159 -0
  275. cancan_microstack/services/infrasrv/domain/workflow/node_handlers.py +509 -0
  276. cancan_microstack/services/infrasrv/domain/workflow/workflow_domain.py +164 -0
  277. cancan_microstack/services/infrasrv/infrastructure/__init__.py +0 -0
  278. cancan_microstack/services/infrasrv/infrastructure/api/__init__.py +0 -0
  279. cancan_microstack/services/infrasrv/infrastructure/api/controllersrv_api.py +165 -0
  280. cancan_microstack/services/infrasrv/infrastructure/cache/__init__.py +0 -0
  281. cancan_microstack/services/infrasrv/infrastructure/cache/service_registry_cache.py +174 -0
  282. cancan_microstack/services/infrasrv/infrastructure/db/__init__.py +0 -0
  283. cancan_microstack/services/infrasrv/infrastructure/db/model/__init__.py +0 -0
  284. cancan_microstack/services/infrasrv/infrastructure/db/model/execution_log_tbl.py +53 -0
  285. cancan_microstack/services/infrasrv/infrastructure/db/model/node_instance_tbl.py +55 -0
  286. cancan_microstack/services/infrasrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
  287. cancan_microstack/services/infrasrv/infrastructure/db/model/service_config_tbl.py +30 -0
  288. cancan_microstack/services/infrasrv/infrastructure/db/model/service_info_tbl.py +59 -0
  289. cancan_microstack/services/infrasrv/infrastructure/db/model/service_instance_tbl.py +88 -0
  290. cancan_microstack/services/infrasrv/infrastructure/db/model/service_operation_tbl.py +73 -0
  291. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_tbl.py +55 -0
  292. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_definition_version_tbl.py +43 -0
  293. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_engine_alert_tbl.py +57 -0
  294. cancan_microstack/services/infrasrv/infrastructure/db/model/workflow_run_tbl.py +56 -0
  295. cancan_microstack/services/infrasrv/infrastructure/db/operate/__init__.py +0 -0
  296. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_action_log_op.py +239 -0
  297. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config.py +80 -0
  298. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_config_manager.py +198 -0
  299. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_info_op.py +297 -0
  300. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_instance_op.py +688 -0
  301. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_operation_op.py +387 -0
  302. cancan_microstack/services/infrasrv/infrastructure/db/operate/service_registry.py +124 -0
  303. cancan_microstack/services/infrasrv/infrastructure/db/operate/workflow_op.py +804 -0
  304. cancan_microstack/services/infrasrv/infrastructure/ddl_manager.py +31 -0
  305. cancan_microstack/services/infrasrv/infrastructure/mongo/__init__.py +1 -0
  306. cancan_microstack/services/infrasrv/infrastructure/mongo/log_repository.py +129 -0
  307. cancan_microstack/services/infrasrv/interface/__init__.py +0 -0
  308. cancan_microstack/services/infrasrv/interface/api/__init__.py +0 -0
  309. cancan_microstack/services/infrasrv/interface/api/health_check_api.py +29 -0
  310. cancan_microstack/services/infrasrv/interface/api/hooks.py +284 -0
  311. cancan_microstack/services/infrasrv/interface/api/internal.py +49 -0
  312. cancan_microstack/services/infrasrv/interface/api/internal_instance_api.py +265 -0
  313. cancan_microstack/services/infrasrv/interface/api/internal_operation_api.py +206 -0
  314. cancan_microstack/services/infrasrv/interface/api/service_config.py +50 -0
  315. cancan_microstack/services/infrasrv/interface/api/service_logs_api.py +49 -0
  316. cancan_microstack/services/infrasrv/interface/api/service_management_api.py +113 -0
  317. cancan_microstack/services/infrasrv/interface/api/service_registry.py +117 -0
  318. cancan_microstack/services/infrasrv/interface/api/workflow_api.py +303 -0
  319. cancan_microstack/services/infrasrv/interface/schedule/__init__.py +0 -0
  320. cancan_microstack/services/infrasrv/interface/schedule/cleanup.py +13 -0
  321. cancan_microstack/services/infrasrv/interface/schedule/health_check.py +27 -0
  322. cancan_microstack/services/infrasrv/interface/schedule/log_cleanup.py +26 -0
  323. cancan_microstack/services/infrasrv/interface/schedule/operation_tracker.py +25 -0
  324. cancan_microstack/services/infrasrv/interface/schedule/scheduler.py +39 -0
  325. cancan_microstack/services/infrasrv/interface/schedule/workflow_scheduler.py +115 -0
  326. cancan_microstack/services/infrasrv/router.py +341 -0
  327. cancan_microstack/services/opsbffsrv/__init__.py +4 -0
  328. cancan_microstack/services/opsbffsrv/application/__init__.py +0 -0
  329. cancan_microstack/services/opsbffsrv/application/async_operation_app.py +150 -0
  330. cancan_microstack/services/opsbffsrv/application/auth_app.py +285 -0
  331. cancan_microstack/services/opsbffsrv/application/caddy/__init__.py +0 -0
  332. cancan_microstack/services/opsbffsrv/application/caddy/access_log_analysis_app.py +344 -0
  333. cancan_microstack/services/opsbffsrv/application/caddy/access_log_ingestion_service.py +169 -0
  334. cancan_microstack/services/opsbffsrv/application/caddy/certificate_management_app.py +355 -0
  335. cancan_microstack/services/opsbffsrv/application/caddy/rate_limit_management_app.py +496 -0
  336. cancan_microstack/services/opsbffsrv/application/caddy/route_management_app.py +401 -0
  337. cancan_microstack/services/opsbffsrv/application/caddy/stats_aggregation_app.py +364 -0
  338. cancan_microstack/services/opsbffsrv/application/db_admin_app.py +103 -0
  339. cancan_microstack/services/opsbffsrv/application/db_init_app.py +283 -0
  340. cancan_microstack/services/opsbffsrv/application/logging/__init__.py +1 -0
  341. cancan_microstack/services/opsbffsrv/application/logging/log_query_app.py +28 -0
  342. cancan_microstack/services/opsbffsrv/application/service_config.py +158 -0
  343. cancan_microstack/services/opsbffsrv/application/service_logs_app.py +74 -0
  344. cancan_microstack/services/opsbffsrv/application/service_registry.py +36 -0
  345. cancan_microstack/services/opsbffsrv/application/workflow_ops_app.py +730 -0
  346. cancan_microstack/services/opsbffsrv/conf/__init__.py +0 -0
  347. cancan_microstack/services/opsbffsrv/conf/config.py +224 -0
  348. cancan_microstack/services/opsbffsrv/domain/__init__.py +0 -0
  349. cancan_microstack/services/opsbffsrv/domain/auth/__init__.py +0 -0
  350. cancan_microstack/services/opsbffsrv/domain/auth/admin_init.py +38 -0
  351. cancan_microstack/services/opsbffsrv/domain/auth/auth_domain.py +108 -0
  352. cancan_microstack/services/opsbffsrv/domain/caddy/__init__.py +0 -0
  353. cancan_microstack/services/opsbffsrv/domain/caddy/access_log_analysis.py +358 -0
  354. cancan_microstack/services/opsbffsrv/domain/caddy/certificate_management.py +325 -0
  355. cancan_microstack/services/opsbffsrv/domain/caddy/default_routes.py +53 -0
  356. cancan_microstack/services/opsbffsrv/domain/caddy/rate_limit_management.py +308 -0
  357. cancan_microstack/services/opsbffsrv/domain/caddy/route_management.py +279 -0
  358. cancan_microstack/services/opsbffsrv/domain/caddy/stats_aggregation.py +654 -0
  359. cancan_microstack/services/opsbffsrv/domain/db_admin/__init__.py +0 -0
  360. cancan_microstack/services/opsbffsrv/domain/db_admin/db_admin_domain.py +118 -0
  361. cancan_microstack/services/opsbffsrv/domain/db_init/__init__.py +3 -0
  362. cancan_microstack/services/opsbffsrv/domain/db_init/db_init_domain.py +358 -0
  363. cancan_microstack/services/opsbffsrv/domain/logging/__init__.py +1 -0
  364. cancan_microstack/services/opsbffsrv/domain/logging/log_query_domain.py +99 -0
  365. cancan_microstack/services/opsbffsrv/domain/service_config/__init__.py +0 -0
  366. cancan_microstack/services/opsbffsrv/domain/service_config/service_config.py +81 -0
  367. cancan_microstack/services/opsbffsrv/domain/service_registry/__init__.py +0 -0
  368. cancan_microstack/services/opsbffsrv/domain/service_registry/service_registry.py +292 -0
  369. cancan_microstack/services/opsbffsrv/infrastructure/__init__.py +0 -0
  370. cancan_microstack/services/opsbffsrv/infrastructure/api/__init__.py +0 -0
  371. cancan_microstack/services/opsbffsrv/infrastructure/api/infrasrv_api.py +242 -0
  372. cancan_microstack/services/opsbffsrv/infrastructure/auth/__init__.py +0 -0
  373. cancan_microstack/services/opsbffsrv/infrastructure/auth/captcha_service.py +67 -0
  374. cancan_microstack/services/opsbffsrv/infrastructure/auth/password_service.py +12 -0
  375. cancan_microstack/services/opsbffsrv/infrastructure/auth/redis_store.py +131 -0
  376. cancan_microstack/services/opsbffsrv/infrastructure/auth/totp_service.py +59 -0
  377. cancan_microstack/services/opsbffsrv/infrastructure/caddy/__init__.py +0 -0
  378. cancan_microstack/services/opsbffsrv/infrastructure/caddy/access_log_parser.py +307 -0
  379. cancan_microstack/services/opsbffsrv/infrastructure/caddy/admin_api_client.py +678 -0
  380. cancan_microstack/services/opsbffsrv/infrastructure/caddy/ip_geo_locator.py +176 -0
  381. cancan_microstack/services/opsbffsrv/infrastructure/db/__init__.py +0 -0
  382. cancan_microstack/services/opsbffsrv/infrastructure/db/model/__init__.py +0 -0
  383. cancan_microstack/services/opsbffsrv/infrastructure/db/model/admin_user_tbl.py +33 -0
  384. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_access_log_tbl.py +90 -0
  385. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_certificate_tbl.py +65 -0
  386. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_rate_limit_tbl.py +69 -0
  387. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_route_tbl.py +66 -0
  388. cancan_microstack/services/opsbffsrv/infrastructure/db/model/caddy_stats_tbl.py +78 -0
  389. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_action_log_tbl.py +44 -0
  390. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_config_tbl.py +30 -0
  391. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_info_tbl.py +51 -0
  392. cancan_microstack/services/opsbffsrv/infrastructure/db/model/service_instance_tbl.py +68 -0
  393. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/__init__.py +0 -0
  394. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/admin_user_operate.py +59 -0
  395. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_access_log.py +531 -0
  396. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_certificate.py +451 -0
  397. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_rate_limit.py +360 -0
  398. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_route.py +271 -0
  399. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/caddy_stats.py +343 -0
  400. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_action_log_op.py +57 -0
  401. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_config.py +86 -0
  402. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_info_op.py +79 -0
  403. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_instance.py +58 -0
  404. cancan_microstack/services/opsbffsrv/infrastructure/db/operate/service_registry.py +138 -0
  405. cancan_microstack/services/opsbffsrv/infrastructure/ddl_manager.py +31 -0
  406. cancan_microstack/services/opsbffsrv/infrastructure/mongo/__init__.py +1 -0
  407. cancan_microstack/services/opsbffsrv/infrastructure/mongo/log_query_repository.py +87 -0
  408. cancan_microstack/services/opsbffsrv/interface/__init__.py +0 -0
  409. cancan_microstack/services/opsbffsrv/interface/api/__init__.py +0 -0
  410. cancan_microstack/services/opsbffsrv/interface/api/async_operation_api.py +137 -0
  411. cancan_microstack/services/opsbffsrv/interface/api/auth_api.py +113 -0
  412. cancan_microstack/services/opsbffsrv/interface/api/caddy/__init__.py +3 -0
  413. cancan_microstack/services/opsbffsrv/interface/api/caddy/access_log_api.py +174 -0
  414. cancan_microstack/services/opsbffsrv/interface/api/caddy/certificate_api.py +235 -0
  415. cancan_microstack/services/opsbffsrv/interface/api/caddy/rate_limit_api.py +302 -0
  416. cancan_microstack/services/opsbffsrv/interface/api/caddy/route_api.py +250 -0
  417. cancan_microstack/services/opsbffsrv/interface/api/caddy/stats_api.py +243 -0
  418. cancan_microstack/services/opsbffsrv/interface/api/db_admin_api.py +62 -0
  419. cancan_microstack/services/opsbffsrv/interface/api/db_init_api.py +109 -0
  420. cancan_microstack/services/opsbffsrv/interface/api/instance_management_api.py +165 -0
  421. cancan_microstack/services/opsbffsrv/interface/api/log_query_api.py +41 -0
  422. cancan_microstack/services/opsbffsrv/interface/api/mongo_express_proxy_api.py +181 -0
  423. cancan_microstack/services/opsbffsrv/interface/api/pgweb_proxy_api.py +154 -0
  424. cancan_microstack/services/opsbffsrv/interface/api/rabbitmq_mgmt_proxy_api.py +518 -0
  425. cancan_microstack/services/opsbffsrv/interface/api/redis_commander_proxy_api.py +133 -0
  426. cancan_microstack/services/opsbffsrv/interface/api/service_config.py +146 -0
  427. cancan_microstack/services/opsbffsrv/interface/api/service_logs_api.py +81 -0
  428. cancan_microstack/services/opsbffsrv/interface/api/service_registry.py +66 -0
  429. cancan_microstack/services/opsbffsrv/interface/api/workflow_ops_api.py +413 -0
  430. cancan_microstack/services/opsbffsrv/interface/middleware/__init__.py +0 -0
  431. cancan_microstack/services/opsbffsrv/interface/middleware/auth_middleware.py +52 -0
  432. cancan_microstack/services/opsbffsrv/router.py +901 -0
  433. cancan_microstack/utils/__init__.py +1 -0
  434. cancan_microstack/utils/container_env.py +218 -0
  435. cancan_microstack-0.0.1.dist-info/METADATA +155 -0
  436. cancan_microstack-0.0.1.dist-info/RECORD +440 -0
  437. cancan_microstack-0.0.1.dist-info/WHEEL +5 -0
  438. cancan_microstack-0.0.1.dist-info/entry_points.txt +2 -0
  439. cancan_microstack-0.0.1.dist-info/licenses/LICENSE +21 -0
  440. cancan_microstack-0.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,68 @@
1
+ #!/bin/bash
2
+
3
+ # PostgreSQL 卷重置脚本
4
+ # 用于解决 PG 版本升级导致的数据目录结构不兼容问题
5
+
6
+ # 设置脚本错误时退出
7
+ set -e
8
+
9
+ # 获取脚本所在目录的绝对路径
10
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
11
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
12
+
13
+ echo "========================================="
14
+ echo "重置 PostgreSQL 数据卷"
15
+ echo "========================================="
16
+ echo "警告:这将删除现有的 PostgreSQL 数据卷!"
17
+ echo "仅在开发环境或数据已备份的情况下执行此操作。"
18
+ echo ""
19
+
20
+ read -p "确定要继续吗?(y/N) " -n 1 -r
21
+ echo
22
+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
23
+ echo "操作已取消"
24
+ exit 0
25
+ fi
26
+
27
+ # 切换到项目根目录
28
+ cd "$PROJECT_ROOT"
29
+
30
+ # 检测容器引擎
31
+ COMPOSE_CMD=""
32
+ if command -v podman-compose &> /dev/null; then
33
+ COMPOSE_CMD="podman-compose"
34
+ CONTAINER_CMD="podman"
35
+ elif command -v docker-compose &> /dev/null; then
36
+ COMPOSE_CMD="docker-compose"
37
+ CONTAINER_CMD="docker"
38
+ else
39
+ echo "❌ 未找到 docker-compose 或 podman-compose"
40
+ exit 1
41
+ fi
42
+
43
+ echo "1. 停止所有相关服务(解决依赖问题)..."
44
+ # 先停止所有业务服务,因为它们依赖数据库
45
+ if [ -f "docker-compose.services.yml" ]; then
46
+ $COMPOSE_CMD -f docker-compose.services.yml down 2>/dev/null || true
47
+ fi
48
+ # 停止基础设施服务
49
+ if [ -f "docker-compose.infra.yml" ]; then
50
+ $COMPOSE_CMD -f docker-compose.infra.yml down 2>/dev/null || true
51
+ fi
52
+
53
+ echo "2. 强制删除 PostgreSQL 容器..."
54
+ $CONTAINER_CMD rm -f my_app_postgres 2>/dev/null || true
55
+
56
+ echo "3. 强制删除其他相关容器(确保没有残留依赖)..."
57
+ $CONTAINER_CMD rm -f my_app_redis my_app_infrasrv my_app_opsbffsrv my_app_besrv my_app_pgweb my_app_caddy 2>/dev/null || true
58
+
59
+ echo "4. 删除数据卷 my_app_postgres_data..."
60
+ # 使用 -f 强制删除
61
+ $CONTAINER_CMD volume rm -f my_app_postgres_data 2>/dev/null || echo "数据卷可能已被删除"
62
+
63
+ echo ""
64
+ echo "✅ 数据卷已清理"
65
+ echo "请重新运行启动脚本以初始化新的数据库:"
66
+ echo " ./scripts/docker/start_compose.sh"
67
+ echo " 或"
68
+ echo " ./scripts/podman/start_compose_podman.sh"
@@ -0,0 +1,141 @@
1
+ #!/bin/bash
2
+
3
+ # 异步操作接口完整测试脚本
4
+ # 测试 opsbffsrv 的所有异步操作接口
5
+
6
+ set -e
7
+
8
+ BASE_URL="http://127.0.0.1:8080/v1/opsbffsrv"
9
+ SERVICE_NAME="besrv"
10
+
11
+ echo "========================================="
12
+ echo "异步操作接口测试"
13
+ echo "========================================="
14
+ echo "当前时间: $(date '+%Y-%m-%d %H:%M:%S')"
15
+ echo ""
16
+
17
+ # 颜色输出
18
+ GREEN='\033[0;32m'
19
+ RED='\033[0;31m'
20
+ YELLOW='\033[1;33m'
21
+ NC='\033[0m' # No Color
22
+
23
+ # 测试结果统计
24
+ TOTAL_TESTS=0
25
+ PASSED_TESTS=0
26
+ FAILED_TESTS=0
27
+
28
+ # 测试函数
29
+ test_api() {
30
+ local test_name=$1
31
+ local method=$2
32
+ local endpoint=$3
33
+ local data=$4
34
+
35
+ TOTAL_TESTS=$((TOTAL_TESTS + 1))
36
+ echo -e "${YELLOW}测试 ${TOTAL_TESTS}: ${test_name}${NC}"
37
+
38
+ if [ "$method" == "GET" ]; then
39
+ response=$(curl -s "${BASE_URL}${endpoint}")
40
+ else
41
+ response=$(curl -s -X POST "${BASE_URL}${endpoint}" \
42
+ -H "Content-Type: application/json" \
43
+ -d "$data")
44
+ fi
45
+
46
+ # 检查是否成功
47
+ success=$(echo "$response" | python3 -c "import sys, json; print(json.load(sys.stdin).get('success', False))")
48
+
49
+ if [ "$success" == "True" ]; then
50
+ echo -e "${GREEN}✓ 通过${NC}"
51
+ PASSED_TESTS=$((PASSED_TESTS + 1))
52
+
53
+ # 提取 operation_id (如果有)
54
+ operation_id=$(echo "$response" | python3 -c "import sys, json; data=json.load(sys.stdin).get('data', {}); print(data.get('operation_id', ''))" 2>/dev/null || echo "")
55
+ if [ -n "$operation_id" ]; then
56
+ echo " Operation ID: $operation_id"
57
+ echo "$operation_id" >> /tmp/test_operation_ids.txt
58
+ fi
59
+ else
60
+ echo -e "${RED}✗ 失败${NC}"
61
+ FAILED_TESTS=$((FAILED_TESTS + 1))
62
+ echo " 响应: $response"
63
+ fi
64
+ echo ""
65
+ }
66
+
67
+ # 清理临时文件
68
+ rm -f /tmp/test_operation_ids.txt
69
+
70
+ echo "========================================="
71
+ echo "1. 测试异步服务操作接口"
72
+ echo "========================================="
73
+ echo ""
74
+
75
+ # 1. 测试重启服务
76
+ test_api "重启服务" "POST" "/async/service/restart" "{\"service_name\": \"${SERVICE_NAME}\"}"
77
+
78
+ # 等待一下
79
+ sleep 1
80
+
81
+ # 2. 测试启动服务
82
+ test_api "启动服务" "POST" "/async/service/start" "{\"service_name\": \"${SERVICE_NAME}\"}"
83
+
84
+ sleep 1
85
+
86
+ # 3. 测试停止服务
87
+ test_api "停止服务" "POST" "/async/service/stop" "{\"service_name\": \"${SERVICE_NAME}\"}"
88
+
89
+ sleep 1
90
+
91
+ # 4. 测试扩缩容服务
92
+ test_api "扩缩容服务" "POST" "/async/service/scale" "{\"service_name\": \"${SERVICE_NAME}\", \"replicas\": 2}"
93
+
94
+ sleep 1
95
+
96
+ echo "========================================="
97
+ echo "2. 测试操作状态查询接口"
98
+ echo "========================================="
99
+ echo ""
100
+
101
+ # 等待操作执行
102
+ sleep 3
103
+
104
+ # 6. 查询最后一个操作的状态
105
+ if [ -f /tmp/test_operation_ids.txt ]; then
106
+ last_operation_id=$(tail -1 /tmp/test_operation_ids.txt)
107
+ test_api "查询操作状态" "GET" "/operation/status?operation_id=${last_operation_id}" ""
108
+ fi
109
+
110
+ # 7. 列出所有操作
111
+ test_api "列出所有操作 (限制5条)" "GET" "/operation/list?limit=5" ""
112
+
113
+ # 8. 按服务名筛选
114
+ test_api "按服务名筛选" "GET" "/operation/list?service_name=${SERVICE_NAME}.service&limit=3" ""
115
+
116
+ # 9. 按状态筛选
117
+ test_api "按状态筛选" "GET" "/operation/list?status=success&limit=3" ""
118
+
119
+ # 10. 组合筛选
120
+ test_api "组合筛选" "GET" "/operation/list?service_name=${SERVICE_NAME}.service&status=success&limit=3" ""
121
+
122
+ echo "========================================="
123
+ echo "测试结果汇总"
124
+ echo "========================================="
125
+ echo ""
126
+ echo "总测试数: ${TOTAL_TESTS}"
127
+ echo -e "${GREEN}通过: ${PASSED_TESTS}${NC}"
128
+ if [ $FAILED_TESTS -gt 0 ]; then
129
+ echo -e "${RED}失败: ${FAILED_TESTS}${NC}"
130
+ else
131
+ echo "失败: ${FAILED_TESTS}"
132
+ fi
133
+ echo ""
134
+
135
+ if [ $FAILED_TESTS -eq 0 ]; then
136
+ echo -e "${GREEN}✓ 所有测试通过!${NC}"
137
+ exit 0
138
+ else
139
+ echo -e "${RED}✗ 部分测试失败${NC}"
140
+ exit 1
141
+ fi
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ # 验证异步操作是否真的影响了容器
4
+
5
+ echo "========================================="
6
+ echo "验证异步操作对容器的实际影响"
7
+ echo "========================================="
8
+ echo ""
9
+
10
+ # 记录当前容器启动时间
11
+ BEFORE=$(podman inspect my_app_besrv --format '{{.State.StartedAt}}')
12
+ echo "容器当前启动时间: $BEFORE"
13
+ echo ""
14
+
15
+ # 执行重启操作
16
+ echo "========================================="
17
+ echo "执行重启操作..."
18
+ echo "========================================="
19
+ OPERATION_ID=$(curl -s -X POST 'http://127.0.0.1:8080/v1/opsbffsrv/async/service/restart' \
20
+ -H 'Content-Type: application/json' \
21
+ -d '{"service_name": "besrv"}' | \
22
+ python3 -c "import sys, json; print(json.load(sys.stdin)['data']['operation_id'])")
23
+
24
+ echo "Operation ID: $OPERATION_ID"
25
+ echo ""
26
+
27
+ # 等待操作完成
28
+ echo "等待操作完成(10秒)..."
29
+ sleep 10
30
+ echo ""
31
+
32
+ # 检查新的启动时间
33
+ AFTER=$(podman inspect my_app_besrv --format '{{.State.StartedAt}}')
34
+ echo "容器新的启动时间: $AFTER"
35
+ echo ""
36
+
37
+ # 比较
38
+ if [ "$BEFORE" != "$AFTER" ]; then
39
+ echo "✅ 验证成功:容器确实被重启了!"
40
+ echo " 启动时间已改变"
41
+ else
42
+ echo "❌ 验证失败:容器未被重启"
43
+ echo " 启动时间未改变"
44
+ fi
45
+ echo ""
46
+
47
+ # 检查 controllersrv 任务状态
48
+ echo "========================================="
49
+ echo "controllersrv 任务执行状态:"
50
+ echo "========================================="
51
+ curl -s "http://localhost:22100/v1/controllersrv/task/status?serial_number=$OPERATION_ID" | \
52
+ python3 -c "import sys, json; t=json.load(sys.stdin)['data']['task']; \
53
+ print(f\"任务状态: {t['status']}\"); \
54
+ print(f\"开始时间: {t.get('started_at', 'N/A')}\"); \
55
+ print(f\"完成时间: {t.get('finished_at', 'N/A')}\"); \
56
+ print(f\"执行结果: {t.get('result', {})}\"); \
57
+ print(f\"错误信息: {t.get('error', 'None')}\")"
58
+ echo ""
59
+
60
+ # 检查 infrasrv 操作记录
61
+ echo "========================================="
62
+ echo "infrasrv 操作记录状态:"
63
+ echo "========================================="
64
+ curl -s "http://127.0.0.1:8080/v1/opsbffsrv/operation/status?operation_id=$OPERATION_ID" | \
65
+ python3 -c "import sys, json; op=json.load(sys.stdin)['data']['operation']; \
66
+ print(f\"操作ID: {op['operation_id']}\"); \
67
+ print(f\"操作类型: {op['operation_type']}\"); \
68
+ print(f\"服务名称: {op['service_name']}\"); \
69
+ print(f\"操作状态: {op['status']}\"); \
70
+ print(f\"开始时间: {op.get('started_at', 'N/A')}\"); \
71
+ print(f\"完成时间: {op.get('completed_at', 'N/A')}\")"
72
+ echo ""
73
+
74
+ echo "========================================="
75
+ echo "验证完成"
76
+ echo "========================================="
@@ -0,0 +1,65 @@
1
+ # syntax=docker/dockerfile:1.7-labs
2
+
3
+ # 通用 Python 服务基础镜像
4
+ ARG PYTHON_VERSION=3.13-slim
5
+
6
+ FROM python:${PYTHON_VERSION} AS base
7
+
8
+ # 1:设置时区环境变量 ---
9
+ ENV TZ=Asia/Shanghai \
10
+ PYTHONDONTWRITEBYTECODE=1 \
11
+ PYTHONUNBUFFERED=1 \
12
+ PIP_DISABLE_PIP_VERSION_CHECK=1
13
+
14
+ WORKDIR /app
15
+
16
+ # 2:安装 tzdata 并应用时区配置 ---
17
+ # 在安装 curl 的同时安装 tzdata,减少镜像层数
18
+ RUN apt-get update && apt-get install -y --no-install-recommends \
19
+ curl \
20
+ tzdata \
21
+ && ln -fs /usr/share/zoneinfo/${TZ} /etc/localtime \
22
+ && echo ${TZ} > /etc/timezone \
23
+
24
+ # =============================
25
+ # 依赖安装阶段(带缓存)
26
+ # =============================
27
+ FROM base AS deps
28
+
29
+ ARG REQUIREMENTS_FILE=requirements.txt
30
+ COPY ${REQUIREMENTS_FILE} /tmp/requirements.txt
31
+
32
+ RUN python -m venv /opt/venv
33
+
34
+ ENV VIRTUAL_ENV=/opt/venv
35
+ ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
36
+
37
+ RUN --mount=type=cache,target=/root/.cache/pip \
38
+ pip install --upgrade pip \
39
+ && pip install --no-warn-script-location -r /tmp/requirements.txt
40
+
41
+ # =============================
42
+ # 运行时镜像
43
+ # =============================
44
+ FROM base AS runtime
45
+
46
+ ENV VIRTUAL_ENV=/opt/venv
47
+ ENV PATH="${VIRTUAL_ENV}/bin:${PATH}"
48
+
49
+ COPY --from=deps ${VIRTUAL_ENV} ${VIRTUAL_ENV}
50
+
51
+ # 复制代码(所有服务共享)
52
+ COPY src /app/src
53
+ COPY cmd /app/cmd
54
+ COPY tools /app/tools
55
+
56
+ # 预创建运行时需要挂载的目录
57
+ RUN mkdir -p /app/ddl /app/server_log_data
58
+
59
+ # 设置 Python 路径
60
+ ENV PYTHONPATH=/app/src:/app/src/libs:/app/cmd
61
+
62
+ EXPOSE 8080
63
+
64
+ # 启动命令由 docker-compose 的 command 字段覆盖
65
+ CMD ["python", "-c", "print('Specify command via docker-compose')"]
@@ -0,0 +1 @@
1
+ import{d as m,x as o,c as r,b as n,e as s,h as d,n as a,t as y,N as u}from"./index-CiFlm8oc.js";const x={class:"app-empty flex flex-col items-center justify-center py-12"},_={class:"text-gray-500 text-lg mb-2"},f={key:0,class:"mt-4"},g=m({__name:"AppEmpty",props:{type:{default:"empty"},description:{default:""}},setup(c){const t=c,i=o(()=>{const e={empty:"i-carbon-document-blank",error:"i-carbon-warning-hex",noPermission:"i-carbon-locked"};return e[t.type]||e.empty}),p=o(()=>{const e={empty:"text-gray-400",error:"text-red-400",noPermission:"text-orange-400"};return e[t.type]||e.empty}),l=o(()=>{if(t.description)return t.description;const e={empty:"暂无数据",error:"加载失败",noPermission:"暂无权限"};return e[t.type]||e.empty});return(e,b)=>(n(),r("div",x,[s("div",{class:a(["empty-icon text-6xl mb-4",p.value])},[s("i",{class:a(i.value)},null,2)],2),s("div",_,y(l.value),1),e.$slots.extra?(n(),r("div",f,[u(e.$slots,"extra")])):d("",!0)]))}});export{g as _};
@@ -0,0 +1 @@
1
+ import{I as A,J as N,K as oe,r as m,E as f,L as ie,d as ue,v as re,x as G,D as ce,G as de,o as ve,g as $,b as k,w as t,i as l,e as a,t as R,j as C,y as h,C as fe,z as me,A as pe,c as Z,h as ge,k as H,l as V,q as _e,_ as ye}from"./index-CiFlm8oc.js";import{u as Ce}from"./useDebounce-BRlqfXqf.js";import{P as be}from"./PageContainer-Byss-yUC.js";import{_ as ke}from"./AppEmpty.vue_vue_type_script_setup_true_lang-BOKUurnM.js";const we=r=>A.Get(N.SERVICE_CONFIG,{name:"getServiceConfig",params:{service_name:r,_t:Date.now()}}),xe=()=>A.Get(N.SERVICE_CONFIG_ALL,{name:"getAllServicesConfig",params:{_t:Date.now()}}),he=(r,p)=>A.Post(N.SERVICE_CONFIG,{conf_dict:p},{name:"addServiceConfig",params:{service_name:r}}),Ve=(r,p)=>A.Put(N.SERVICE_CONFIG,{conf_dict:p},{name:"updateServiceConfig",params:{service_name:r}}),Se=(r,p)=>A.Delete(N.SERVICE_CONFIG,{name:"deleteServiceConfigItem",params:{service_name:r,conf_key:p}}),Ee=oe("config",()=>{const r=m({}),p=m({}),I=m(""),d=m(!1),b=m(null),w=async s=>{d.value=!0,b.value=null,I.value=s;try{const o=await we(s);return r.value=o,o}catch(o){throw b.value=o,f.error("获取配置失败"),o}finally{d.value=!1}};return{currentConfig:r,allConfigs:p,currentServiceName:I,loading:d,error:b,fetchConfig:w,fetchAllConfigs:async()=>{d.value=!0,b.value=null;try{const s=await xe();return p.value=s,s}catch(s){throw b.value=s,f.error("获取配置失败"),s}finally{d.value=!1}},addConfig:async(s,o)=>{try{const n=await he(s,o);if(r.value={...r.value,...o},f.success("添加配置成功"),n.push_result){const{success_count:_,total_instances:c}=n.push_result;f.info(`已推送到 ${_}/${c} 个实例`)}return n}catch(n){throw f.error("添加配置失败"),n}},updateConfig:async(s,o)=>{try{const n=await Ve(s,o);if(r.value={...r.value,...o},f.success("更新配置成功"),n.push_result){const{success_count:_,total_instances:c}=n.push_result;f.info(`已推送到 ${_}/${c} 个实例`)}return n}catch(n){throw f.error("更新配置失败"),n}},deleteConfig:async(s,o)=>{try{await ie.confirm(`确定要删除配置项 "${o}" 吗?`,"确认删除",{type:"warning",confirmButtonText:"确定",cancelButtonText:"取消"});const n=await Se(s,o),_={...r.value};if(delete _[o],r.value=_,f.success("删除配置成功"),n.push_result){const{success_count:c,total_instances:T}=n.push_result;f.info(`已推送到 ${c}/${T} 个实例`)}return n}catch(n){if(n!=="cancel")throw f.error("删除配置失败"),n}},refreshConfig:async s=>{await w(s),f.success("刷新成功")},clearData:()=>{r.value={},p.value={},I.value="",b.value=null}}});function $e(r){return/^[A-Za-z0-9][A-Za-z0-9_.-]*$/.test(r)}const Ie={class:"config-actions"},Re={class:"stats-grid"},Ae={class:"stat-item text-center"},Ne={class:"stat-value stat-value-primary"},Be={class:"stat-item text-center"},De={class:"stat-value stat-value-success"},Fe={class:"stat-item text-center"},Ge={class:"stat-value stat-value-tertiary"},Te={class:"min-h-300px"},ze={class:"config-key"},Le={class:"config-key-text"},Me={key:1,class:"flex items-center justify-between group"},Oe={class:"font-mono text-sm"},Pe=ue({__name:"ConfigManage",setup(r){const p=ce(),I=_e(),d=Ee(),{currentConfig:b,loading:w}=re(d),g=G(()=>p.params.serviceName),y=Ce("",300),B=G(()=>Object.entries(b.value).map(([i,e])=>({key:i,value:e,editable:!0}))),P=G(()=>B.value.length),S=m("刚刚"),D=G(()=>{if(!y.value)return B.value;const i=y.value.toLowerCase();return B.value.filter(e=>e.key.toLowerCase().includes(i)||e.value.toLowerCase().includes(i))}),s=m(!1),o=m("add"),n=m(),_=m(!1),c=m({key:"",value:""}),T={key:[{required:!0,message:"请输入配置键",trigger:"blur"},{validator:(i,e,v)=>{$e(e)?v():v(new Error("请输入合法配置键:字母/数字开头,仅允许字母、数字、下划线、点、中划线"))},trigger:"blur"}],value:[{required:!0,message:"请输入配置值",trigger:"blur"}]},z=m(""),E=m(""),J=()=>{I.back()},X=async()=>{await d.refreshConfig(g.value),S.value="刚刚"},U=()=>{o.value="add",c.value={key:"",value:""},s.value=!0},Y=i=>{o.value="edit",c.value={key:i.key,value:i.value},s.value=!0},Q=async i=>{try{await d.deleteConfig(g.value,i.key),S.value="刚刚"}catch{}},W=i=>{navigator.clipboard.writeText(i.value).then(()=>{f.success("复制成功")}).catch(()=>{f.error("复制失败")})},ee=i=>{z.value=i.key,E.value=i.value},K=async i=>{if(E.value===i.value){L();return}try{await d.updateConfig(g.value,{[i.key]:E.value}),S.value="刚刚",L()}catch{}},L=()=>{z.value="",E.value=""},te=async()=>{n.value&&await n.value.validate(async i=>{if(i){_.value=!0;try{o.value==="add"?await d.addConfig(g.value,{[c.value.key]:c.value.value}):await d.updateConfig(g.value,{[c.value.key]:c.value.value}),S.value="刚刚",s.value=!1,c.value={key:"",value:""}}catch{}finally{_.value=!1}}})};return de(g,()=>{d.fetchConfig(g.value)},{immediate:!0}),ve(async()=>{await d.fetchConfig(g.value)}),(i,e)=>{const v=C("el-button"),M=C("el-card"),F=C("el-input"),O=C("el-table-column"),j=C("el-space"),ae=C("el-table"),q=C("el-form-item"),le=C("el-form"),se=C("el-dialog"),ne=pe("loading");return k(),$(be,{title:`${g.value} 配置管理`,subtitle:"管理服务的配置项",icon:"i-carbon-settings"},{actions:t(()=>[a("div",Ie,[l(v,{onClick:J,class:"action-btn back-btn"},{default:t(()=>[...e[7]||(e[7]=[a("i",{class:"i-carbon-arrow-left"},null,-1),a("span",{class:"btn-text"},"返回",-1)])]),_:1}),l(v,{type:"success",onClick:U,class:"action-btn add-btn"},{default:t(()=>[...e[8]||(e[8]=[a("i",{class:"i-carbon-add"},null,-1),a("span",{class:"btn-text"},"添加",-1)])]),_:1}),l(v,{onClick:X,loading:h(w),class:"action-btn refresh-btn"},{default:t(()=>[...e[9]||(e[9]=[a("i",{class:"i-carbon-renew"},null,-1),a("span",{class:"btn-text"},"刷新",-1)])]),_:1},8,["loading"])])]),default:t(()=>[l(M,{class:"mb-4 stats-card"},{default:t(()=>[a("div",Re,[a("div",Ae,[a("div",Ne,R(P.value),1),e[10]||(e[10]=a("div",{class:"stat-label"},"配置项总数",-1))]),a("div",Be,[a("div",De,R(g.value),1),e[11]||(e[11]=a("div",{class:"stat-label"},"服务名称",-1))]),a("div",Fe,[a("div",Ge,R(S.value),1),e[12]||(e[12]=a("div",{class:"stat-label"},"最后更新",-1))])])]),_:1}),l(M,{class:"mb-4"},{default:t(()=>[l(F,{modelValue:h(y),"onUpdate:modelValue":e[0]||(e[0]=u=>fe(y)?y.value=u:null),placeholder:"搜索配置项名称或值",class:"w-full",clearable:""},{prefix:t(()=>[...e[13]||(e[13]=[a("i",{class:"i-carbon-search"},null,-1)])]),_:1},8,["modelValue"])]),_:1}),l(M,null,{header:t(()=>[...e[14]||(e[14]=[a("span",{class:"text-lg font-semibold"},"配置列表",-1)])]),default:t(()=>[me((k(),Z("div",Te,[!h(w)&&D.value.length>0?(k(),$(ae,{key:0,data:D.value,stripe:"",style:{width:"100%"}},{default:t(()=>[l(O,{prop:"key",label:"配置键","min-width":"200"},{default:t(({row:u})=>[a("div",ze,[e[15]||(e[15]=a("i",{class:"i-carbon-settings-adjust config-icon"},null,-1)),a("span",Le,R(u.key),1)])]),_:1}),l(O,{prop:"value",label:"配置值","min-width":"300"},{default:t(({row:u})=>[z.value===u.key?(k(),$(F,{key:0,modelValue:E.value,"onUpdate:modelValue":e[1]||(e[1]=x=>E.value=x),onBlur:x=>K(u),onKeyup:[H(x=>K(u),["enter"]),H(L,["esc"])]},null,8,["modelValue","onBlur","onKeyup"])):(k(),Z("div",Me,[a("span",Oe,R(u.value),1),l(v,{text:"",size:"small",class:"opacity-0 group-hover:opacity-100 transition-opacity",onClick:x=>ee(u)},{default:t(()=>[...e[16]||(e[16]=[a("i",{class:"i-carbon-edit"},null,-1)])]),_:1},8,["onClick"])]))]),_:1}),l(O,{label:"操作",width:"200",fixed:"right"},{default:t(({row:u})=>[l(j,null,{default:t(()=>[l(v,{text:"",type:"primary",size:"small",onClick:x=>Y(u)},{default:t(()=>[...e[17]||(e[17]=[a("i",{class:"i-carbon-edit mr-1"},null,-1),V(" 编辑 ",-1)])]),_:1},8,["onClick"]),l(v,{text:"",type:"danger",size:"small",onClick:x=>Q(u)},{default:t(()=>[...e[18]||(e[18]=[a("i",{class:"i-carbon-trash-can mr-1"},null,-1),V(" 删除 ",-1)])]),_:1},8,["onClick"]),l(v,{text:"",type:"info",size:"small",onClick:x=>W(u)},{default:t(()=>[...e[19]||(e[19]=[a("i",{class:"i-carbon-copy mr-1"},null,-1),V(" 复制 ",-1)])]),_:1},8,["onClick"])]),_:2},1024)]),_:1})]),_:1},8,["data"])):!h(w)&&D.value.length===0?(k(),$(ke,{key:1,type:"empty",description:h(y)?"未找到匹配的配置项":"暂无配置数据"},{extra:t(()=>[h(y)?(k(),$(v,{key:0,onClick:e[2]||(e[2]=u=>y.value="")},{default:t(()=>[...e[20]||(e[20]=[V(" 清空搜索 ",-1)])]),_:1})):(k(),$(v,{key:1,type:"primary",onClick:U},{default:t(()=>[...e[21]||(e[21]=[V(" 添加配置 ",-1)])]),_:1}))]),_:1},8,["description"])):ge("",!0)])),[[ne,h(w)]])]),_:1}),l(se,{modelValue:s.value,"onUpdate:modelValue":e[6]||(e[6]=u=>s.value=u),title:o.value==="add"?"添加配置":"编辑配置",width:"600px"},{footer:t(()=>[l(j,null,{default:t(()=>[l(v,{onClick:e[5]||(e[5]=u=>s.value=!1)},{default:t(()=>[...e[23]||(e[23]=[V("取消",-1)])]),_:1}),l(v,{type:"primary",onClick:te,loading:_.value},{default:t(()=>[...e[24]||(e[24]=[V(" 确定 ",-1)])]),_:1},8,["loading"])]),_:1})]),default:t(()=>[l(le,{ref_key:"configFormRef",ref:n,model:c.value,rules:T,"label-width":"100px"},{default:t(()=>[l(q,{label:"配置键",prop:"key"},{default:t(()=>[l(F,{modelValue:c.value.key,"onUpdate:modelValue":e[3]||(e[3]=u=>c.value.key=u),placeholder:"字母/数字开头,允许字母、数字、下划线、点、中划线,如:MAX_RETRY 或 app.config-v1",disabled:o.value==="edit"},null,8,["modelValue","disabled"]),e[22]||(e[22]=a("div",{class:"form-hint"}," 字母或数字开头;可包含字母、数字、下划线、点、中划线 ",-1))]),_:1}),l(q,{label:"配置值",prop:"value"},{default:t(()=>[l(F,{modelValue:c.value.value,"onUpdate:modelValue":e[4]||(e[4]=u=>c.value.value=u),type:"textarea",rows:4,placeholder:"请输入配置值"},null,8,["modelValue"])]),_:1})]),_:1},8,["model"])]),_:1},8,["modelValue","title"])]),_:1},8,["title"])}}}),Ze=ye(Pe,[["__scopeId","data-v-23bbf448"]]);export{Ze as default};
@@ -0,0 +1 @@
1
+ .stats-card[data-v-23bbf448] .el-card__body{padding:24px}.stats-grid[data-v-23bbf448]{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:24px}.stat-item[data-v-23bbf448]{padding:20px;background:var(--bg-secondary);border-radius:var(--radius-md);border:1px solid var(--border-tertiary)}.stat-value[data-v-23bbf448]{font-size:32px;font-weight:700;line-height:1.2;margin-bottom:8px}.stat-value-primary[data-v-23bbf448]{color:var(--primary-500)}.stat-value-success[data-v-23bbf448]{color:var(--success-500)}.stat-value-tertiary[data-v-23bbf448]{color:var(--warning-500)}.stat-label[data-v-23bbf448]{font-size:14px;color:var(--text-secondary)}.config-key[data-v-23bbf448]{display:flex;align-items:center;gap:8px}.config-icon[data-v-23bbf448]{color:var(--primary-500);font-size:16px;flex-shrink:0}.config-key-text[data-v-23bbf448]{font-family:SF Mono,Consolas,Monaco,monospace;font-weight:600;color:var(--text-primary)}.form-hint[data-v-23bbf448]{font-size:12px;color:var(--text-tertiary);margin-top:4px}.min-h-300px[data-v-23bbf448]{min-height:300px}.config-actions[data-v-23bbf448]{display:flex;gap:8px;flex-wrap:wrap}.action-btn[data-v-23bbf448]{display:flex;align-items:center;gap:6px}@media (max-width: 768px){.config-actions[data-v-23bbf448]{width:100%}.action-btn[data-v-23bbf448]{flex:1;min-width:0;justify-content:center;padding:8px 12px}.btn-text[data-v-23bbf448]{font-size:13px}[data-v-23bbf448] .el-card{margin-bottom:12px}[data-v-23bbf448] .el-card__header{padding:12px 16px}[data-v-23bbf448] .el-card__body{padding:16px}.stat-item[data-v-23bbf448]{padding:16px 12px}.stat-value[data-v-23bbf448]{font-size:24px}.stat-label[data-v-23bbf448],[data-v-23bbf448] .el-table{font-size:13px}[data-v-23bbf448] .el-table th,[data-v-23bbf448] .el-table td{padding:8px 0}[data-v-23bbf448] .el-dialog{width:95%!important;margin:20px auto!important}[data-v-23bbf448] .el-dialog__body{padding:16px}[data-v-23bbf448] .el-form-item__label{font-size:13px}}@media (min-width: 769px){.action-btn[data-v-23bbf448]{min-width:100px}.btn-text[data-v-23bbf448]{margin-left:6px}}
@@ -0,0 +1 @@
1
+ import{d as K,x as Y,D as Z,r as w,G as ee,o as te,H as le,g as d,b as l,w as t,i as a,h as g,c as i,e as n,l as c,j as m,z as ne,t as f,P as se,n as oe,F as k,B as h,E as ae,_ as re}from"./index-CiFlm8oc.js";import{P as ie}from"./PageContainer-Byss-yUC.js";const P="/v1/opsbffsrv",R={pgweb:{id:"pgweb",title:"PGWeb 数据库控制台",subtitle:"PostgreSQL Web UI",icon:"i-carbon-data-base",iframeUrl:`${P}/pgweb/`,description:"通过 pgweb 直接管理 PostgreSQL,支持 SQL 查询、表结构调整与导出。",features:["SQL 查询","表结构浏览","结果导出","快捷键执行"],notes:["仅在内网环境开放,请勿暴露公网。","执行数据修改指令前请再次确认条件。","若页面空白,请检查 opsbffsrv 与 Caddy 代理状态。"],infoSections:[{title:"快捷键",tags:["Cmd/Ctrl + Enter 执行","Cmd/Ctrl + S 保存查询"]},{title:"安全提醒",description:"请谨慎执行 DELETE、DROP、UPDATE 等语句,建议先备份关键数据。",alertType:"warning"}],docLinks:[{label:"PGWeb 官方文档",url:"https://github.com/sosedoff/pgweb"}]},"redis-commander":{id:"redis-commander",title:"Redis Commander",subtitle:"Redis Web 管理器",icon:"i-carbon-ibm-data-replication",iframeUrl:`${P}/redis_commander/`,description:"查看与编辑 Redis key,支持多 DB 与 TTL 监控。",features:["Key 搜索","结构化查看","TTL 监控","命令行执行"],notes:["默认只读,请在执行写操作前确认环境。","若无法连接,请确认 Redis 内部服务是否就绪。"],infoSections:[{title:"使用提示",tags:["支持 JSON/Hash 预览","命令历史可搜索"]}],docLinks:[{label:"项目主页",url:"https://github.com/joeferner/redis-commander"}]},"mongo-express":{id:"mongo-express",title:"Mongo Express",subtitle:"日志存储浏览器",icon:"i-carbon-tree-view",iframeUrl:`${P}/mongo_express/`,description:"直接浏览 infra_logging.service_logs 库,支持集合内查询与导出。",features:["集合预览","文档编辑","索引查看","导出 JSON"],notes:["日志库数据量较大,查询时请设置条件。","后台依赖 Mongo 与 RabbitMQ,请关注基础设施健康。"],infoSections:[{title:"集合关注",tags:["infra_logging.service_logs","infra_logging.metadata"]}],docLinks:[{label:"Mongo Express 官方",url:"https://github.com/mongo-express/mongo-express"}]},"rabbitmq-mgmt":{id:"rabbitmq-mgmt",title:"RabbitMQ Management",subtitle:"消息队列监控",icon:"i-carbon-data-1",iframeUrl:`${P}/rabbitmq_mgmt/`,description:"查看交换机、队列与消息堆积,配合日志管线排查延迟。",features:["队列监控","连接/信道管理","流量速率可视化"],notes:["默认账户具备只读权限,执行写操作前请确认。","如需访问宿主暴露端口,可打开 35673 端口代理。"],infoSections:[{title:"关键队列",tags:["besrv.logs.ingress","infra.logging.persist"]}],docLinks:[{label:"RabbitMQ Docs",url:"https://www.rabbitmq.com/management.html"}],disableCacheParam:!0}},ue=C=>C&&R[C]?R[C]:R.pgweb,ce={class:"page-actions"},de={class:"mt-2"},me={key:0,class:"loading-container"},pe={class:"loading-text"},fe={key:1,class:"error-container"},ve={key:2,class:"error-container"},be=["src"],ge={class:"card-header"},_e={class:"help-description"},ye={key:0,class:"help-tags"},ke={key:1,class:"text-secondary"},we={key:3,class:"note-list"},he={key:4,class:"doc-links"},Ce={key:1,class:"fullscreen-actions"},Le=K({__name:"ConsoleManage",setup(C){const Q=Z(),s=Y(()=>ue(Q.meta.consoleId)),v=w(!0),p=w(""),b=w(!1),L=()=>{const r=s.value.iframeUrl;if(s.value.disableCacheParam)return r;const e=r.includes("?")?"&":"?";return`${r}${e}ts=${Date.now()}`},y=w(""),_=w(!1),$=r=>r===401||r===403,q=r=>{const e=r.toLowerCase();return["login","signin","auth"].some(u=>e.includes(u))},G=async()=>{const r=s.value.iframeUrl;try{const e=await fetch(r,{method:"GET",credentials:"include",headers:{"X-Requested-With":"XMLHttpRequest"}});if($(e.status)){console.warn("[Precheck] Auth status detected:",e.status),_.value=!0;return}if(e.redirected&&q(e.url)){console.warn("[Precheck] Redirect to login detected:",e.url),_.value=!0;return}y.value=L(),_.value=!1}catch(e){console.warn("[Precheck] Network error, attempting to render iframe anyway:",e),y.value=L(),_.value=!1}};ee(()=>s.value.id,()=>{v.value=!0,p.value="",y.value=L()});const T=()=>{v.value=!1},W=()=>{T(),p.value=""},A=()=>{T(),p.value="无法连接到控制台,请检查服务是否正常运行",ae.error("加载失败")},S=()=>{v.value=!0,p.value="",y.value=L()},M=()=>{S()},F=()=>{b.value=!0,document.body.style.overflow="hidden"},E=()=>{b.value=!1,document.body.style.overflow=""},I=r=>{r.key==="Escape"&&b.value&&E(),r.key==="F11"&&(r.preventDefault(),b.value?E():F())},x=()=>{window.open(s.value.iframeUrl,"_blank","noopener")};return te(()=>{window.addEventListener("keydown",I),G().then(()=>{_.value&&(setTimeout(()=>{x()},200),v.value=!1,p.value="该控制台无法在内嵌 iframe 中直接访问,已在新标签打开。")}),setTimeout(()=>{v.value&&(v.value=!1,p.value)},15e3)}),le(()=>{window.removeEventListener("keydown",I),document.body.style.overflow=""}),(r,e)=>{const u=m("el-button"),U=m("el-alert"),V=m("el-icon"),D=m("el-result"),N=m("el-card"),z=m("el-tag"),H=m("el-divider"),X=m("el-descriptions-item"),j=m("el-descriptions"),J=m("el-link"),B=m("el-tooltip");return l(),d(ie,{title:s.value.title,icon:s.value.icon},{actions:t(()=>[n("div",ce,[a(u,{onClick:S},{default:t(()=>[...e[0]||(e[0]=[n("i",{class:"i-carbon-renew mr-2"},null,-1),n("span",null,"刷新",-1)])]),_:1}),b.value?(l(),d(u,{key:1,onClick:E},{default:t(()=>[...e[2]||(e[2]=[n("i",{class:"i-carbon-minimize mr-2"},null,-1),n("span",null,"退出全屏",-1)])]),_:1})):(l(),d(u,{key:0,onClick:F},{default:t(()=>[...e[1]||(e[1]=[n("i",{class:"i-carbon-fit-to-screen mr-2"},null,-1),n("span",null,"全屏",-1)])]),_:1})),a(u,{onClick:x},{default:t(()=>[...e[3]||(e[3]=[n("i",{class:"i-carbon-launch mr-2"},null,-1),n("span",null,"新标签打开",-1)])]),_:1})])]),default:t(()=>[a(U,{type:"info","show-icon":"",closable:!1,class:"mb-4 console-tip",title:"控制台加载提示"},{default:t(()=>[e[9]||(e[9]=n("p",null,"若页面长时间加载或加载失败,请检查 Caddy / opsbffsrv 代理以及相关服务是否健康。",-1)),n("p",de,[e[6]||(e[6]=c("如果页面加载后显示空白、部分异常或报错,说明该组件服务内部发生故障,请联系后端排查。您仍可以尝试 ",-1)),a(u,{type:"primary",link:"",onClick:S},{default:t(()=>[...e[4]||(e[4]=[c("刷新",-1)])]),_:1}),e[7]||(e[7]=c(" 或 ",-1)),a(u,{type:"primary",link:"",onClick:x},{default:t(()=>[...e[5]||(e[5]=[c("在新标签页打开",-1)])]),_:1}),e[8]||(e[8]=c("。",-1))])]),_:1}),a(N,{class:oe(["pgweb-card",{"pgweb-fullscreen":b.value}])},{default:t(()=>[v.value?(l(),i("div",me,[a(V,{class:"is-loading",size:40},{default:t(()=>[...e[10]||(e[10]=[n("i",{class:"i-carbon-progress-bar"},null,-1)])]),_:1}),n("p",pe,"正在加载 "+f(s.value.title)+"...",1)])):p.value?(l(),i("div",fe,[a(D,{icon:"error",title:"加载失败","sub-title":p.value},{extra:t(()=>[a(u,{type:"primary",onClick:M},{default:t(()=>[...e[11]||(e[11]=[n("i",{class:"i-carbon-renew mr-2"},null,-1),c(" 重试 ",-1)])]),_:1})]),_:1},8,["sub-title"])])):_.value?(l(),i("div",ve,[a(D,{icon:"warning",title:"嵌入检测失败","sub-title":"该控制台无法在内嵌 iframe 中直接访问"},{extra:t(()=>[a(u,{type:"primary",onClick:x},{default:t(()=>[...e[12]||(e[12]=[n("i",{class:"i-carbon-launch mr-2"},null,-1),c(" 在新标签页打开 ",-1)])]),_:1}),a(u,{onClick:M},{default:t(()=>[...e[13]||(e[13]=[n("i",{class:"i-carbon-renew mr-2"},null,-1),c(" 再试一次 ",-1)])]),_:1})]),_:1})])):g("",!0),ne(n("iframe",{src:y.value,class:"pgweb-iframe",frameborder:"0",onLoad:W,onError:A},null,40,be),[[se,!v.value&&!p.value&&!_.value&&y.value]])]),_:1},8,["class"]),b.value?g("",!0):(l(),d(N,{key:0,class:"help-card mt-4"},{header:t(()=>[n("div",ge,[e[14]||(e[14]=n("i",{class:"i-carbon-help mr-2"},null,-1)),n("span",null,f(s.value.title)+" 使用指南",1)])]),default:t(()=>[n("p",_e,f(s.value.description),1),s.value.features.length?(l(),i("div",ye,[(l(!0),i(k,null,h(s.value.features,o=>(l(),d(z,{key:o,size:"small",type:"info",class:"mr-2 mb-2"},{default:t(()=>[c(f(o),1)]),_:2},1024))),128))])):g("",!0),s.value.infoSections?.length||s.value.notes.length?(l(),d(H,{key:1})):g("",!0),s.value.infoSections?.length?(l(),d(j,{key:2,column:1,border:""},{default:t(()=>[(l(!0),i(k,null,h(s.value.infoSections,o=>(l(),d(X,{key:o.title,label:o.title},{default:t(()=>[o.tags?.length?(l(!0),i(k,{key:0},h(o.tags,O=>(l(),d(z,{key:O,size:"small",class:"mr-2 mb-2",type:o.alertType==="warning"?"warning":"info"},{default:t(()=>[c(f(O),1)]),_:2},1032,["type"]))),128)):(l(),i(k,{key:1},[o.alertType?(l(),d(U,{key:0,type:o.alertType==="danger"?"error":o.alertType,closable:!1,"show-icon":""},{title:t(()=>[c(f(o.description),1)]),_:2},1032,["type"])):(l(),i("p",ke,f(o.description),1))],64))]),_:2},1032,["label"]))),128))]),_:1})):g("",!0),s.value.notes.length?(l(),i("ul",we,[(l(!0),i(k,null,h(s.value.notes,o=>(l(),i("li",{key:o},f(o),1))),128))])):g("",!0),s.value.docLinks?.length?(l(),i("div",he,[e[15]||(e[15]=n("span",{class:"text-secondary"},"参考文档:",-1)),(l(!0),i(k,null,h(s.value.docLinks,o=>(l(),d(J,{key:o.url,href:o.url,target:"_blank",rel:"noopener",type:"primary",class:"mr-2"},{default:t(()=>[c(f(o.label),1)]),_:2},1032,["href"]))),128))])):g("",!0)]),_:1})),b.value?(l(),i("div",Ce,[a(B,{content:"刷新",placement:"left"},{default:t(()=>[a(u,{circle:"",onClick:S},{default:t(()=>[...e[16]||(e[16]=[n("i",{class:"i-carbon-renew"},null,-1)])]),_:1})]),_:1}),a(B,{content:"退出全屏",placement:"left"},{default:t(()=>[a(u,{circle:"",onClick:E},{default:t(()=>[...e[17]||(e[17]=[n("i",{class:"i-carbon-minimize"},null,-1)])]),_:1})]),_:1})])):g("",!0)]),_:1},8,["title","icon"])}}}),xe=re(Le,[["__scopeId","data-v-1b0c8a40"]]);export{xe as default};
@@ -0,0 +1 @@
1
+ .page-actions[data-v-1b0c8a40]{display:flex;gap:8px;flex-wrap:wrap}@media (max-width: 768px){.page-actions[data-v-1b0c8a40]{flex-direction:column;width:100%;gap:12px}.page-actions .el-button[data-v-1b0c8a40]{width:100%;margin:0}}.pgweb-card[data-v-1b0c8a40]{border:none;background:var(--bg-elevated);min-height:calc(100vh - 300px);position:relative;overflow:hidden}.pgweb-fullscreen[data-v-1b0c8a40]{position:fixed;inset:0;z-index:9999;min-height:100vh;margin:0;border-radius:0}.pgweb-iframe[data-v-1b0c8a40]{width:100%;height:calc(100vh - 300px);border:none;display:block;background:var(--bg-primary)}.pgweb-fullscreen .pgweb-iframe[data-v-1b0c8a40]{height:100vh}.loading-container[data-v-1b0c8a40]{display:flex;flex-direction:column;align-items:center;justify-content:center;min-height:calc(100vh - 300px);gap:var(--spacing-4)}.loading-text[data-v-1b0c8a40]{color:var(--text-secondary);font-size:14px;margin:0}.error-container[data-v-1b0c8a40]{display:flex;align-items:center;justify-content:center;min-height:calc(100vh - 300px)}.help-card[data-v-1b0c8a40]{border:none;background:var(--bg-elevated)}.card-header[data-v-1b0c8a40]{display:flex;align-items:center;font-weight:600;color:var(--text-primary)}.help-description[data-v-1b0c8a40]{color:var(--text-secondary);margin-bottom:var(--spacing-3)}.help-tags[data-v-1b0c8a40]{margin-bottom:var(--spacing-3)}.note-list[data-v-1b0c8a40]{margin-top:var(--spacing-3);padding-left:20px;color:var(--text-secondary)}.note-list li[data-v-1b0c8a40]{margin-bottom:6px}.doc-links[data-v-1b0c8a40]{margin-top:var(--spacing-3)}.fullscreen-actions[data-v-1b0c8a40]{position:fixed;right:var(--spacing-6);bottom:var(--spacing-6);z-index:10000;display:flex;flex-direction:column;align-items:center;gap:var(--spacing-3);padding:var(--spacing-3);background:var(--bg-elevated);border-radius:var(--radius-lg);box-shadow:var(--shadow-lg)}.fullscreen-actions .el-button[data-v-1b0c8a40]{width:48px;height:48px;font-size:20px;display:flex;align-items:center;justify-content:center;margin:0}.console-tip code[data-v-1b0c8a40],code[data-v-1b0c8a40]{padding:2px 8px;background:var(--bg-tertiary);border-radius:var(--radius-sm);font-family:Monaco,Courier New,monospace;font-size:13px;color:var(--error-500)}@media (max-width: 768px){.pgweb-iframe[data-v-1b0c8a40]{height:calc(100vh - 250px)}.loading-container[data-v-1b0c8a40],.error-container[data-v-1b0c8a40]{min-height:calc(100vh - 250px)}.fullscreen-actions[data-v-1b0c8a40]{right:var(--spacing-4);bottom:var(--spacing-4)}.fullscreen-actions .el-button[data-v-1b0c8a40]{width:40px;height:40px;font-size:18px}}:root[data-theme=dark] .pgweb-iframe[data-v-1b0c8a40]{background:var(--bg-secondary)}:root[data-theme=dark] code[data-v-1b0c8a40]{background:var(--bg-secondary);color:var(--error-400)}.loading-container .is-loading[data-v-1b0c8a40]{animation:rotate-1b0c8a40 1s linear infinite}@keyframes rotate-1b0c8a40{0%{transform:rotate(0)}to{transform:rotate(360deg)}}[data-v-1b0c8a40] .el-descriptions{--el-descriptions-item-bordered-label-background: var(--bg-secondary);--el-descriptions-row-bg-color: var(--bg-elevated)}[data-v-1b0c8a40] .el-result__title,[data-v-1b0c8a40] .el-result__subtitle{color:var(--text-primary)}
@@ -0,0 +1 @@
1
+ import{d as F,v as j,x as n,c as p,b as r,e as s,i as S,w as m,l as b,y as i,j as H,t as l,n as v,z as M,A as P,g as w,h as G,F as J,B as K,q as Q,E as k,_ as U}from"./index-CiFlm8oc.js";import{u as W}from"./service-BYlgGPs_.js";import{O as f}from"./service-operation-6GzLw2Z1.js";import{S as X}from"./ServiceCard-BJUhWnA-.js";import{_ as Y}from"./AppEmpty.vue_vue_type_script_setup_true_lang-BOKUurnM.js";import"./OperationProgressDialog-BdEYwqFq.js";const Z={class:"dashboard-container"},ss={class:"dashboard-header animate-fade-in"},ts={class:"header-content"},es={class:"stats-grid animate-fade-in",style:{"animation-delay":"100ms"}},as={class:"stat-card card gradient-primary"},ns={class:"stat-content"},is={class:"stat-info"},os={class:"stat-value"},rs={class:"stat-card card gradient-success"},ls={class:"stat-content"},cs={class:"stat-info"},ds={class:"stat-value"},vs={class:"stat-card card gradient-warning"},us={class:"stat-content"},ps={class:"stat-info"},ms={class:"stat-value"},fs={class:"stat-content"},gs={class:"stat-info"},hs={class:"stat-value"},_s={class:"stat-trend"},ys={class:"services-section animate-fade-in",style:{"animation-delay":"200ms"}},Ss={class:"services-grid"},bs=F({__name:"DashboardNew",setup(ws){const a=Q(),c=W(),{services:d,loading:u,healthyServices:C,systemHealthRate:o}=j(c),R=n(()=>d.value.length),N=n(()=>C.value.length),D=n(()=>d.value.reduce((e,t)=>e+(t.total_instances||0),0)),T=n(()=>{const e=o.value;return e>=90?"gradient-success":e>=70?"gradient-warning":"gradient-error"}),g=n(()=>{const e=o.value;return e>=90?"success":e>=70?"warning":"error"}),x=n(()=>{const e=o.value;return e>=90?"i-carbon-checkmark-filled":e>=70?"i-carbon-warning":"i-carbon-warning-filled"}),q=n(()=>{const e=o.value;return e>=90?"优秀":e>=70?"良好":"需关注"}),h=async()=>{await c.fetchServices(),k.success("数据已刷新")},B=e=>{const t=typeof e=="string"?e:e.service_name;a.push(`/services/${t}`)},$=e=>{const t=typeof e=="string"?e:e.service_name;a.push(`/services/${t}`)},E=e=>{const t=typeof e=="string"?e:e.service_name;a.push(`/config/${t}`)},I=async e=>{const t=typeof e=="string"?e:e.service_name;await c.refreshServices(),k.success(`服务 ${t} 已刷新`)},L=e=>{const t=typeof e=="string"?e:e.service_name;a.push({name:"ServiceLogs",query:{serviceName:t}})},V=e=>{const t=typeof e=="string"?e:e.service_name;a.push({name:"ServiceDetail",params:{serviceName:t},query:{action:f.RESTART}})},A=e=>{const t=typeof e=="string"?e:e.service_name;a.push({name:"ServiceDetail",params:{serviceName:t},query:{action:f.START}})},O=e=>{const t=typeof e=="string"?e:e.service_name;a.push({name:"ServiceDetail",params:{serviceName:t},query:{action:f.STOP}})};return c.fetchServices(),(e,t)=>{const _=H("el-button"),z=P("loading");return r(),p("div",Z,[s("div",ss,[s("div",ts,[t[1]||(t[1]=s("div",null,[s("h1",{class:"page-title"},"仪表板"),s("p",{class:"page-subtitle"},"系统整体运行状态监控")],-1)),S(_,{type:"primary",loading:i(u),onClick:h,class:"refresh-btn"},{default:m(()=>[...t[0]||(t[0]=[s("i",{class:"i-carbon-renew mr-2"},null,-1),b(" 刷新数据 ",-1)])]),_:1},8,["loading"])])]),s("div",es,[s("div",as,[s("div",ns,[s("div",is,[t[2]||(t[2]=s("div",{class:"stat-label"},"服务总数",-1)),s("div",os,l(R.value),1),t[3]||(t[3]=s("div",{class:"stat-trend"},[s("i",{class:"i-carbon-arrow-up"}),s("span",null,"所有注册服务")],-1))]),t[4]||(t[4]=s("div",{class:"stat-icon-wrapper primary"},[s("i",{class:"i-carbon-application stat-icon"})],-1))]),t[5]||(t[5]=s("div",{class:"stat-glow primary"},null,-1))]),s("div",rs,[s("div",ls,[s("div",cs,[t[6]||(t[6]=s("div",{class:"stat-label"},"健康服务",-1)),s("div",ds,l(N.value),1),t[7]||(t[7]=s("div",{class:"stat-trend"},[s("i",{class:"i-carbon-checkmark"}),s("span",null,"运行正常")],-1))]),t[8]||(t[8]=s("div",{class:"stat-icon-wrapper success"},[s("i",{class:"i-carbon-checkmark-filled stat-icon"})],-1))]),t[9]||(t[9]=s("div",{class:"stat-glow success"},null,-1))]),s("div",vs,[s("div",us,[s("div",ps,[t[10]||(t[10]=s("div",{class:"stat-label"},"总实例数",-1)),s("div",ms,l(D.value),1),t[11]||(t[11]=s("div",{class:"stat-trend"},[s("i",{class:"i-carbon-container-software"}),s("span",null,"活跃实例")],-1))]),t[12]||(t[12]=s("div",{class:"stat-icon-wrapper warning"},[s("i",{class:"i-carbon-container-software stat-icon"})],-1))]),t[13]||(t[13]=s("div",{class:"stat-glow warning"},null,-1))]),s("div",{class:v(["stat-card card",T.value])},[s("div",fs,[s("div",gs,[t[14]||(t[14]=s("div",{class:"stat-label"},"系统健康率",-1)),s("div",hs,l(i(o))+"%",1),s("div",_s,[s("i",{class:v(x.value)},null,2),s("span",null,l(q.value),1)])]),s("div",{class:v(["stat-icon-wrapper",g.value])},[...t[15]||(t[15]=[s("i",{class:"i-carbon-health-cross stat-icon"},null,-1)])],2)]),s("div",{class:v(["stat-glow",g.value])},null,2)],2)]),s("div",ys,[t[17]||(t[17]=s("div",{class:"section-header"},[s("div",null,[s("h2",{class:"section-title"},"服务列表"),s("p",{class:"section-subtitle"},"查看所有注册的服务及其状态")])],-1)),M((r(),p("div",Ss,[(r(!0),p(J,null,K(i(d),y=>(r(),w(X,{key:y.service_name,service:y,class:"service-card-item",onClick:B,onDetail:$,onConfig:E,onRefresh:I,onLogs:L,onRestart:V,onStart:A,onStop:O},null,8,["service"]))),128)),!i(u)&&i(d).length===0?(r(),w(Y,{key:0,type:"empty",description:"暂无服务数据,请检查服务注册中心",class:"col-span-full"},{extra:m(()=>[S(_,{type:"primary",onClick:h},{default:m(()=>[...t[16]||(t[16]=[b(" 刷新数据 ",-1)])]),_:1})]),_:1})):G("",!0)])),[[z,i(u)]])])])}}}),xs=U(bs,[["__scopeId","data-v-1d4a4b8c"]]);export{xs as default};
@@ -0,0 +1 @@
1
+ .dashboard-container[data-v-1d4a4b8c]{display:flex;flex-direction:column;gap:var(--spacing-6)}.dashboard-header[data-v-1d4a4b8c]{background:var(--bg-elevated);border-radius:var(--radius-xl);padding:var(--spacing-8);box-shadow:var(--shadow-sm);border:1px solid var(--border-secondary)}.header-content[data-v-1d4a4b8c]{display:flex;align-items:center;justify-content:space-between;gap:var(--spacing-4)}.page-title[data-v-1d4a4b8c]{font-size:32px;font-weight:700;color:var(--text-primary);margin-bottom:var(--spacing-1);letter-spacing:-.02em}.page-subtitle[data-v-1d4a4b8c]{font-size:14px;color:var(--text-tertiary);font-weight:400}.refresh-btn[data-v-1d4a4b8c]{height:44px;padding:0 var(--spacing-6);font-size:15px;font-weight:500;border-radius:var(--radius-base)}.stats-grid[data-v-1d4a4b8c]{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:var(--spacing-6)}.stat-card[data-v-1d4a4b8c]{position:relative;background:var(--bg-elevated);border-radius:var(--radius-xl);padding:var(--spacing-6);overflow:hidden;border:1px solid var(--border-secondary);transition:all var(--duration-base) var(--ease-in-out);cursor:default}.stat-card[data-v-1d4a4b8c]:hover{transform:translateY(-4px);box-shadow:var(--shadow-lg)}.stat-card[data-v-1d4a4b8c]:before{content:"";position:absolute;top:0;left:0;right:0;height:4px;background:var(--gradient-primary);opacity:.8}.stat-card.gradient-primary[data-v-1d4a4b8c]:before{background:var(--gradient-primary)}.stat-card.gradient-success[data-v-1d4a4b8c]:before{background:var(--gradient-success)}.stat-card.gradient-warning[data-v-1d4a4b8c]:before{background:var(--gradient-warning)}.stat-card.gradient-error[data-v-1d4a4b8c]:before{background:var(--gradient-error)}.stat-content[data-v-1d4a4b8c]{display:flex;align-items:center;justify-content:space-between;gap:var(--spacing-4);position:relative;z-index:1}.stat-info[data-v-1d4a4b8c]{flex:1}.stat-label[data-v-1d4a4b8c]{font-size:14px;color:var(--text-secondary);margin-bottom:var(--spacing-2);font-weight:500}.stat-value[data-v-1d4a4b8c]{font-size:36px;font-weight:700;color:var(--text-primary);line-height:1.2;margin-bottom:var(--spacing-2);font-family:var(--font-family-number, -apple-system)}.stat-trend[data-v-1d4a4b8c]{display:flex;align-items:center;gap:var(--spacing-1);font-size:12px;color:var(--text-tertiary)}.stat-icon-wrapper[data-v-1d4a4b8c]{width:64px;height:64px;border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center;flex-shrink:0;position:relative;transition:all var(--duration-base) var(--ease-in-out)}.stat-icon-wrapper.primary[data-v-1d4a4b8c]{background:var(--primary-50);color:var(--primary-500)}.stat-icon-wrapper.success[data-v-1d4a4b8c]{background:var(--success-50);color:var(--success-500)}.stat-icon-wrapper.warning[data-v-1d4a4b8c]{background:var(--warning-50);color:var(--warning-500)}.stat-icon-wrapper.error[data-v-1d4a4b8c]{background:var(--error-50);color:var(--error-500)}:root[data-theme=dark] .stat-icon-wrapper.primary[data-v-1d4a4b8c]{background:var(--primary-900)}:root[data-theme=dark] .stat-icon-wrapper.success[data-v-1d4a4b8c]{background:var(--success-900)}:root[data-theme=dark] .stat-icon-wrapper.warning[data-v-1d4a4b8c]{background:var(--warning-900)}:root[data-theme=dark] .stat-icon-wrapper.error[data-v-1d4a4b8c]{background:var(--error-900)}.stat-icon[data-v-1d4a4b8c]{font-size:32px}.stat-card:hover .stat-icon-wrapper[data-v-1d4a4b8c]{transform:scale(1.1) rotate(5deg)}.stat-glow[data-v-1d4a4b8c]{position:absolute;bottom:-50%;right:-20%;width:200px;height:200px;border-radius:50%;opacity:.1;filter:blur(40px);pointer-events:none;transition:opacity var(--duration-base) var(--ease-in-out)}.stat-glow.primary[data-v-1d4a4b8c]{background:var(--primary-500)}.stat-glow.success[data-v-1d4a4b8c]{background:var(--success-500)}.stat-glow.warning[data-v-1d4a4b8c]{background:var(--warning-500)}.stat-glow.error[data-v-1d4a4b8c]{background:var(--error-500)}.stat-card:hover .stat-glow[data-v-1d4a4b8c]{opacity:.2}.services-section[data-v-1d4a4b8c]{background:var(--bg-elevated);border-radius:var(--radius-xl);padding:var(--spacing-8);box-shadow:var(--shadow-sm);border:1px solid var(--border-secondary)}.section-header[data-v-1d4a4b8c]{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-6)}.section-title[data-v-1d4a4b8c]{font-size:24px;font-weight:600;color:var(--text-primary);margin-bottom:var(--spacing-1)}.section-subtitle[data-v-1d4a4b8c]{font-size:14px;color:var(--text-tertiary)}.services-grid[data-v-1d4a4b8c]{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:var(--spacing-4)}.service-card-item[data-v-1d4a4b8c]{animation:slideInRight var(--duration-base) var(--ease-in-out)}@media (max-width: 1023px){.stats-grid[data-v-1d4a4b8c]{grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--spacing-4)}.services-grid[data-v-1d4a4b8c]{grid-template-columns:repeat(auto-fill,minmax(280px,1fr))}}@media (max-width: 767px){.dashboard-header[data-v-1d4a4b8c]{padding:var(--spacing-4)}.header-content[data-v-1d4a4b8c]{flex-direction:column;align-items:flex-start}.page-title[data-v-1d4a4b8c]{font-size:24px}.refresh-btn[data-v-1d4a4b8c]{width:100%}.stats-grid[data-v-1d4a4b8c]{grid-template-columns:1fr;gap:var(--spacing-4)}.stat-card[data-v-1d4a4b8c]{padding:var(--spacing-4)}.stat-value[data-v-1d4a4b8c]{font-size:28px}.stat-icon-wrapper[data-v-1d4a4b8c]{width:56px;height:56px}.stat-icon[data-v-1d4a4b8c]{font-size:28px}.services-section[data-v-1d4a4b8c]{padding:var(--spacing-4)}.services-grid[data-v-1d4a4b8c]{grid-template-columns:1fr;gap:var(--spacing-3)}}
@@ -0,0 +1 @@
1
+ import{I as ce,J as pe,d as ge,r as b,x as U,o as ve,g as R,b as f,w as n,i as a,l as d,j as m,m as fe,y as W,c as V,B as z,F as x,e as s,t as r,h as _e,E as T,_ as be}from"./index-CiFlm8oc.js";import{P as he}from"./PageContainer-Byss-yUC.js";import{u as Ne}from"./service-BYlgGPs_.js";import{a as ye}from"./format-Cuzxgna9.js";const we=P=>ce.Post(pe.OPSBFF_LOG_SEARCH,P),ke={class:"result-header"},Se={class:"result-desc"},Ce={class:"result-actions"},Re={class:"expand-panel"},Ve={class:"meta-block"},ze={class:"meta-block"},xe={class:"meta-block"},Te={class:"metadata-tags"},Ie={class:"expand-actions"},De={class:"cell-time"},Oe={class:"cell-instance"},Le={class:"instance-id"},Ae={class:"instance-ip"},Ee={class:"cell-message"},Ue={class:"cell-actions"},Pe={class:"table-footer"},$e={class:"json-viewer"},Be=ge({__name:"LogSearch",setup(P){const h=Ne(),j=["DEBUG","INFO","WARNING","ERROR","CRITICAL"],Z=[50,100,200],k=b("local");function q(l){if(l instanceof Date)return l;const e=String(l);return/Z$|[+-]\d{2}:\d{2}$|[+-]\d{4}$/.test(e)?new Date(e):new Date(e.endsWith("Z")?e:e+"Z")}function $(l){const e=q(l);if(isNaN(e.getTime()))return"无效时间";const i={year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1};return k.value==="local"?e.toLocaleString("zh-CN",i).replace(/\//g,"-"):e.toLocaleString("zh-CN",{...i,timeZone:k.value}).replace(/\//g,"-")}const o=b({serviceNames:[],timeRange:A(),levels:["INFO","WARNING","ERROR"],methodNames:[],keywords:[],targets:[]}),S=b([]),N=b(!1),u=b({page:1,pageSize:100,total:0,hasNext:!1}),I=b(!1),D=b(null),B=U(()=>h.serviceNames),F=U(()=>!N.value&&o.value.serviceNames.length>0&&o.value.timeRange?.length===2),H=[{text:"近 24 小时",value:()=>{const l=new Date;return[new Date(l.getTime()-1440*60*1e3),l]}},{text:"近 3 天",value:()=>{const l=new Date;return[new Date(l.getTime()-4320*60*1e3),l]}},{text:"近 7 天",value:()=>{const l=new Date;return[new Date(l.getTime()-10080*60*1e3),l]}}],Y=l=>l.getTime()>Date.now(),K=U(()=>D.value?JSON.stringify(D.value,null,2):""),Q=l=>{if(!l||l.length!==2)return;const[e,i]=l;i.getTime()-e.getTime()>10080*60*1e3&&(T.error("时间范围不能超过 7 天"),o.value.timeRange=A())},C=async()=>{if(!F.value){T.warning("请至少选择一个服务并设置时间范围");return}N.value=!0;try{const l=X(),e=await we(l);S.value=e.items,u.value={page:e.page,pageSize:e.page_size,total:e.total,hasNext:e.has_next},S.value.length===1&&L(S.value[0]),e.items.length||T.info("未查询到日志记录,尝试缩小时间范围或调整关键词")}catch(l){console.error(l)}finally{N.value=!1}},X=()=>{const[l,e]=o.value.timeRange,[i,c]=ne(O(o.value.targets)),p=O(o.value.keywords),g=O(o.value.methodNames);return{service_names:o.value.serviceNames,start_time:G(l),end_time:G(e),levels:o.value.levels.length?o.value.levels:void 0,keywords:p.length?p:void 0,method_names:g.length?g:void 0,ip_addresses:i.length?i:void 0,instance_ids:c.length?c:void 0,page:u.value.page,page_size:u.value.pageSize}},O=l=>{const e=[];return l.forEach(i=>{const c=String(i||"").trim();c&&(e.includes(c)||e.push(c))}),e},ee=()=>{o.value={serviceNames:B.value.slice(0,1),timeRange:A(),levels:["INFO","WARNING","ERROR"],methodNames:[],keywords:[],targets:[]},u.value.page=1},le=l=>{u.value.page=l,C()},te=l=>{u.value.pageSize=l,u.value.page=1,C()},L=l=>{D.value=l,I.value=!0},ae=l=>{l.func_name&&!o.value.methodNames.includes(l.func_name)&&o.value.methodNames.push(l.func_name),l.trace_id&&!o.value.keywords.includes(l.trace_id)&&o.value.keywords.push(l.trace_id),T.success("已根据该行更新过滤条件,可重新检索")},M=l=>{const e=l==="mongo"?"/infra/mongo-express":"/infra/rabbitmq";window.open(e,"_blank")},se=l=>{switch(l){case"ERROR":case"CRITICAL":return"danger";case"WARNING":return"warning";case"INFO":case"DEBUG":return"success";default:return"info"}},ne=l=>{const e=[],i=[];return l.forEach(c=>{/^\d+\.\d+\.\d+\.\d+$/.test(c)?e.push(c):i.push(c)}),[e,i]},G=l=>(l instanceof Date?l:new Date(l)).toISOString();function A(){const l=new Date;return[new Date(l.getTime()-1440*60*1e3),l]}return ve(async()=>{h.serviceNames.length||await h.fetchServiceNames(),!o.value.serviceNames.length&&h.serviceNames.length&&(o.value.serviceNames=h.serviceNames.slice(0,1)),o.value.serviceNames.length&&await C()}),(l,e)=>{const i=m("el-button"),c=m("el-alert"),p=m("el-option"),g=m("el-select"),y=m("el-form-item"),w=m("el-col"),oe=m("el-date-picker"),ie=m("el-row"),re=m("el-form"),J=m("el-card"),E=m("el-tag"),v=m("el-table-column"),ue=m("el-table"),de=m("el-pagination"),me=m("el-drawer");return f(),R(he,{title:"业务日志检索",icon:"i-carbon-search"},{actions:n(()=>[a(i,{type:"primary",disabled:!F.value,loading:N.value,onClick:C},{default:n(()=>[...e[12]||(e[12]=[s("i",{class:"i-carbon-search mr-2"},null,-1),s("span",null,"检索",-1)])]),_:1},8,["disabled","loading"]),a(i,{onClick:ee,disabled:N.value},{default:n(()=>[...e[13]||(e[13]=[s("i",{class:"i-carbon-renew mr-2"},null,-1),s("span",null,"重置",-1)])]),_:1},8,["disabled"])]),default:n(()=>[a(c,{type:"info","show-icon":"",class:"mb-4"},{title:n(()=>[...e[14]||(e[14]=[d(" 日志来自 infra_logging.service_logs,时间跨度最大 7 天,若结果为空可尝试缩小时间范围或减少关键词。 ",-1)])]),_:1}),a(J,{class:"filter-card mb-6"},{default:n(()=>[a(re,{model:o.value,"label-width":"120px",onSubmit:e[6]||(e[6]=fe(()=>{},["prevent"]))},{default:n(()=>[a(ie,{gutter:20},{default:n(()=>[a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"服务"},{default:n(()=>[a(g,{modelValue:o.value.serviceNames,"onUpdate:modelValue":e[0]||(e[0]=t=>o.value.serviceNames=t),multiple:"",filterable:"",placeholder:"请选择服务",loading:W(h).loading,"collapse-tags":"","collapse-tags-tooltip":""},{default:n(()=>[(f(!0),V(x,null,z(B.value,t=>(f(),R(p,{key:t,label:t,value:t},null,8,["label","value"]))),128))]),_:1},8,["modelValue","loading"])]),_:1})]),_:1}),a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"时间范围"},{default:n(()=>[a(oe,{modelValue:o.value.timeRange,"onUpdate:modelValue":e[1]||(e[1]=t=>o.value.timeRange=t),type:"datetimerange","range-separator":"至","start-placeholder":"开始时间","end-placeholder":"结束时间","disabled-date":Y,shortcuts:H,onChange:Q},null,8,["modelValue"])]),_:1})]),_:1}),a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"日志等级"},{default:n(()=>[a(g,{modelValue:o.value.levels,"onUpdate:modelValue":e[2]||(e[2]=t=>o.value.levels=t),multiple:"",placeholder:"全部","collapse-tags":""},{default:n(()=>[(f(),V(x,null,z(j,t=>a(p,{key:t,label:t,value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"])]),_:1})]),_:1}),a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"方法名"},{default:n(()=>[a(g,{modelValue:o.value.methodNames,"onUpdate:modelValue":e[3]||(e[3]=t=>o.value.methodNames=t),multiple:"","allow-create":"",filterable:"","default-first-option":"",placeholder:"输入后回车添加"},null,8,["modelValue"])]),_:1})]),_:1}),a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"关键词"},{default:n(()=>[a(g,{modelValue:o.value.keywords,"onUpdate:modelValue":e[4]||(e[4]=t=>o.value.keywords=t),multiple:"","allow-create":"",filterable:"","default-first-option":"",placeholder:"支持多关键词"},null,8,["modelValue"])]),_:1})]),_:1}),a(w,{xs:24,sm:12,lg:8},{default:n(()=>[a(y,{label:"IP / 实例"},{default:n(()=>[a(g,{modelValue:o.value.targets,"onUpdate:modelValue":e[5]||(e[5]=t=>o.value.targets=t),multiple:"","allow-create":"",filterable:"","default-first-option":"",placeholder:"输入 IP 或实例 ID"},null,8,["modelValue"])]),_:1})]),_:1})]),_:1})]),_:1},8,["model"])]),_:1}),a(J,{class:"result-card"},{default:n(()=>[s("div",ke,[s("div",null,[e[15]||(e[15]=s("p",{class:"result-title"},"查询结果",-1)),s("p",Se,"共 "+r(u.value.total)+" 条,展示第 "+r(u.value.page)+" 页",1)]),s("div",Ce,[a(g,{modelValue:k.value,"onUpdate:modelValue":e[7]||(e[7]=t=>k.value=t),size:"small",class:"timezone-select"},{prefix:n(()=>[...e[16]||(e[16]=[s("i",{class:"i-carbon-time"},null,-1)])]),default:n(()=>[a(p,{label:"本地时间",value:"local"}),a(p,{label:"UTC",value:"UTC"}),a(p,{label:"Asia/Shanghai",value:"Asia/Shanghai"}),a(p,{label:"America/New_York",value:"America/New_York"}),a(p,{label:"Europe/London",value:"Europe/London"})]),_:1},8,["modelValue"]),u.value.hasNext?(f(),R(E,{key:0,type:"warning"},{default:n(()=>[...e[17]||(e[17]=[d("仍有更多结果",-1)])]),_:1})):_e("",!0)])]),a(ue,{data:S.value,loading:N.value,stripe:"",border:"",class:"log-table","empty-text":"暂无日志"},{default:n(()=>[a(v,{type:"expand"},{default:n(({row:t})=>[s("div",Re,[s("div",Ve,[s("p",null,[e[18]||(e[18]=s("strong",null,"Trace ID:",-1)),d(r(t.trace_id||"-"),1)]),s("p",null,[e[19]||(e[19]=s("strong",null,"Logger:",-1)),d(r(t.logger_name||"-"),1)]),s("p",null,[e[20]||(e[20]=s("strong",null,"源文件:",-1)),d(r(t.file)+":"+r(t.line_no),1)])]),s("div",ze,[s("p",null,[e[21]||(e[21]=s("strong",null,"函数:",-1)),d(r(t.func_name||"-"),1)]),s("p",null,[e[22]||(e[22]=s("strong",null,"主机:",-1)),d(r(t.host||"-")+" / "+r(t.ip||"-"),1)]),s("p",null,[e[23]||(e[23]=s("strong",null,"创建时间:",-1)),d(r($(t.created_at||t.timestamp)),1)])]),s("div",xe,[e[24]||(e[24]=s("p",null,[s("strong",null,"Metadata:")],-1)),s("div",Te,[(f(!0),V(x,null,z(t.metadata_flattened||[],_=>(f(),R(E,{key:_,type:"info",size:"small"},{default:n(()=>[d(r(_),1)]),_:2},1024))),128))])])]),s("div",Ie,[a(i,{link:"",type:"primary",size:"small",onClick:_=>L(t)},{default:n(()=>[...e[25]||(e[25]=[s("i",{class:"i-carbon-code mr-1"},null,-1),d("查看原始 JSON ",-1)])]),_:1},8,["onClick"]),a(i,{link:"",type:"success",size:"small",onClick:e[8]||(e[8]=_=>M("mongo"))},{default:n(()=>[...e[26]||(e[26]=[s("i",{class:"i-carbon-data-base mr-1"},null,-1),d("打开 Mongo 控制台 ",-1)])]),_:1}),a(i,{link:"",type:"warning",size:"small",onClick:e[9]||(e[9]=_=>M("rabbitmq"))},{default:n(()=>[...e[27]||(e[27]=[s("i",{class:"i-carbon-data-1 mr-1"},null,-1),d("查看 RabbitMQ 管理台 ",-1)])]),_:1})])]),_:1}),a(v,{prop:"timestamp",label:"时间",width:"140","class-name":"cell-compact"},{default:n(({row:t})=>[s("div",De,[s("span",null,r($(t.timestamp)),1),s("small",null,r(W(ye)(t.timestamp)),1)])]),_:1}),a(v,{prop:"service_name",label:"服务",width:"90","class-name":"cell-compact","show-overflow-tooltip":""}),a(v,{prop:"host",label:"实例",width:"130","class-name":"cell-compact"},{default:n(({row:t})=>[s("div",Oe,[s("span",Le,r(t.host||"-"),1),s("span",Ae,r(t.ip||""),1)])]),_:1}),a(v,{prop:"level",label:"Level",width:"85",align:"center"},{default:n(({row:t})=>[a(E,{type:se(t.level),size:"small"},{default:n(()=>[d(r(t.level),1)]),_:2},1032,["type"])]),_:1}),a(v,{prop:"message",label:"Message","min-width":"500"},{default:n(({row:t})=>[s("div",Ee,r(t.message),1)]),_:1}),a(v,{prop:"trace_id",label:"Trace","min-width":"180","class-name":"cell-compact cell-mono"}),a(v,{prop:"func_name",label:"Method","min-width":"150","class-name":"cell-compact cell-mono"}),a(v,{label:"操作",width:"90",align:"center"},{default:n(({row:t})=>[s("div",Ue,[a(i,{link:"",type:"primary",size:"small",onClick:_=>L(t)},{default:n(()=>[...e[28]||(e[28]=[d(" JSON ",-1)])]),_:1},8,["onClick"]),a(i,{link:"",type:"warning",size:"small",class:"btn-keyword",onClick:_=>ae(t)},{default:n(()=>[...e[29]||(e[29]=[d(" +关键词 ",-1)])]),_:1},8,["onClick"])])]),_:1})]),_:1},8,["data","loading"]),s("div",Pe,[a(g,{modelValue:u.value.pageSize,"onUpdate:modelValue":e[10]||(e[10]=t=>u.value.pageSize=t),size:"small",onChange:te},{default:n(()=>[(f(),V(x,null,z(Z,t=>a(p,{key:t,label:`${t} 条/页`,value:t},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),a(de,{layout:"prev, pager, next","current-page":u.value.page,"page-size":u.value.pageSize,total:u.value.total,onCurrentChange:le},null,8,["current-page","page-size","total"])])]),_:1}),a(me,{modelValue:I.value,"onUpdate:modelValue":e[11]||(e[11]=t=>I.value=t),title:"日志详情 (JSON)",size:"40%"},{default:n(()=>[s("pre",$e,r(K.value),1)]),_:1},8,["modelValue"])]),_:1})}}}),We=be(Be,[["__scopeId","data-v-c13a1ce4"]]);export{We as default};
@@ -0,0 +1 @@
1
+ .filter-card[data-v-c13a1ce4],.result-card[data-v-c13a1ce4]{border:none;background:var(--bg-elevated)}.result-header[data-v-c13a1ce4]{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-4)}.result-actions[data-v-c13a1ce4]{display:flex;align-items:center;gap:var(--spacing-3)}.timezone-select[data-v-c13a1ce4]{width:150px}.result-title[data-v-c13a1ce4]{margin:0;font-size:18px;font-weight:600;color:var(--text-primary)}.result-desc[data-v-c13a1ce4]{margin:4px 0 0;color:var(--text-secondary);font-size:13px}.expand-panel[data-v-c13a1ce4]{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--spacing-4);padding:var(--spacing-3);background:var(--bg-secondary);border-radius:var(--radius-base)}.meta-block[data-v-c13a1ce4]{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--text-secondary)}.metadata-tags[data-v-c13a1ce4]{display:flex;flex-wrap:wrap;gap:var(--spacing-2)}.expand-actions[data-v-c13a1ce4]{display:flex;flex-wrap:wrap;gap:var(--spacing-3);margin-top:var(--spacing-3);padding-top:var(--spacing-3);border-top:1px solid var(--border-color)}.cell-time[data-v-c13a1ce4]{display:flex;flex-direction:column;gap:2px}.cell-time small[data-v-c13a1ce4]{color:var(--text-tertiary);font-size:11px}.cell-instance[data-v-c13a1ce4]{display:flex;flex-direction:column;gap:4px}.cell-instance .instance-id[data-v-c13a1ce4]{font-weight:600;color:var(--text-primary);font-size:13px;font-family:var(--font-mono, "SF Mono", "Monaco", "Consolas", monospace)}.cell-instance .instance-ip[data-v-c13a1ce4]{color:var(--text-tertiary);font-size:11px;font-family:var(--font-mono, "SF Mono", "Monaco", "Consolas", monospace);background:var(--bg-secondary);padding:2px 6px;border-radius:4px;width:fit-content}.cell-message[data-v-c13a1ce4]{white-space:pre-wrap;word-break:break-word;line-height:1.5;max-height:120px;overflow-y:auto;font-size:13px;color:var(--text-secondary)}.cell-actions[data-v-c13a1ce4]{display:flex;flex-direction:column;align-items:center;gap:2px}.table-footer[data-v-c13a1ce4]{margin-top:var(--spacing-4);display:flex;justify-content:flex-end;gap:var(--spacing-3);align-items:center}.json-viewer[data-v-c13a1ce4]{background:var(--bg-secondary);color:var(--text-primary);padding:var(--spacing-4);border-radius:var(--radius-base);white-space:pre-wrap;max-height:70vh;overflow:auto}:root[data-theme=dark] .expand-panel[data-v-c13a1ce4]{background:var(--bg-primary)}[data-v-c13a1ce4] .cell-compact{font-size:12px!important}[data-v-c13a1ce4] .cell-compact .cell{font-size:12px!important;color:var(--text-secondary)}[data-v-c13a1ce4] .cell-mono{font-family:var(--font-mono, "SF Mono", "Monaco", "Consolas", monospace)!important}[data-v-c13a1ce4] .cell-mono .cell{font-family:var(--font-mono, "SF Mono", "Monaco", "Consolas", monospace)!important;font-size:11px!important;word-break:break-all}.cell-instance .instance-id[data-v-c13a1ce4]{font-size:11px;font-weight:500}.cell-instance .instance-ip[data-v-c13a1ce4]{font-size:10px;padding:1px 4px}.btn-keyword[data-v-c13a1ce4]{text-decoration:underline;text-underline-offset:2px}.btn-keyword[data-v-c13a1ce4]:hover{text-decoration:underline;opacity:.8}
@@ -0,0 +1 @@
1
+ .login-container[data-v-001fbe81]{min-height:100vh;display:flex;align-items:center;justify-content:center;background:var(--bg-page);padding:20px}.login-card[data-v-001fbe81]{width:100%;max-width:420px;padding:40px 36px;border-radius:var(--radius-xl, 16px);background:var(--bg-container, #fff);box-shadow:var(--shadow-lg, 0 8px 32px rgba(0, 0, 0, .08));border:1px solid var(--border-secondary, #e5e7eb)}.login-header[data-v-001fbe81]{text-align:center;margin-bottom:32px}.logo-icon[data-v-001fbe81]{width:56px;height:56px;margin:0 auto 16px;display:flex;align-items:center;justify-content:center;border-radius:var(--radius-lg, 12px);background:var(--gradient-primary, linear-gradient(135deg, #6366f1, #8b5cf6));box-shadow:var(--shadow-sm)}.login-title[data-v-001fbe81]{font-size:22px;font-weight:600;color:var(--text-primary);margin-bottom:4px}.login-subtitle[data-v-001fbe81]{font-size:14px;color:var(--text-tertiary)}.captcha-row[data-v-001fbe81]{display:flex;gap:12px;width:100%}.captcha-input[data-v-001fbe81]{flex:1}.captcha-image-wrapper[data-v-001fbe81]{width:140px;height:40px;border-radius:var(--radius-base, 8px);overflow:hidden;cursor:pointer;border:1px solid var(--border-secondary, #e5e7eb);flex-shrink:0;display:flex;align-items:center;justify-content:center;background:var(--bg-subtle, #f9fafb);transition:opacity .2s}.captcha-image-wrapper[data-v-001fbe81]:hover{opacity:.8}.captcha-image[data-v-001fbe81]{width:100%;height:100%;object-fit:cover}.captcha-placeholder[data-v-001fbe81]{font-size:20px;color:var(--text-tertiary)}.login-btn[data-v-001fbe81]{width:100%}
@@ -0,0 +1 @@
1
+ import{d as I,u as M,r as l,a as U,o as K,c as b,b as c,e as v,f as R,g as C,h as L,i as t,j as d,w as r,k as T,n as z,l as P,m as j,p as A,q as E,_ as O}from"./index-CiFlm8oc.js";const $={class:"login-container"},D={class:"login-card"},F={class:"captcha-row"},G=["src"],H={key:1,class:"captcha-placeholder"},J=I({__name:"LoginView",setup(Q){const y=E(),B=M(),f=l(),o=l(!1),_=l(!1),u=l(""),V=l(""),i=l(""),s=l(!1),k=l(""),a=U({username:"",password:"",captcha_answer:""}),N={username:[{required:!0,message:"请输入用户名",trigger:"blur"}],password:[{required:!0,message:"请输入密码",trigger:"blur"}],captcha_answer:[{required:!0,message:"请输入验证码",trigger:"blur"}]};async function h(){_.value=!0;try{const p=await A();V.value=p.captcha_id,u.value=p.image_base64}catch{u.value=""}finally{_.value=!1}}async function g(){if(!(!f.value||!await f.value.validate().catch(()=>!1))){o.value=!0,i.value="",s.value=!1;try{const e=await B.doLogin({username:a.username,password:a.password,captcha_id:V.value,captcha_answer:a.captcha_answer});e.next_step==="totp_bind"?y.push({name:"TotpBind"}):e.next_step==="totp_verify"&&y.push({name:"TotpVerify"})}catch(e){e?.code==="60003"?(s.value=!0,k.value=e?.message||"IP 已锁定,请稍后重试"):i.value=e?.message||"登录失败",a.captcha_answer="",h()}finally{o.value=!1}}}return K(()=>{h()}),(p,e)=>{const x=d("el-alert"),w=d("el-input"),m=d("el-form-item"),S=d("el-button"),q=d("el-form");return c(),b("div",$,[v("div",D,[e[5]||(e[5]=R('<div class="login-header" data-v-001fbe81><div class="logo-icon" data-v-001fbe81><i class="i-carbon-cloud-satellite text-3xl" style="color:white;" data-v-001fbe81></i></div><h2 class="login-title" data-v-001fbe81>OPS 管理平台</h2><p class="login-subtitle" data-v-001fbe81>请输入账号信息登录</p></div>',1)),s.value?(c(),C(x,{key:0,type:"error",title:k.value,"show-icon":"",closable:!1,class:"mb-4"},null,8,["title"])):L("",!0),t(q,{ref_key:"formRef",ref:f,model:a,rules:N,"label-width":"0",size:"large",onSubmit:j(g,["prevent"])},{default:r(()=>[t(m,{prop:"username"},{default:r(()=>[t(w,{modelValue:a.username,"onUpdate:modelValue":e[0]||(e[0]=n=>a.username=n),placeholder:"用户名","prefix-icon":"User",disabled:o.value||s.value},null,8,["modelValue","disabled"])]),_:1}),t(m,{prop:"password"},{default:r(()=>[t(w,{modelValue:a.password,"onUpdate:modelValue":e[1]||(e[1]=n=>a.password=n),type:"password",placeholder:"密码","prefix-icon":"Lock","show-password":"",disabled:o.value||s.value},null,8,["modelValue","disabled"])]),_:1}),t(m,{prop:"captcha_answer"},{default:r(()=>[v("div",F,[t(w,{modelValue:a.captcha_answer,"onUpdate:modelValue":e[2]||(e[2]=n=>a.captcha_answer=n),placeholder:"验证码","prefix-icon":"Key",disabled:o.value||s.value,class:"captcha-input",onKeyup:T(g,["enter"])},null,8,["modelValue","disabled"]),v("div",{class:"captcha-image-wrapper",onClick:h},[u.value?(c(),b("img",{key:0,src:u.value,alt:"验证码",class:"captcha-image"},null,8,G)):(c(),b("div",H,[v("i",{class:z(["i-carbon-renew",{"animate-spin":_.value}])},null,2)]))])])]),_:1}),t(m,null,{default:r(()=>[t(S,{type:"primary",class:"login-btn",loading:o.value,disabled:s.value,onClick:g},{default:r(()=>[...e[4]||(e[4]=[P(" 登 录 ",-1)])]),_:1},8,["loading","disabled"])]),_:1})]),_:1},8,["model"]),i.value&&!s.value?(c(),C(x,{key:1,type:"warning",title:i.value,"show-icon":"",closable:"",class:"mt-2",onClose:e[3]||(e[3]=n=>i.value="")},null,8,["title"])):L("",!0)])])}}}),X=O(J,[["__scopeId","data-v-001fbe81"]]);export{X as default};
@@ -0,0 +1 @@
1
+ import{c as ee,d as M,I as te,H as se,e as ae,u as le,O as x,D as z,f as c,g as Q,h as oe}from"./service-operation-6GzLw2Z1.js";import{d as J,x as g,g as V,b as r,j as D,n as j,w as E,c as p,h as S,e,t as d,_ as K,r as L,i as P,y as a,F as H,B as Y,l as $,H as ne,E as q,G as W}from"./index-CiFlm8oc.js";const re=J({__name:"StatusTag",props:{status:{},type:{default:"service"},size:{default:"default"},effect:{default:"light"},showIcon:{type:Boolean,default:!0}},setup(A){const k=A,m=s=>te[s],f=s=>se[s],T=s=>ae[s],b=g(()=>{const s=k.status.toString();switch(k.type){case"instance":return m(s)?.type||"info";case"health":return f(s)?.type||"info";case"operation":return T(s)?.type||"info";case"service":default:return ee[s]||"info"}}),t=g(()=>{const s=k.status.toString();switch(k.type){case"instance":return m(s)?.label||s;case"health":return f(s)?.label||s;case"operation":return T(s)?.label||s;case"service":default:return M[s]?.label||s}}),i=g(()=>{const s=k.status.toString();switch(k.type){case"instance":return m(s)?.icon||"";case"health":return f(s)?.icon||"";case"operation":return T(s)?.icon||"";case"service":default:return M[s]?.icon||""}}),v=g(()=>{if(k.type==="service"){const s=M[k.status];return`${s?.color||""} ${s?.bgColor||""}`}return""});return(s,I)=>{const C=D("el-tag");return r(),V(C,{type:b.value,effect:s.effect,size:s.size,class:j(["status-tag",v.value])},{default:E(()=>[s.showIcon?(r(),p("i",{key:0,class:j([i.value,"mr-1"])},null,2)):S("",!0),e("span",null,d(t.value),1)]),_:1},8,["type","effect","size","class"])}}}),ie=K(re,[["__scopeId","data-v-5fdd77e5"]]),ue={class:"service-list"},ce={class:"service-list"},de={class:"service-list"},pe=J({__name:"ServiceOperationDialog",props:{modelValue:{type:Boolean},operation:{},serviceNames:{}},emits:["update:modelValue","success","operationSubmitted"],setup(A,{emit:k}){const m=A,f=k,T=le(),b=L(),t=L(!1),i=L({confirmText:""}),v=g({get:()=>m.modelValue,set:n=>f("update:modelValue",n)}),s=g(()=>({[x.RESTART]:"重启服务",[x.START]:"启动服务",[x.STOP]:"停止服务",[x.REBUILD]:"重建服务",[z.DELETE]:"删除服务信息"})[m.operation]),I={confirmText:[{required:!0,message:"请输入服务名称以确认删除",trigger:"blur"}]},C=()=>{b.value?.resetFields(),i.value.confirmText="",v.value=!1},F=async()=>{if(m.operation===z.DELETE){if(!b.value)return;try{await b.value.validate()}catch{return}}t.value=!0;try{let n;switch(m.operation){case x.RESTART:n=await T.restart(m.serviceNames);break;case x.START:n=await T.start(m.serviceNames);break;case x.STOP:n=await T.stop(m.serviceNames);break;case x.REBUILD:n=await T.rebuild(m.serviceNames);break;case z.DELETE:await T.remove(m.serviceNames[0]),f("success"),C();return}n&&(f("operationSubmitted",n),C())}catch(n){console.error("操作失败:",n)}finally{t.value=!1}};return(n,l)=>{const U=D("el-alert"),B=D("el-input"),w=D("el-form-item"),R=D("el-form"),h=D("el-button"),G=D("el-dialog");return r(),V(G,{modelValue:v.value,"onUpdate:modelValue":l[1]||(l[1]=y=>v.value=y),title:s.value,width:"500px",onClose:C},{footer:E(()=>[P(h,{onClick:C},{default:E(()=>[...l[10]||(l[10]=[$("取消",-1)])]),_:1}),P(h,{type:"primary",loading:t.value,onClick:F,disabled:n.operation===a(z).DELETE&&i.value.confirmText!==n.serviceNames[0]},{default:E(()=>[...l[11]||(l[11]=[$(" 确认 ",-1)])]),_:1},8,["loading","disabled"])]),default:E(()=>[P(R,{ref_key:"formRef",ref:b,model:i.value,rules:I,"label-width":"100px"},{default:E(()=>[n.operation===a(x).RESTART?(r(),V(U,{key:0,title:"重启服务",type:"warning",closable:!1,"show-icon":"",class:"mb-4"},{default:E(()=>[l[2]||(l[2]=e("p",null,"此操作将重启以下服务:",-1)),e("ul",ue,[(r(!0),p(H,null,Y(n.serviceNames,y=>(r(),p("li",{key:y},d(y),1))),128))])]),_:1})):S("",!0),n.operation===a(x).START?(r(),V(U,{key:1,title:"启动服务",type:"success",closable:!1,"show-icon":"",class:"mb-4"},{default:E(()=>[l[3]||(l[3]=e("p",null,"此操作将启动以下服务:",-1)),e("ul",ce,[(r(!0),p(H,null,Y(n.serviceNames,y=>(r(),p("li",{key:y},d(y),1))),128))])]),_:1})):S("",!0),n.operation===a(x).STOP?(r(),V(U,{key:2,title:"停止服务",type:"error",closable:!1,"show-icon":"",class:"mb-4"},{default:E(()=>[l[4]||(l[4]=e("p",null,"⚠️ 此操作将停止以下服务:",-1)),e("ul",de,[(r(!0),p(H,null,Y(n.serviceNames,y=>(r(),p("li",{key:y},d(y),1))),128))]),l[5]||(l[5]=e("p",{class:"mt-2"},"停止后服务将无法访问,请谨慎操作!",-1))]),_:1})):S("",!0),n.operation===a(z).DELETE?(r(),p(H,{key:3},[P(U,{title:"删除服务信息",type:"error",closable:!1,"show-icon":"",class:"mb-4"},{default:E(()=>[e("p",null,[l[6]||(l[6]=$("⚠️ 此操作将删除服务 ",-1)),e("strong",null,d(n.serviceNames[0]),1),l[7]||(l[7]=$(" 的基本信息记录",-1))]),l[8]||(l[8]=e("p",{class:"mt-2"},[e("strong",null,"注意:")],-1)),l[9]||(l[9]=e("ul",{class:"warning-list"},[e("li",null,"只删除 service_info_tbl 中的记录"),e("li",null,"不会删除实例记录(service_registry_tbl)"),e("li",null,"不会删除配置记录(service_config_tbl)"),e("li",null,"建议先停止服务实例,再删除配置,最后删除服务信息")],-1))]),_:1}),P(w,{label:"确认操作",prop:"confirmText"},{default:E(()=>[P(B,{modelValue:i.value.confirmText,"onUpdate:modelValue":l[0]||(l[0]=y=>i.value.confirmText=y),placeholder:"请输入服务名称以确认删除"},null,8,["modelValue"])]),_:1})],64)):S("",!0)]),_:1},8,["model"])]),_:1},8,["modelValue","title"])}}}),Me=K(pe,[["__scopeId","data-v-c06a7005"]]);function me(A={}){const{interval:k=2e3,timeout:m=300*1e3,onProgress:f,onSuccess:T,onError:b,onTimeout:t}=A,i=L(null),v=L(!1),s=L(null);let I=null,C=null;const F=g(()=>{if(!i.value)return!1;const N=i.value.status;return N===c.SUCCESS||N===c.FAILED}),n=g(()=>i.value?.status===c.SUCCESS),l=g(()=>i.value?.status===c.FAILED),U=g(()=>i.value?.status===c.PENDING),B=g(()=>i.value?.status===c.RUNNING),w=()=>{I!==null&&(clearInterval(I),I=null),C!==null&&(clearTimeout(C),C=null)},R=async N=>{w(),v.value=!0,s.value=null,i.value=null;try{const _=await Q(N);if(i.value=_,_.status===c.SUCCESS||_.status===c.FAILED){v.value=!1,h(_);return}f?.(_)}catch(_){s.value=_,v.value=!1,q.error("查询操作状态失败");return}C=window.setTimeout(()=>{w(),v.value=!1,q.warning("操作超时,请检查操作状态"),t?.()},m),I=window.setInterval(async()=>{try{const _=await Q(N);i.value=_,f?.(_),(_.status===c.SUCCESS||_.status===c.FAILED)&&(w(),v.value=!1,h(_))}catch(_){w(),s.value=_,v.value=!1,q.error("查询操作状态失败")}},k)},h=N=>{N.status===c.SUCCESS?T?.(N):N.status===c.FAILED&&b?.(N)},G=()=>{w(),v.value=!1},y=()=>{w(),i.value=null,v.value=!1,s.value=null};return ne(()=>{w()}),{currentOperation:i,loading:v,error:s,isCompleted:F,isSuccess:n,isFailed:l,isPending:U,isRunning:B,startPolling:R,stopPolling:G,reset:y}}const fe={key:0,class:"operation-progress"},ve={class:"text-center mb-4"},_e={class:"text-lg font-medium text-gray-700"},ge={key:1,class:"text-sm text-gray-500 mt-2"},ye={key:0,class:"operation-info bg-gray-50 rounded p-4 text-sm"},Se={class:"info-item"},Te={class:"value"},be={class:"info-item"},Ce={class:"value"},Ee={key:0,class:"info-item"},ke={class:"value"},Ie={key:1,class:"info-item"},we={class:"value"},Ne={key:1,class:"operation-result"},xe={class:"flex items-center justify-center mb-6"},he={class:"text-center mb-4"},Oe={key:0,class:"text-sm text-red-600 mt-2 px-4"},De={class:"operation-info bg-gray-50 rounded p-4 text-sm"},Ue={class:"info-item"},Ve={class:"value"},Ae={class:"info-item"},Re={class:"value"},Pe={key:0,class:"info-item"},Le={class:"value"},Fe={key:1,class:"info-item"},$e={class:"value"},Be={key:2,class:"info-item"},Ge={class:"value"},ze=J({__name:"OperationProgressDialog",props:{modelValue:{type:Boolean},operationId:{}},emits:["update:modelValue","success","error"],setup(A,{expose:k,emit:m}){const f=A,T=m,b=g({get:()=>f.modelValue,set:u=>T("update:modelValue",u)}),{currentOperation:t,loading:i,isCompleted:v,startPolling:s,reset:I}=me({interval:2e3,onSuccess:u=>{T("success",u)},onError:u=>{T("error",u)}}),C=L(),F=()=>{!f.operationId||!b.value||f.operationId===C.value&&(i.value||t.value)||(C.value=f.operationId,s(f.operationId))};W(()=>f.operationId,()=>{F()},{immediate:!0}),W(b,u=>{u?F():(I(),C.value=void 0)});const n=g(()=>t.value?i.value?"操作进行中":"操作结果":"操作进度"),l=g(()=>{if(!t.value)return"准备中...";const u=R(t.value.operation_type);switch(t.value.status){case c.PENDING:return`${u}操作等待执行中...`;case c.RUNNING:return`${u}操作执行中...`;case c.SUCCESS:return`${u}操作成功!`;case c.FAILED:return`${u}操作失败`;default:return"处理中..."}}),U=g(()=>t.value?t.value.status===c.SUCCESS?"操作成功":"操作失败":""),B=g(()=>t.value?t.value.status===c.SUCCESS?"text-green-600":"text-red-600":""),w=g(()=>{if(!t.value?.started_at||!t.value?.completed_at)return null;const u=new Date(t.value.started_at).getTime(),O=new Date(t.value.completed_at).getTime()-u;return O<1e3?`${O}ms`:O<6e4?`${(O/1e3).toFixed(1)}s`:`${Math.floor(O/6e4)}m ${Math.floor(O%6e4/1e3)}s`}),R=u=>oe[u]?.label||u,h=u=>new Date(u).toLocaleString("zh-CN",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit",hour12:!1}),G=u=>{I(),u()},y=()=>{b.value=!1},N=()=>{b.value=!1},_=()=>{I()};return k({currentOperation:t,isPolling:i,isCompleted:v}),(u,o)=>{const O=D("el-button"),X=D("el-dialog");return r(),V(X,{modelValue:b.value,"onUpdate:modelValue":o[0]||(o[0]=Z=>b.value=Z),title:n.value,width:"600px","close-on-click-modal":!1,"close-on-press-escape":!0,"show-close":!0,"append-to-body":"","before-close":G,onClosed:_},{footer:E(()=>[e("div",null,[P(O,{onClick:y},{default:E(()=>[...o[11]||(o[11]=[$("关闭",-1)])]),_:1}),a(t)?.status===a(c).SUCCESS?(r(),V(O,{key:0,type:"primary",onClick:N},{default:E(()=>[...o[12]||(o[12]=[$(" 确定 ",-1)])]),_:1})):S("",!0)])]),default:E(()=>[a(i)?(r(),p("div",fe,[o[5]||(o[5]=e("div",{class:"flex items-center justify-center mb-6"},[e("i",{class:"i-carbon-in-progress text-6xl text-blue-500 animate-spin"})],-1)),e("div",ve,[a(t)?(r(),V(ie,{key:0,status:a(t).status,type:"operation",size:"large",class:"mb-3"},null,8,["status"])):S("",!0),e("div",_e,d(l.value),1),a(t)?(r(),p("div",ge," 操作 ID: "+d(a(t).operation_id.slice(0,12))+"... ",1)):S("",!0)]),a(t)?(r(),p("div",ye,[e("div",Se,[o[1]||(o[1]=e("span",{class:"label"},"操作类型:",-1)),e("span",Te,d(R(a(t).operation_type)),1)]),e("div",be,[o[2]||(o[2]=e("span",{class:"label"},"服务名称:",-1)),e("span",Ce,d(a(t).service_name),1)]),a(t).target_replicas?(r(),p("div",Ee,[o[3]||(o[3]=e("span",{class:"label"},"目标副本数:",-1)),e("span",ke,d(a(t).target_replicas),1)])):S("",!0),a(t).started_at?(r(),p("div",Ie,[o[4]||(o[4]=e("span",{class:"label"},"开始时间:",-1)),e("span",we,d(h(a(t).started_at)),1)])):S("",!0)])):S("",!0)])):a(t)?(r(),p("div",Ne,[e("div",xe,[e("i",{class:j(["text-6xl",a(t).status===a(c).SUCCESS?"i-carbon-checkmark-filled text-green-500":"i-carbon-close-filled text-red-500"])},null,2)]),e("div",he,[e("div",{class:j(["text-xl font-medium mb-2",B.value])},d(U.value),3),a(t).error_message?(r(),p("div",Oe,d(a(t).error_message),1)):S("",!0)]),e("div",De,[e("div",Ue,[o[6]||(o[6]=e("span",{class:"label"},"操作类型:",-1)),e("span",Ve,d(R(a(t).operation_type)),1)]),e("div",Ae,[o[7]||(o[7]=e("span",{class:"label"},"服务名称:",-1)),e("span",Re,d(a(t).service_name),1)]),a(t).started_at?(r(),p("div",Pe,[o[8]||(o[8]=e("span",{class:"label"},"开始时间:",-1)),e("span",Le,d(h(a(t).started_at)),1)])):S("",!0),a(t).completed_at?(r(),p("div",Fe,[o[9]||(o[9]=e("span",{class:"label"},"完成时间:",-1)),e("span",$e,d(h(a(t).completed_at)),1)])):S("",!0),w.value?(r(),p("div",Be,[o[10]||(o[10]=e("span",{class:"label"},"耗时:",-1)),e("span",Ge,d(w.value),1)])):S("",!0)])])):S("",!0)]),_:1},8,["modelValue","title"])}}}),Ye=K(ze,[["__scopeId","data-v-f6597358"]]);export{Ye as O,ie as S,Me as a};
@@ -0,0 +1 @@
1
+ .status-tag[data-v-5fdd77e5]{display:inline-flex;align-items:center}.service-list[data-v-c06a7005]{margin:8px 0;padding-left:20px}.service-list li[data-v-c06a7005]{margin:4px 0;color:var(--text-primary);font-family:Courier New,monospace}.warning-list[data-v-c06a7005]{margin:8px 0;padding-left:20px}.warning-list li[data-v-c06a7005]{margin:4px 0;color:var(--text-secondary);font-size:13px}[data-v-c06a7005] .el-alert__content{flex:1}.operation-progress[data-v-f6597358],.operation-result[data-v-f6597358]{padding:20px 0}.operation-info[data-v-f6597358]{border:1px solid #e5e7eb}.info-item[data-v-f6597358]{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid #f3f4f6}.info-item[data-v-f6597358]:last-child{border-bottom:none}.info-item .label[data-v-f6597358]{color:#6b7280;font-weight:500}.info-item .value[data-v-f6597358]{color:#1f2937}.is-loading[data-v-f6597358]{animation:rotating-f6597358 2s linear infinite}@keyframes rotating-f6597358{0%{transform:rotate(0)}to{transform:rotate(360deg)}}
@@ -0,0 +1 @@
1
+ import{d as l,c as s,b as t,h as a,e as o,n as c,t as n,N as i,_ as r}from"./index-CiFlm8oc.js";const d={class:"page-container"},p={key:0,class:"page-header mb-6"},_={class:"flex flex-col md:flex-row md:items-center justify-between gap-4"},u={class:"flex items-center"},h={class:"page-title"},m={key:0,class:"page-subtitle"},f={key:0,class:"page-actions"},g={class:"page-content"},v=l({__name:"PageContainer",props:{title:{},subtitle:{},icon:{},showHeader:{type:Boolean,default:!0}},setup(b){return(e,y)=>(t(),s("div",d,[e.showHeader?(t(),s("div",p,[o("div",_,[o("div",u,[e.icon?(t(),s("i",{key:0,class:c([e.icon,"page-icon"])},null,2)):a("",!0),o("div",null,[o("h1",h,n(e.title),1),e.subtitle?(t(),s("p",m,n(e.subtitle),1)):a("",!0)])]),e.$slots.actions?(t(),s("div",f,[i(e.$slots,"actions",{},void 0,!0)])):a("",!0)])])):a("",!0),o("div",g,[i(e.$slots,"default",{},void 0,!0)])]))}}),C=r(v,[["__scopeId","data-v-35fbb750"]]);export{C as P};
@@ -0,0 +1 @@
1
+ .page-container[data-v-35fbb750]{padding:24px;min-height:calc(100vh - 60px)}.page-header[data-v-35fbb750]{background:var(--bg-elevated);padding:24px;border-radius:var(--radius-lg);box-shadow:var(--shadow-sm);border:1px solid var(--border-secondary)}.page-icon[data-v-35fbb750]{font-size:28px;margin-right:12px;color:var(--primary-500)}.page-title[data-v-35fbb750]{font-size:24px;font-weight:600;color:var(--text-primary);line-height:1.3}.page-subtitle[data-v-35fbb750]{font-size:14px;color:var(--text-secondary);margin-top:4px}.page-content[data-v-35fbb750]{margin-top:16px}@media (max-width: 768px){.page-container[data-v-35fbb750],.page-header[data-v-35fbb750]{padding:16px}.page-icon[data-v-35fbb750]{font-size:24px;margin-right:8px}.page-title[data-v-35fbb750]{font-size:20px}.page-subtitle[data-v-35fbb750]{font-size:13px}}
@@ -0,0 +1 @@
1
+ .stats-cards[data-v-449af0a5]{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--spacing-4)}.stat-card[data-v-449af0a5]{border:none;background:var(--bg-elevated)}.stat-content[data-v-449af0a5]{display:flex;align-items:center;gap:var(--spacing-4)}.stat-icon[data-v-449af0a5]{width:48px;height:48px;border-radius:var(--radius-lg);display:flex;align-items:center;justify-content:center;font-size:24px}.stat-icon-primary[data-v-449af0a5]{background:linear-gradient(135deg,var(--primary-500),var(--primary-600));color:#fff}.stat-icon-success[data-v-449af0a5]{background:linear-gradient(135deg,var(--success-500),var(--success-600));color:#fff}.stat-icon-warning[data-v-449af0a5]{background:linear-gradient(135deg,var(--warning-500),var(--warning-600));color:#fff}.stat-label[data-v-449af0a5]{color:var(--text-secondary);font-size:14px;margin:0 0 4px}.stat-value[data-v-449af0a5]{color:var(--text-primary);font-size:28px;font-weight:600;margin:0}.filter-card[data-v-449af0a5]{border:none;background:var(--bg-elevated)}.caddy-table[data-v-449af0a5]{--el-table-bg-color: var(--bg-elevated);--el-table-tr-bg-color: var(--bg-elevated);--el-table-header-bg-color: var(--bg-secondary)}.action-buttons[data-v-449af0a5]{display:flex;gap:var(--spacing-2);flex-wrap:wrap}.ip-chips[data-v-449af0a5]{display:flex;flex-wrap:wrap;gap:var(--spacing-2)}@media (max-width: 768px){.stats-cards[data-v-449af0a5]{grid-template-columns:1fr}}