chenluhua1980
7 天以前 ceb64b6612309fe384e096dcdc8b5a5e0dfe6cce
SourceCode/Bond/Servo/ProductionStats.cpp
@@ -88,7 +88,9 @@
   }
   const char* sql =
      "SELECT class_id, buddy_id, aoi_result "
      "SELECT class_id, buddy_id, aoi_result, "
      "IFNULL(strftime('%Y-%m-%d %H:%M:%S', t_start, 'localtime'), ''),"
      "IFNULL(strftime('%Y-%m-%d %H:%M:%S', t_end,   'localtime'), '') "
      "FROM glass_log "
      "WHERE t_end IS NOT NULL AND t_end >= ? AND t_end < ?;";
@@ -105,6 +107,7 @@
      bool hasPass = false;
      bool hasFail = false;
      bool hasNo = false;
      long long maxTaktSeconds = -1;
   };
   std::unordered_map<std::string, PairAgg> pairs;
@@ -114,6 +117,8 @@
         const char* classId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 0));
         const char* buddyId = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 1));
         const int aoi = sqlite3_column_int(stmt, 2);
         const char* sStart = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 3));
         const char* sEnd = reinterpret_cast<const char*>(sqlite3_column_text(stmt, 4));
         const std::string a = classId ? classId : "";
         const std::string b = buddyId ? buddyId : "";
@@ -130,6 +135,12 @@
         if (aoi == 1) agg.hasPass = true;
         else if (aoi == 2) agg.hasFail = true;
         else agg.hasNo = true;
         std::chrono::system_clock::time_point tpStart{}, tpEnd{};
         if (TryParseLocalTime(sStart ? sStart : "", tpStart) && TryParseLocalTime(sEnd ? sEnd : "", tpEnd) && tpEnd > tpStart) {
            const auto secs = std::chrono::duration_cast<std::chrono::seconds>(tpEnd - tpStart).count();
            if (secs > agg.maxTaktSeconds) agg.maxTaktSeconds = secs;
         }
      }
      else if (rc == SQLITE_DONE) {
         break;
@@ -143,14 +154,23 @@
   sqlite3_close(db);
   out.pairsTotal = static_cast<long long>(pairs.size());
   long long sumTakt = 0;
   long long cntTakt = 0;
   for (const auto& kv : pairs) {
      const auto& agg = kv.second;
      if (agg.hasFail) out.pairsFail++;
      else if (agg.hasPass) out.pairsPass++;
      else out.pairsNoResult++;
      if (agg.maxTaktSeconds >= 0) {
         sumTakt += agg.maxTaktSeconds;
         cntTakt += 1;
      }
   }
   const long long denom = out.pairsPass + out.pairsFail;
   out.yield = (denom > 0) ? (static_cast<double>(out.pairsPass) / static_cast<double>(denom)) : 0.0;
   out.taktSamplePairs = cntTakt;
   out.avgTaktSeconds = (cntTakt > 0) ? (static_cast<double>(sumTakt) / static_cast<double>(cntTakt)) : 0.0;
}
static void ComputeAlarmSummaryFromDb(
@@ -359,6 +379,7 @@
   LOGI("<ProductionStats>Shift=%s, [%s ~ %s]", shiftName, s.window.startLocal.c_str(), s.window.endLocal.c_str());
   LOGI("<ProductionStats>Output(pairs): total=%lld, pass=%lld, fail=%lld, no_result=%lld, yield=%.2f%%",
      s.output.pairsTotal, s.output.pairsPass, s.output.pairsFail, s.output.pairsNoResult, s.output.yield * 100.0);
   LOGI("<ProductionStats>Takt: avg=%.1fs, samples=%lld", s.output.avgTaktSeconds, s.output.taktSamplePairs);
   LOGI("<ProductionStats>Alarms: triggered=%d, overlapping=%d, downtime=%.1f min",
      s.alarms.alarmsTriggered, s.alarms.alarmsOverlapping, s.alarms.downtimeMinutes);
   if (!s.alarms.bySeverity.empty()) {
@@ -375,3 +396,43 @@
      LOGI("%s", oss.str().c_str());
   }
}
bool ProductionStats::ComputeDayNightSummaries(CConfiguration& config, ProductionShiftSummary& outDay, ProductionShiftSummary& outNight)
{
   ProductionShiftSummary cur;
   if (!ComputeCurrentShiftSummary(config, cur)) return false;
   // Determine previous adjacent window for the other shift.
   ProductionShiftSummary other = cur;
   if (cur.window.type == ProductionShiftType::Day) {
      other.window.type = ProductionShiftType::Night;
      other.window.end = cur.window.start;
      other.window.start = cur.window.start - (cur.window.end - cur.window.start);
   }
   else {
      other.window.type = ProductionShiftType::Day;
      other.window.end = cur.window.start;
      other.window.start = cur.window.start - (cur.window.end - cur.window.start);
   }
   other.window.startLocal = FormatLocal(other.window.start);
   other.window.endLocal = FormatLocal(other.window.end);
   other.window.startUtcIso = FormatUtcIso(other.window.start);
   other.window.endUtcIso = FormatUtcIso(other.window.end);
   other.output = ProductionOutputSummary{};
   other.alarms = ProductionAlarmSummary{};
   other.transfers = ProductionTransferSummary{};
   ComputeOutputFromProcessDb(other.window, other.output);
   ComputeAlarmSummaryFromDb(other.window, other.alarms);
   ComputeTransferSummaryFromDb(other.window, other.transfers);
   if (cur.window.type == ProductionShiftType::Day) {
      outDay = std::move(cur);
      outNight = std::move(other);
   }
   else {
      outNight = std::move(cur);
      outDay = std::move(other);
   }
   return true;
}