evaluation_service.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from __future__ import annotations
  2. from datetime import datetime, timezone
  3. from sqlalchemy.orm import Session
  4. from app.db.base import new_id
  5. from app.db.models.evaluation import EvaluationRun
  6. from app.db.repositories import diagnosis as diagnosis_repo
  7. from app.db.repositories import evaluation as evaluation_repo
  8. from app.db.repositories import monitoring as monitoring_repo
  9. from app.db.repositories import work_order as work_order_repo
  10. from app.schemas.evaluation import EvaluationRunRequest
  11. from app.services.mine_service import require_mine
  12. def _run_no() -> str:
  13. stamp = datetime.now(timezone.utc).strftime("%Y%m%d%H%M%S")
  14. return f"EV-{stamp}-{new_id()[:6].upper()}"
  15. def _grade(score: float) -> str:
  16. if score >= 90:
  17. return "A"
  18. if score >= 80:
  19. return "B"
  20. if score >= 70:
  21. return "C"
  22. return "D"
  23. def run_evaluation(
  24. db: Session,
  25. payload: EvaluationRunRequest,
  26. ) -> EvaluationRun:
  27. mine = require_mine(db, payload.mine_id)
  28. monitoring = monitoring_repo.monitoring_overview(db, mine.id)
  29. defects = diagnosis_repo.result_summary(db, mine.id)
  30. work_orders = work_order_repo.status_summary(db, mine.id)
  31. sensor_total = max(monitoring["sensor_count"], 1)
  32. online_ratio = monitoring["online_sensor_count"] / sensor_total
  33. high_defects = defects.get("high", 0)
  34. medium_defects = defects.get("medium", 0)
  35. open_orders = work_orders.get("pending", 0) + work_orders.get("processing", 0)
  36. total_orders = max(sum(work_orders.values()), 1)
  37. dimension_scores = {
  38. "安全性": max(50, 100 - high_defects * 8 - medium_defects * 3),
  39. "可靠性": round(70 + online_ratio * 30, 2),
  40. "经济性": 85.0,
  41. "管理合规": max(60, 100 - open_orders / total_orders * 30),
  42. "数据质量": round(80 + online_ratio * 15, 2),
  43. }
  44. default_weights = {
  45. "安全性": 0.3,
  46. "可靠性": 0.2,
  47. "经济性": 0.15,
  48. "管理合规": 0.2,
  49. "数据质量": 0.15,
  50. }
  51. total_score = round(
  52. sum(dimension_scores[key] * default_weights[key] for key in dimension_scores),
  53. 2,
  54. )
  55. grade = _grade(total_score)
  56. recommendations = []
  57. if high_defects:
  58. recommendations.append("优先处置高风险缺陷并完成复核闭环。")
  59. if online_ratio < 0.95:
  60. recommendations.append("核查离线传感器通讯与供电状态,提高数据连续性。")
  61. if open_orders:
  62. recommendations.append("压降未闭环工单数量,重点关注逾期和超时任务。")
  63. if not recommendations:
  64. recommendations.append("维持当前通防业务管控状态,继续按周期复评。")
  65. run = evaluation_repo.create_run(
  66. db,
  67. {
  68. "mine_id": mine.id,
  69. "run_no": _run_no(),
  70. "period_start": payload.period_start,
  71. "period_end": payload.period_end,
  72. "status": "completed",
  73. "total_score": total_score,
  74. "grade": grade,
  75. "summary": (
  76. f"{mine.name}通防业务综合得分 {total_score},等级 {grade}。"
  77. f"当前高风险缺陷 {high_defects} 项,传感器在线率 {online_ratio:.1%}。"
  78. ),
  79. "recommendations": recommendations,
  80. "weight_snapshot": default_weights,
  81. "input_snapshot": payload.context,
  82. "model_output": {
  83. "dimension_scores": dimension_scores,
  84. "monitoring": monitoring,
  85. "defects": defects,
  86. "work_orders": work_orders,
  87. },
  88. "started_at": datetime.now(timezone.utc),
  89. "finished_at": datetime.now(timezone.utc),
  90. "created_by": payload.requested_by,
  91. },
  92. )
  93. indicators = evaluation_repo.list_indicators(db, mine_id=mine.id)
  94. if indicators:
  95. for indicator in indicators:
  96. score = dimension_scores.get(indicator.dimension, 80)
  97. weight = indicator.weight if indicator.weight else default_weights.get(indicator.dimension, 0)
  98. evaluation_repo.create_score(
  99. db,
  100. {
  101. "run_id": run.id,
  102. "indicator_id": indicator.id,
  103. "raw_value": score,
  104. "score": score,
  105. "weighted_score": round(score * weight, 2),
  106. "weight": weight,
  107. "level": _grade(score),
  108. "evidence": "根据监测在线率、缺陷数量、工单闭环和业务基础数据综合计算。",
  109. "metadata_json": {},
  110. },
  111. )
  112. return run