dashboard.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. """
  2. 仪表盘统计接口
  3. """
  4. from fastapi import APIRouter, Depends
  5. from sqlalchemy.orm import Session
  6. from sqlalchemy import func, and_
  7. from app.database import get_db
  8. from app.api.deps import get_current_admin
  9. from app.models.user import User
  10. from app.models.software import Software
  11. from app.models.card import Card
  12. from app.models.api_log import APILog
  13. from app.services.heartbeat_monitor import HeartbeatMonitor
  14. from app.background_tasks import get_task_manager
  15. from datetime import datetime, timedelta
  16. from app.utils.timezone import beijing_now
  17. router = APIRouter()
  18. @router.get("/stats")
  19. async def get_dashboard_stats(
  20. db: Session = Depends(get_db),
  21. current_admin = Depends(get_current_admin)
  22. ):
  23. """获取仪表盘统计数据"""
  24. # 用户总数
  25. total_users = db.query(func.count(User.id)).scalar() or 0
  26. # 今日新增用户
  27. today_start = beijing_now().replace(hour=0, minute=0, second=0, microsecond=0)
  28. today_new_users = db.query(func.count(User.id)).filter(
  29. User.created_at >= today_start
  30. ).scalar() or 0
  31. # 软件数量
  32. total_software = db.query(func.count(Software.id)).scalar() or 0
  33. # 卡密总数
  34. total_cards = db.query(func.count(Card.id)).scalar() or 0
  35. # 已激活卡密数
  36. activated_cards = db.query(func.count(Card.id)).filter(
  37. Card.status == 1
  38. ).scalar() or 0
  39. # 未激活卡密数
  40. unactivated_cards = db.query(func.count(Card.id)).filter(
  41. Card.status == 0
  42. ).scalar() or 0
  43. # 日志总数
  44. total_logs = db.query(func.count(APILog.id)).scalar() or 0
  45. # 今日日志数
  46. today_logs = db.query(func.count(APILog.id)).filter(
  47. APILog.created_at >= today_start
  48. ).scalar() or 0
  49. # 有效用户数(未过期)
  50. active_users = db.query(func.count(User.id)).filter(
  51. and_(
  52. User.expire_time.isnot(None),
  53. User.expire_time > beijing_now()
  54. )
  55. ).scalar() or 0
  56. # 过期用户数
  57. expired_users = db.query(func.count(User.id)).filter(
  58. and_(
  59. User.expire_time.isnot(None),
  60. User.expire_time <= beijing_now()
  61. )
  62. ).scalar() or 0
  63. # 最近7天新增用户趋势
  64. seven_days_ago = beijing_now() - timedelta(days=7)
  65. recent_users = db.query(
  66. func.date(User.created_at).label('date'),
  67. func.count(User.id).label('count')
  68. ).filter(
  69. User.created_at >= seven_days_ago
  70. ).group_by(func.date(User.created_at)).all()
  71. user_trend = [
  72. {
  73. "date": str(row.date),
  74. "count": row.count
  75. }
  76. for row in recent_users
  77. ]
  78. # 最近7天日志趋势
  79. recent_logs = db.query(
  80. func.date(APILog.created_at).label('date'),
  81. func.count(APILog.id).label('count')
  82. ).filter(
  83. APILog.created_at >= seven_days_ago
  84. ).group_by(func.date(APILog.created_at)).all()
  85. log_trend = [
  86. {
  87. "date": str(row.date),
  88. "count": row.count
  89. }
  90. for row in recent_logs
  91. ]
  92. # 获取心跳监控统计
  93. heartbeat_stats = HeartbeatMonitor.get_monitoring_stats()
  94. # 获取后台任务状态
  95. task_manager = get_task_manager()
  96. background_tasks_status = {
  97. "running": task_manager.running,
  98. "total_tasks": len(task_manager.tasks),
  99. "active_tasks": sum(1 for task in task_manager.tasks if not task.done()),
  100. "completed_tasks": sum(1 for task in task_manager.tasks if task.done()),
  101. }
  102. return {
  103. "code": 200,
  104. "msg": "成功",
  105. "data": {
  106. "users": {
  107. "total": total_users,
  108. "today_new": today_new_users,
  109. "active": active_users,
  110. "expired": expired_users,
  111. "trend": user_trend
  112. },
  113. "software": {
  114. "total": total_software
  115. },
  116. "cards": {
  117. "total": total_cards,
  118. "activated": activated_cards,
  119. "unactivated": unactivated_cards
  120. },
  121. "logs": {
  122. "total": total_logs,
  123. "today": today_logs,
  124. "trend": log_trend
  125. },
  126. "heartbeat": heartbeat_stats,
  127. "background_tasks": background_tasks_status
  128. }
  129. }
  130. @router.get("/background-tasks/status")
  131. async def get_background_tasks_status(
  132. db: Session = Depends(get_db),
  133. current_admin = Depends(get_current_admin)
  134. ):
  135. """获取后台任务状态详情"""
  136. task_manager = get_task_manager()
  137. # 获取各个任务的详细信息
  138. task_details = []
  139. for i, task in enumerate(task_manager.tasks):
  140. task_info = {
  141. "id": i + 1,
  142. "name": f"后台任务-{i + 1}",
  143. "status": "running" if not task.done() else "completed",
  144. "done": task.done(),
  145. "cancelled": task.cancelled(),
  146. }
  147. # 如果任务已完成,获取结果或异常信息
  148. if task.done():
  149. try:
  150. result = task.result()
  151. task_info["result"] = str(result) if result is not None else None
  152. except Exception as e:
  153. task_info["exception"] = str(e)
  154. task_details.append(task_info)
  155. return {
  156. "code": 200,
  157. "msg": "成功",
  158. "data": {
  159. "manager_running": task_manager.running,
  160. "total_tasks": len(task_manager.tasks),
  161. "tasks": task_details
  162. }
  163. }
  164. @router.get("/client-configs")
  165. async def get_client_configs(
  166. db: Session = Depends(get_db),
  167. current_admin = Depends(get_current_admin)
  168. ):
  169. """获取客户端配置(供客户端使用)"""
  170. from app.models.system_config import SystemConfig
  171. # 获取客户端需要的配置
  172. client_configs = {
  173. "api_timeout_seconds": SystemConfig.get_config_value('api_timeout_seconds', 30),
  174. "client_heartbeat_interval_seconds": SystemConfig.get_config_value('client_heartbeat_interval_seconds', 30),
  175. "max_heartbeat_failures": SystemConfig.get_config_value('max_heartbeat_failures', 10),
  176. "max_network_failures": SystemConfig.get_config_value('max_network_failures', 15),
  177. }
  178. return {
  179. "code": 200,
  180. "msg": "成功",
  181. "data": client_configs
  182. }