diff --git a/api.asp b/api.asp
index 998a9e4..6025c98 100644
--- a/api.asp
+++ b/api.asp
@@ -49,10 +49,14 @@ Select Case action
GetRecordedIP()
Case "updateMachinePositions"
UpdateMachinePositions()
- Case "logDNCEvent"
- LogDNCEvent()
- Case "getDNCStats"
- GetDNCStats()
+ Case "getUDCPartRuns"
+ GetUDCPartRuns()
+ Case "getUDCOperatorStats"
+ GetUDCOperatorStats()
+ Case "getUDCMachineStats"
+ GetUDCMachineStats()
+ Case "getUDCManualTiming"
+ GetUDCManualTiming()
Case Else
SendError "Invalid action: " & action
End Select
@@ -2546,99 +2550,47 @@ Sub UpdateMachinePositions()
End Sub
' ============================================================================
-' eDNC SPECIAL CHARACTER FIX - LOGGING
+' UDC LOG DATA ENDPOINTS
' ============================================================================
-Sub LogDNCEvent()
+Sub GetUDCPartRuns()
On Error Resume Next
- ' Get parameters
- Dim hostname, filename, eventAction, bytesRemoved, version, message
- hostname = Trim(Request.Form("hostname") & "")
- filename = Trim(Request.Form("filename") & "")
- eventAction = Trim(Request.Form("eventType") & "")
- bytesRemoved = Request.Form("bytesRemoved")
- version = Trim(Request.Form("version") & "")
- message = Trim(Request.Form("message") & "")
+ ' Get optional filters
+ Dim machinenumber, startdate, enddate, badgenumber
+ machinenumber = Trim(Request.QueryString("machinenumber") & "")
+ startdate = Trim(Request.QueryString("startdate") & "")
+ enddate = Trim(Request.QueryString("enddate") & "")
+ badgenumber = Trim(Request.QueryString("badgenumber") & "")
- ' Validate required fields
- If hostname = "" Or eventAction = "" Then
- SendError "hostname and eventType are required"
- Exit Sub
+ ' Build query
+ Dim sql, conditions
+ sql = "SELECT p.partrunid, s.machinenumber, p.partnumber, p.opernumber, p.serialnumber, " & _
+ "p.programname, p.jobnumber, p.badgenumber, p.programstart, p.programend, " & _
+ "p.cycletime, p.changeover, p.measurementcount, p.manualcount, p.probecount, p.ootcount " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid "
+
+ conditions = ""
+ If machinenumber <> "" Then
+ conditions = conditions & " AND s.machinenumber = '" & Replace(machinenumber, "'", "''") & "'"
+ End If
+ If startdate <> "" Then
+ conditions = conditions & " AND p.programstart >= '" & Replace(startdate, "'", "''") & "'"
+ End If
+ If enddate <> "" Then
+ conditions = conditions & " AND p.programstart <= '" & Replace(enddate, "'", "''") & " 23:59:59'"
+ End If
+ If badgenumber <> "" Then
+ conditions = conditions & " AND p.badgenumber = '" & Replace(badgenumber, "'", "''") & "'"
End If
- ' Default bytesRemoved to 0 if not numeric
- If Not IsNumeric(bytesRemoved) Or bytesRemoved = "" Then bytesRemoved = 0
-
- ' Get machineid from hostname (required for logging)
- Dim safeHostname, machineid, rsLookup
- safeHostname = Replace(hostname, "'", "''")
- Set rsLookup = objConn.Execute("SELECT machineid FROM machines WHERE UPPER(hostname) = UPPER('" & safeHostname & "') AND pctypeid IS NOT NULL LIMIT 1")
-
- If rsLookup.EOF Then
- rsLookup.Close
- Set rsLookup = Nothing
- SendError "Unknown hostname: " & hostname
- Exit Sub
+ If conditions <> "" Then
+ sql = sql & " WHERE 1=1 " & conditions
End If
+ sql = sql & " ORDER BY p.programstart DESC LIMIT 1000"
- machineid = CLng(rsLookup("machineid"))
- rsLookup.Close
- Set rsLookup = Nothing
-
- ' Sanitize remaining inputs
- Dim safeFilename, safeAction, safeVersion, safeMessage
- safeFilename = Replace(filename, "'", "''")
- safeAction = Replace(eventAction, "'", "''")
- safeVersion = Replace(version, "'", "''")
- safeMessage = Replace(message, "'", "''")
-
- ' Insert log entry using machineid
- Dim insertSQL
- insertSQL = "INSERT INTO ednclogs (machineid, filename, action, bytes_removed, version, message) " & _
- "VALUES (" & machineid & ", '" & safeFilename & "', '" & safeAction & "', " & _
- CLng(bytesRemoved) & ", '" & safeVersion & "', '" & safeMessage & "')"
- objConn.Execute insertSQL
-
- If Err.Number <> 0 Then
- SendError "Failed to log event: " & Err.Description
- Exit Sub
- End If
-
- ' Track in installedapps (appid 79 = eDNC Special Character Fix)
- Dim edncAppId, rsApp
- edncAppId = 79
-
- ' Check if already in installedapps
- Set rsApp = objConn.Execute("SELECT installedappid FROM installedapps WHERE machineid = " & machineid & " AND appid = " & edncAppId)
- If rsApp.EOF Then
- ' Insert new record
- objConn.Execute "INSERT INTO installedapps (appid, machineid, isactive) VALUES (" & edncAppId & ", " & machineid & ", 1)"
- End If
- rsApp.Close
- Set rsApp = Nothing
-
- ' Send success response
- Response.Write "{""success"":true,""message"":""Event logged""}"
-End Sub
-
-Sub GetDNCStats()
- On Error Resume Next
-
- ' Get stats derived from ednclogs, joined to machines for hostname
- Dim sql, rs
- sql = "SELECT m.hostname, " & _
- "(SELECT version FROM ednclogs WHERE machineid = l.machineid ORDER BY created DESC LIMIT 1) AS version, " & _
- "MIN(l.created) AS first_seen, " & _
- "MAX(l.created) AS last_seen, " & _
- "SUM(CASE WHEN l.action = 'cleaned' THEN 1 ELSE 0 END) AS total_cleaned, " & _
- "SUM(CASE WHEN l.action = 'failed' THEN 1 ELSE 0 END) AS total_failed, " & _
- "(SELECT COUNT(*) FROM ednclogs WHERE machineid = l.machineid AND created > DATE_SUB(NOW(), INTERVAL 24 HOUR)) AS events_24h " & _
- "FROM ednclogs l " & _
- "INNER JOIN machines m ON l.machineid = m.machineid " & _
- "GROUP BY l.machineid, m.hostname " & _
- "ORDER BY last_seen DESC"
-
+ Dim rs
Set rs = objConn.Execute(sql)
If Err.Number <> 0 Then
@@ -2648,7 +2600,7 @@ Sub GetDNCStats()
' Build JSON response
Dim json, first
- json = "{""success"":true,""installations"":["
+ json = "{""success"":true,""partruns"":["
first = True
Do While Not rs.EOF
@@ -2656,22 +2608,236 @@ Sub GetDNCStats()
first = False
json = json & "{" & _
- """hostname"":""" & (rs("hostname") & "") & """," & _
- """version"":""" & (rs("version") & "") & """," & _
- """firstSeen"":""" & (rs("first_seen") & "") & """," & _
- """lastSeen"":""" & (rs("last_seen") & "") & """," & _
- """totalCleaned"":" & (rs("total_cleaned") + 0) & "," & _
- """totalFailed"":" & (rs("total_failed") + 0) & "," & _
- """events24h"":" & (rs("events_24h") + 0) & _
+ """partrunid"":" & CLng(rs("partrunid") & "0") & "," & _
+ """machinenumber"":""" & (rs("machinenumber") & "") & """," & _
+ """partnumber"":""" & (rs("partnumber") & "") & """," & _
+ """opernumber"":""" & (rs("opernumber") & "") & """," & _
+ """serialnumber"":""" & (rs("serialnumber") & "") & """," & _
+ """programname"":""" & (rs("programname") & "") & """," & _
+ """jobnumber"":""" & (rs("jobnumber") & "") & """," & _
+ """badgenumber"":""" & (rs("badgenumber") & "") & """," & _
+ """programstart"":""" & (rs("programstart") & "") & """," & _
+ """programend"":""" & (rs("programend") & "") & """," & _
+ """cycletime"":" & CLng(rs("cycletime") & "0") & "," & _
+ """changeover"":" & CLng(rs("changeover") & "0") & "," & _
+ """measurementcount"":" & CLng(rs("measurementcount") & "0") & "," & _
+ """manualcount"":" & CLng(rs("manualcount") & "0") & "," & _
+ """probecount"":" & CLng(rs("probecount") & "0") & "," & _
+ """ootcount"":" & CLng(rs("ootcount") & "0") & _
"}"
rs.MoveNext
Loop
json = json & "]}"
-
rs.Close
Set rs = Nothing
+ Response.ContentType = "application/json"
+ Response.Write json
+End Sub
+
+Sub GetUDCOperatorStats()
+ On Error Resume Next
+
+ Dim startdate, enddate
+ startdate = Trim(Request.QueryString("startdate") & "")
+ enddate = Trim(Request.QueryString("enddate") & "")
+
+ Dim sql, conditions
+ sql = "SELECT p.badgenumber, COUNT(*) AS partsrun, " & _
+ "AVG(p.cycletime) AS avgcycletime, AVG(p.changeover) AS avgchangeover, " & _
+ "SUM(p.measurementcount) AS totalmeasurements, SUM(p.manualcount) AS totalmanual, " & _
+ "SUM(p.ootcount) AS totaloot, MIN(p.programstart) AS firstrun, MAX(p.programend) AS lastrun, " & _
+ "(SELECT AVG(mr.responseseconds) FROM udcmanualrequests mr " & _
+ " JOIN udcparts p2 ON mr.partrunid = p2.partrunid WHERE p2.badgenumber = p.badgenumber) AS avgmanualtime " & _
+ "FROM udcparts p " & _
+ "WHERE p.badgenumber IS NOT NULL AND p.badgenumber != '' "
+
+ If startdate <> "" Then
+ sql = sql & " AND p.programstart >= '" & Replace(startdate, "'", "''") & "'"
+ End If
+ If enddate <> "" Then
+ sql = sql & " AND p.programstart <= '" & Replace(enddate, "'", "''") & " 23:59:59'"
+ End If
+
+ sql = sql & " GROUP BY p.badgenumber ORDER BY partsrun DESC"
+
+ Dim rs
+ Set rs = objConn.Execute(sql)
+
+ If Err.Number <> 0 Then
+ SendError "Database error: " & Err.Description
+ Exit Sub
+ End If
+
+ Dim json, first
+ Dim avgCycle, avgChange, avgManual
+ json = "{""success"":true,""operators"":["
+ first = True
+
+ Do While Not rs.EOF
+ If Not first Then json = json & ","
+ first = False
+
+ If IsNull(rs("avgcycletime")) Then avgCycle = 0 Else avgCycle = Round(CDbl(rs("avgcycletime")), 0)
+ If IsNull(rs("avgchangeover")) Then avgChange = 0 Else avgChange = Round(CDbl(rs("avgchangeover")), 0)
+ If IsNull(rs("avgmanualtime")) Then avgManual = 0 Else avgManual = Round(CDbl(rs("avgmanualtime")), 0)
+
+ json = json & "{" & _
+ """badgenumber"":""" & (rs("badgenumber") & "") & """," & _
+ """partsrun"":" & CLng(rs("partsrun") & "0") & "," & _
+ """avgcycletime"":" & avgCycle & "," & _
+ """avgchangeover"":" & avgChange & "," & _
+ """avgmanualtime"":" & avgManual & "," & _
+ """totalmeasurements"":" & CLng(rs("totalmeasurements") & "0") & "," & _
+ """totalmanual"":" & CLng(rs("totalmanual") & "0") & "," & _
+ """totaloot"":" & CLng(rs("totaloot") & "0") & "," & _
+ """firstrun"":""" & (rs("firstrun") & "") & """," & _
+ """lastrun"":""" & (rs("lastrun") & "") & """" & _
+ "}"
+ rs.MoveNext
+ Loop
+
+ json = json & "]}"
+ rs.Close
+ Set rs = Nothing
+
+ Response.ContentType = "application/json"
+ Response.Write json
+End Sub
+
+Sub GetUDCMachineStats()
+ On Error Resume Next
+
+ Dim startdate, enddate
+ startdate = Trim(Request.QueryString("startdate") & "")
+ enddate = Trim(Request.QueryString("enddate") & "")
+
+ Dim sql
+ sql = "SELECT s.machinenumber, COUNT(*) AS partsrun, " & _
+ "AVG(p.cycletime) AS avgcycletime, AVG(p.changeover) AS avgchangeover, " & _
+ "SUM(p.measurementcount) AS totalmeasurements, SUM(p.ootcount) AS totaloot, " & _
+ "MIN(p.programstart) AS firstrun, MAX(p.programend) AS lastrun " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid "
+
+ If startdate <> "" Or enddate <> "" Then
+ sql = sql & " WHERE 1=1 "
+ If startdate <> "" Then
+ sql = sql & " AND p.programstart >= '" & Replace(startdate, "'", "''") & "'"
+ End If
+ If enddate <> "" Then
+ sql = sql & " AND p.programstart <= '" & Replace(enddate, "'", "''") & " 23:59:59'"
+ End If
+ End If
+
+ sql = sql & " GROUP BY s.machinenumber ORDER BY partsrun DESC"
+
+ Dim rs
+ Set rs = objConn.Execute(sql)
+
+ If Err.Number <> 0 Then
+ SendError "Database error: " & Err.Description
+ Exit Sub
+ End If
+
+ Dim json, first
+ Dim avgCycle, avgChange
+ json = "{""success"":true,""machines"":["
+ first = True
+
+ Do While Not rs.EOF
+ If Not first Then json = json & ","
+ first = False
+
+ If IsNull(rs("avgcycletime")) Then avgCycle = 0 Else avgCycle = Round(CDbl(rs("avgcycletime")), 0)
+ If IsNull(rs("avgchangeover")) Then avgChange = 0 Else avgChange = Round(CDbl(rs("avgchangeover")), 0)
+
+ json = json & "{" & _
+ """machinenumber"":""" & (rs("machinenumber") & "") & """," & _
+ """partsrun"":" & CLng(rs("partsrun") & "0") & "," & _
+ """avgcycletime"":" & avgCycle & "," & _
+ """avgchangeover"":" & avgChange & "," & _
+ """totalmeasurements"":" & CLng(rs("totalmeasurements") & "0") & "," & _
+ """totaloot"":" & CLng(rs("totaloot") & "0") & "," & _
+ """firstrun"":""" & (rs("firstrun") & "") & """," & _
+ """lastrun"":""" & (rs("lastrun") & "") & """" & _
+ "}"
+ rs.MoveNext
+ Loop
+
+ json = json & "]}"
+ rs.Close
+ Set rs = Nothing
+
+ Response.ContentType = "application/json"
+ Response.Write json
+End Sub
+
+Sub GetUDCManualTiming()
+ On Error Resume Next
+
+ Dim machinenumber, startdate, enddate
+ machinenumber = Trim(Request.QueryString("machinenumber") & "")
+ startdate = Trim(Request.QueryString("startdate") & "")
+ enddate = Trim(Request.QueryString("enddate") & "")
+
+ Dim sql, conditions
+ sql = "SELECT mr.requestid, p.badgenumber, s.machinenumber, " & _
+ "mr.requesttime, mr.responsetime, mr.responseseconds, mr.description " & _
+ "FROM udcmanualrequests mr " & _
+ "JOIN udcparts p ON mr.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid "
+
+ conditions = ""
+ If machinenumber <> "" Then
+ conditions = conditions & " AND s.machinenumber = '" & Replace(machinenumber, "'", "''") & "'"
+ End If
+ If startdate <> "" Then
+ conditions = conditions & " AND mr.requesttime >= '" & Replace(startdate, "'", "''") & "'"
+ End If
+ If enddate <> "" Then
+ conditions = conditions & " AND mr.requesttime <= '" & Replace(enddate, "'", "''") & " 23:59:59'"
+ End If
+
+ If conditions <> "" Then
+ sql = sql & " WHERE 1=1 " & conditions
+ End If
+ sql = sql & " ORDER BY mr.requesttime DESC LIMIT 1000"
+
+ Dim rs
+ Set rs = objConn.Execute(sql)
+
+ If Err.Number <> 0 Then
+ SendError "Database error: " & Err.Description
+ Exit Sub
+ End If
+
+ Dim json, first
+ json = "{""success"":true,""manualrequests"":["
+ first = True
+
+ Do While Not rs.EOF
+ If Not first Then json = json & ","
+ first = False
+
+ json = json & "{" & _
+ """requestid"":" & CLng(rs("requestid") & "0") & "," & _
+ """badgenumber"":""" & (rs("badgenumber") & "") & """," & _
+ """machinenumber"":""" & (rs("machinenumber") & "") & """," & _
+ """requesttime"":""" & (rs("requesttime") & "") & """," & _
+ """responsetime"":""" & (rs("responsetime") & "") & """," & _
+ """responseseconds"":" & CLng(rs("responseseconds") & "0") & "," & _
+ """description"":""" & Replace(rs("description") & "", """", "\""") & """" & _
+ "}"
+ rs.MoveNext
+ Loop
+
+ json = json & "]}"
+ rs.Close
+ Set rs = Nothing
+
+ Response.ContentType = "application/json"
Response.Write json
End Sub
diff --git a/displaymachine.asp b/displaymachine.asp
index c4d73f3..48256ad 100644
--- a/displaymachine.asp
+++ b/displaymachine.asp
@@ -112,6 +112,24 @@
Response.Redirect("default.asp")
Response.End
End If
+
+ ' Check if machine has UDC data (only for equipment with machinenumber)
+ Dim rsUDCCheck, hasUDCData, strSQL2, machineNum
+ hasUDCData = False
+ machineNum = rs("machinenumber") & ""
+ If machineNum <> "" Then
+ strSQL2 = "SELECT COUNT(*) as cnt FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ?"
+ Set rsUDCCheck = ExecuteParameterizedQuery(objConn, strSQL2, Array(machineNum))
+ If Not rsUDCCheck Is Nothing Then
+ If Not rsUDCCheck.EOF Then
+ If CLng(rsUDCCheck("cnt") & "0") > 0 Then hasUDCData = True
+ End If
+ rsUDCCheck.Close
+ Set rsUDCCheck = Nothing
+ End If
+ End If
%>
@@ -143,6 +161,12 @@
<%=Server.HTMLEncode(rs("machinetype") & "")%>
<%' machinedescription column doesn't exist in Phase 2 schema %>
<%=Server.HTMLEncode(rs("machinenotes") & "")%>
+<%
+ ' Only show Print Badge for equipment (has machinenumber), not servers/network devices
+ If Trim(rs("machinenumber") & "") <> "" Then
+%>
+ Print Badge
+<% End If %>
@@ -168,6 +192,11 @@
Applications
+<% End If %>
+<% If hasUDCData Then %>
+
+ UDC
+
<% End If %>
Edit Machine
@@ -408,6 +437,7 @@ End If
| PC Hostname |
IP Address |
+ Location |
Relationship |
@@ -416,7 +446,8 @@ End If
' Query PCs that control this machine (directly or via dualpath)
' Check both directions - the PC is identified by pctypeid IS NOT NULL
' Use GROUP_CONCAT to combine multiple IPs into one row per PC
- strSQL2 = "SELECT m.machineid, m.machinenumber, m.hostname, GROUP_CONCAT(DISTINCT c.address ORDER BY c.address SEPARATOR ', ') as address, 'Controls' as relationshiptype " & _
+ strSQL2 = "SELECT m.machineid, m.machinenumber, m.hostname, " & _
+ "GROUP_CONCAT(DISTINCT c.address ORDER BY c.address SEPARATOR ', ') as address, 'Controls' as relationshiptype " & _
"FROM machinerelationships mr " & _
"JOIN machines m ON (mr.machineid = m.machineid OR mr.related_machineid = m.machineid) " & _
"LEFT JOIN communications c ON m.machineid = c.machineid AND c.comstypeid IN (1, 3) AND c.isactive = 1 " & _
@@ -425,11 +456,11 @@ End If
"GROUP BY m.machineid, m.machinenumber, m.hostname"
Set rs2 = ExecuteParameterizedQuery(objConn, strSQL2, Array(machineid, machineid, machineid))
+ Dim pcHostname, pcIP, pcMachineID
If rs2.EOF Then
- Response.Write("| No controlling PC assigned |
")
+ Response.Write("| No controlling PC assigned |
")
Else
Do While Not rs2.EOF
- Dim pcHostname, pcIP, pcMachineID
pcHostname = rs2("hostname") & ""
pcIP = rs2("address") & ""
pcMachineID = rs2("machineid")
@@ -440,6 +471,7 @@ End If
Response.Write("")
Response.Write("| " & Server.HTMLEncode(pcHostname) & " | ")
Response.Write("" & pcIP & " | ")
+ Response.Write(" | ")
Response.Write("" & Server.HTMLEncode(rs2("relationshiptype") & "") & " | ")
Response.Write("
")
rs2.MoveNext
@@ -787,6 +819,338 @@ End If
+<% End If %>
+<% If hasUDCData Then %>
+
+
UDC Performance Data
+
+
+
+<%
+' Get today's UDC stats for this machine
+Dim rsUDCToday, todayParts, todayOOT, todayAvgCycle, todayLastBadge
+strSQL2 = "SELECT COUNT(*) as partstoday, " & _
+ "SUM(ootcount) as oottoday, " & _
+ "AVG(cycletime) as avgcycle, " & _
+ "(SELECT badgenumber FROM udcparts p2 JOIN udcsessions s2 ON p2.sessionid = s2.sessionid " & _
+ " WHERE s2.machinenumber = ? ORDER BY p2.programend DESC LIMIT 1) as lastbadge " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ? AND DATE(p.programstart) = CURDATE()"
+Set rsUDCToday = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & "", rs("machinenumber") & ""))
+If Not rsUDCToday.EOF Then
+ todayParts = CLng(rsUDCToday("partstoday") & "0")
+ todayOOT = CLng(rsUDCToday("oottoday") & "0")
+ If Not IsNull(rsUDCToday("avgcycle")) Then
+ todayAvgCycle = FormatNumber(CDbl(rsUDCToday("avgcycle")) / 60, 1)
+ Else
+ todayAvgCycle = "0"
+ End If
+ todayLastBadge = rsUDCToday("lastbadge") & ""
+Else
+ todayParts = 0
+ todayOOT = 0
+ todayAvgCycle = "0"
+ todayLastBadge = ""
+End If
+rsUDCToday.Close
+Set rsUDCToday = Nothing
+%>
+
+
+
+
<%=todayParts%>
+ Parts Today
+
+
+
+
+
+
+
<%=todayAvgCycle%>m
+ Avg Cycle Time
+
+
+
+
+
text-white">
+
+
<%=todayOOT%>
+ OOT Today
+
+
+
+
+
+
+
<%If todayLastBadge <> "" Then Response.Write(Server.HTMLEncode(todayLastBadge)) Else Response.Write("-")%>
+ Current Operator
+
+
+
+
+
+
+
Recent Activity
+
+
+
+
+ | Time |
+ Type |
+ Badge |
+ Details |
+
+
+
+<%
+' Get recent activity (violations + badge changes) for this machine
+Dim rsActivity, actBadge
+strSQL2 = "SELECT * FROM (" & _
+ "SELECT eventtime, 'Violation' as acttype, badgenumber, " & _
+ "CONCAT(crossingdesc, ': ', previousval, ' -> ', currentval) as details " & _
+ "FROM udcviolations WHERE machinenumber = ? " & _
+ "UNION ALL " & _
+ "SELECT eventtime, 'Badge Change' as acttype, badgenumber, details " & _
+ "FROM udcheaderupdates WHERE machinenumber = ? " & _
+ ") combined ORDER BY eventtime DESC LIMIT 15"
+Set rsActivity = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & "", rs("machinenumber") & ""))
+If rsActivity.EOF Then
+ Response.Write("| No recent activity |
")
+Else
+ Do While Not rsActivity.EOF
+ If rsActivity("acttype") = "Violation" Then
+ actBadge = "Setting Change"
+ Else
+ actBadge = "Badge"
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsActivity("eventtime") & "") & " | ")
+ Response.Write("" & actBadge & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActivity("badgenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActivity("details") & "") & " | ")
+ Response.Write("
")
+ rsActivity.MoveNext
+ Loop
+End If
+rsActivity.Close
+Set rsActivity = Nothing
+%>
+
+
+
+
+
+
Tool Health
+<%
+' Get tool health summary for this machine (last 30 days)
+Dim rsToolSummary, toolCount, toolMeasurements, toolOOT, toolLastCheck
+strSQL2 = "SELECT COUNT(DISTINCT t.toolnumber) as unique_tools, " & _
+ "COUNT(*) as total_measurements, " & _
+ "SUM(t.oot) as oot_count, " & _
+ "MAX(t.eventtime) as last_check " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ? AND t.eventtime >= DATE_SUB(NOW(), INTERVAL 30 DAY)"
+Set rsToolSummary = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & ""))
+If Not rsToolSummary.EOF Then
+ toolCount = CLng(rsToolSummary("unique_tools") & "0")
+ toolMeasurements = CLng(rsToolSummary("total_measurements") & "0")
+ toolOOT = CLng(rsToolSummary("oot_count") & "0")
+ toolLastCheck = rsToolSummary("last_check") & ""
+Else
+ toolCount = 0
+ toolMeasurements = 0
+ toolOOT = 0
+ toolLastCheck = ""
+End If
+rsToolSummary.Close
+Set rsToolSummary = Nothing
+
+If toolMeasurements > 0 Then
+%>
+
+
+
+
+
+
<%=toolCount%>
+ Tools Monitored
+
+
+
+
+
+
+
<%=toolMeasurements%>
+ Measurements (30d)
+
+
+
+
+
+
+
+
<%If toolLastCheck <> "" Then Response.Write(Server.HTMLEncode(Left(toolLastCheck, 16))) Else Response.Write("-")%>
+ Last Tool Check
+
+
+
+
+
+
+
+
+
+
+ | Tool # |
+ Description |
+ Checks |
+ Avg Dev |
+ Max Dev |
+ Status |
+
+
+
+<%
+' Get tool status by tool number
+Dim rsTools, toolStatus, toolStatusClass, toolAvgDev, toolMaxDev, toolDevPct
+strSQL2 = "SELECT t.toolnumber, " & _
+ "MAX(t.description) as description, " & _
+ "COUNT(*) as measurements, " & _
+ "ROUND(AVG(t.deviation), 4) as avg_deviation, " & _
+ "ROUND(MAX(ABS(t.deviation)), 4) as max_deviation, " & _
+ "MAX(ABS(t.minval)) as tolerance_ref, " & _
+ "SUM(t.oot) as oot_count " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ? AND t.eventtime >= DATE_SUB(NOW(), INTERVAL 30 DAY) " & _
+ "GROUP BY t.toolnumber " & _
+ "ORDER BY oot_count DESC, measurements DESC " & _
+ "LIMIT 10"
+Set rsTools = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & ""))
+If rsTools.EOF Then
+ Response.Write("| No tool data available |
")
+Else
+ Do While Not rsTools.EOF
+ ' Calculate status based on OOT and deviation
+ If CLng(rsTools("oot_count") & "0") > 0 Then
+ toolStatus = " OOT"
+ toolStatusClass = "bg-danger text-white"
+ Else
+ toolStatus = " OK"
+ toolStatusClass = ""
+ End If
+
+ If Not IsNull(rsTools("avg_deviation")) Then
+ toolAvgDev = FormatNumber(CDbl(rsTools("avg_deviation")), 4)
+ Else
+ toolAvgDev = "-"
+ End If
+ If Not IsNull(rsTools("max_deviation")) Then
+ toolMaxDev = FormatNumber(CDbl(rsTools("max_deviation")), 4)
+ Else
+ toolMaxDev = "-"
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsTools("toolnumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(Left(rsTools("description") & "", 30)) & " | ")
+ Response.Write("" & rsTools("measurements") & " | ")
+ Response.Write("" & toolAvgDev & " | ")
+ Response.Write("" & toolMaxDev & " | ")
+ Response.Write("" & toolStatus & " | ")
+ Response.Write("
")
+ rsTools.MoveNext
+ Loop
+End If
+rsTools.Close
+Set rsTools = Nothing
+%>
+
+
+
+<%
+' Check for recent OOT events
+Dim rsOOT, ootEventCount
+strSQL2 = "SELECT COUNT(*) as cnt FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ? AND t.oot = 1 AND t.eventtime >= DATE_SUB(NOW(), INTERVAL 7 DAY)"
+Set rsOOT = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & ""))
+ootEventCount = 0
+If Not rsOOT.EOF Then ootEventCount = CLng(rsOOT("cnt") & "0")
+rsOOT.Close
+Set rsOOT = Nothing
+
+If ootEventCount > 0 Then
+%>
+
+
Recent Out-of-Tolerance Events (7 days)
+
+
+
+
+ | Time |
+ Tool # |
+ Description |
+ Actual |
+ Min/Max |
+ Deviation |
+
+
+
+<%
+Dim rsOOTEvents
+strSQL2 = "SELECT t.eventtime, t.toolnumber, t.description, " & _
+ "t.actualval, t.minval, t.maxval, t.deviation " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ "WHERE s.machinenumber = ? AND t.oot = 1 AND t.eventtime >= DATE_SUB(NOW(), INTERVAL 7 DAY) " & _
+ "ORDER BY t.eventtime DESC LIMIT 10"
+Set rsOOTEvents = ExecuteParameterizedQuery(objConn, strSQL2, Array(rs("machinenumber") & ""))
+Do While Not rsOOTEvents.EOF
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsOOTEvents("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsOOTEvents("toolnumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(Left(rsOOTEvents("description") & "", 25)) & " | ")
+ Response.Write("" & FormatNumber(CDbl(rsOOTEvents("actualval") & "0"), 4) & " | ")
+ Response.Write("" & FormatNumber(CDbl(rsOOTEvents("minval") & "0"), 4) & " / " & FormatNumber(CDbl(rsOOTEvents("maxval") & "0"), 4) & " | ")
+ Response.Write("" & FormatNumber(CDbl(rsOOTEvents("deviation") & "0"), 4) & " | ")
+ Response.Write("
")
+ rsOOTEvents.MoveNext
+Loop
+rsOOTEvents.Close
+Set rsOOTEvents = Nothing
+%>
+
+
+
+<%
+End If ' ootEventCount > 0
+Else ' toolMeasurements = 0
+%>
+
+ No tool measurement data available for this machine.
+
+<%
+End If ' toolMeasurements > 0
+%>
+
+
+
+
<% End If %>
@@ -1024,7 +1388,7 @@ End If
$('.location-link').on('mouseenter', function(e) {
var $link = $(this);
var machineId = $link.data('machineid');
- var locationName = $link.text().trim();
+ var locationName = $link.data('name') || $link.text().trim();
var mouseEvent = e;
if (hoverTimer) {
@@ -1043,6 +1407,15 @@ End If
}
});
+ // Also handle click for location links (useful for touch devices)
+ $('.location-link').on('click', function(e) {
+ e.preventDefault();
+ var $link = $(this);
+ var machineId = $link.data('machineid');
+ var locationName = $link.data('name') || $link.text().trim();
+ showLocationPopup(machineId, locationName, e);
+ });
+
$popup.on('mouseenter', function() {});
$popup.on('mouseleave', function() {
hideLocationPopup();
diff --git a/displayudc.asp b/displayudc.asp
new file mode 100644
index 0000000..cd46c56
--- /dev/null
+++ b/displayudc.asp
@@ -0,0 +1,2173 @@
+<%@ Language=VBScript %>
+<%
+Option Explicit
+Response.Expires = -1
+Response.ExpiresAbsolute = Now() - 1
+Response.AddHeader "pragma", "no-cache"
+Response.AddHeader "cache-control", "private, no-cache, must-revalidate"
+'=============================================================================
+' FILE: displayudc.asp
+' PURPOSE: UDC (Universal Data Collector) Management Dashboard
+' SECURITY: Parameterized queries, HTML encoding, input validation
+' CREATED: 2025-12-12
+'=============================================================================
+Dim theme, strSQL, rs, objConn
+%>
+
+
+
+
+
+ UDC Dashboard - ShopDB
+
+
+<%
+ theme = Request.Cookies("theme")
+ If theme = "" Then theme = "bg-theme1"
+
+ ' Get filter parameters
+ Dim filterMachine, filterBadge, filterPart, filterStart, filterEnd, periodFilter, filterBU
+ filterMachine = Trim(Request.QueryString("machine") & "")
+ filterBadge = Trim(Request.QueryString("badge") & "")
+ filterPart = Trim(Request.QueryString("part") & "")
+ filterStart = Trim(Request.QueryString("startdate") & "")
+ filterEnd = Trim(Request.QueryString("enddate") & "")
+ periodFilter = Trim(Request.QueryString("period") & "")
+ filterBU = Trim(Request.QueryString("bu") & "")
+
+ ' Tab persistence
+ Dim activeTab
+ activeTab = Trim(Request.QueryString("tab") & "")
+ If activeTab = "" Then activeTab = "dashboard"
+
+ ' Shift-span filter for manual response times
+ Dim excludeShiftSpan, shiftFilter
+ excludeShiftSpan = (Request.QueryString("excludeshift") = "1")
+ shiftFilter = ""
+ If excludeShiftSpan Then
+ shiftFilter = " AND mr.responseseconds < 1800"
+ End If
+
+ ' Default date range: last 30 days
+ If filterStart = "" Then filterStart = Year(DateAdd("d", -30, Date())) & "-" & Right("0" & Month(DateAdd("d", -30, Date())), 2) & "-" & Right("0" & Day(DateAdd("d", -30, Date())), 2)
+ If filterEnd = "" Then filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
+
+ ' Period shortcuts
+ Dim periodLabel
+ If periodFilter = "today" Then
+ filterStart = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
+ filterEnd = filterStart
+ periodLabel = "Today"
+ ElseIf periodFilter = "week" Then
+ filterStart = Year(DateAdd("d", -7, Date())) & "-" & Right("0" & Month(DateAdd("d", -7, Date())), 2) & "-" & Right("0" & Day(DateAdd("d", -7, Date())), 2)
+ filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
+ periodLabel = "This Week"
+ ElseIf periodFilter = "month" Then
+ filterStart = Year(DateAdd("d", -30, Date())) & "-" & Right("0" & Month(DateAdd("d", -30, Date())), 2) & "-" & Right("0" & Day(DateAdd("d", -30, Date())), 2)
+ filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
+ periodLabel = "This Month"
+ Else
+ periodLabel = "Custom Range"
+ End If
+%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<%
+' Build WHERE clause for filters
+Dim whereClause
+whereClause = " WHERE p.programstart >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND p.programstart <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+
+If filterMachine <> "" Then
+ whereClause = whereClause & " AND s.machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ whereClause = whereClause & " AND s.machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+If filterBadge <> "" Then
+ whereClause = whereClause & " AND p.badgenumber = '" & Replace(filterBadge, "'", "''") & "'"
+End If
+If filterPart <> "" Then
+ whereClause = whereClause & " AND p.partnumber LIKE '%" & Replace(filterPart, "'", "''") & "%'"
+End If
+
+' Get summary statistics
+Dim rsSummary, totalParts, totalOOT, partsWithOOT, avgCycleTime, avgManualTime, ootRate, strSQL2, ootCardClass
+strSQL2 = "SELECT COUNT(*) as totalparts, " & _
+ "SUM(ootcount) as totaloot, " & _
+ "SUM(CASE WHEN ootcount > 0 THEN 1 ELSE 0 END) as partswithoot, " & _
+ "AVG(cycletime) as avgcycle, " & _
+ "SUM(manualcount) as totalmanual " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & whereClause
+
+Set rsSummary = objConn.Execute(strSQL2)
+If Not rsSummary.EOF Then
+ If IsNull(rsSummary("totalparts")) Then totalParts = 0 Else totalParts = CLng(rsSummary("totalparts"))
+ If IsNull(rsSummary("totaloot")) Then totalOOT = 0 Else totalOOT = CLng(rsSummary("totaloot"))
+ If IsNull(rsSummary("partswithoot")) Then partsWithOOT = 0 Else partsWithOOT = CLng(rsSummary("partswithoot"))
+ If Not IsNull(rsSummary("avgcycle")) Then
+ avgCycleTime = FormatNumber(CDbl(rsSummary("avgcycle")) / 60, 1)
+ Else
+ avgCycleTime = "0"
+ End If
+ If totalParts > 0 Then
+ ootRate = FormatNumber(CDbl(partsWithOOT) / CDbl(totalParts) * 100, 1)
+ Else
+ ootRate = "0"
+ End If
+Else
+ totalParts = 0
+ totalOOT = 0
+ partsWithOOT = 0
+ avgCycleTime = "0"
+ ootRate = "0"
+End If
+rsSummary.Close
+Set rsSummary = Nothing
+
+' Get avg manual response time
+Dim rsManual, avgManualResp
+strSQL2 = "SELECT AVG(mr.responseseconds) as avgresponse " & _
+ "FROM udcmanualrequests mr " & _
+ "JOIN udcparts p ON mr.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & whereClause & shiftFilter
+Set rsManual = objConn.Execute(strSQL2)
+If Not rsManual.EOF And Not IsNull(rsManual("avgresponse")) Then
+ avgManualResp = FormatNumber(CDbl(rsManual("avgresponse")), 0)
+Else
+ avgManualResp = "0"
+End If
+rsManual.Close
+Set rsManual = Nothing
+
+%>
+
+
+
+
+
+
+
+
+
<%=totalParts%>
+ Total Parts Produced
+
+
+
+
+
+
+
+
+
+
+
<%=avgCycleTime%>m
+ Avg Cycle Time
+
+
+
+
+
+
+ <%
+ If CDbl(ootRate) > 5 Then
+ ootCardClass = "bg-danger"
+ ElseIf CDbl(ootRate) > 0 Then
+ ootCardClass = "bg-warning"
+ Else
+ ootCardClass = "bg-success"
+ End If
+ %>
+
+
+
+
+
<%=ootRate%>%
+ Parts with OOT (<%=partsWithOOT%> of <%=totalParts%>)
+
+
+
+
+
+
+
+
+
+
+
<%=avgManualResp%>s
+ Avg Manual Response
+
+
+
+
+
+
+
+<%
+' ============================================================================
+' DASHBOARD CHARTS DATA QUERIES
+' ============================================================================
+
+' Chart 1: Production Trend (daily parts for date range)
+Dim rsProductionTrend, prodLabels, prodData, prodDate
+prodLabels = ""
+prodData = ""
+strSQL2 = "SELECT DATE_FORMAT(DATE(p.programstart), '%m/%d') as day_label, COUNT(*) as parts " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " GROUP BY DATE(p.programstart) ORDER BY DATE(p.programstart) ASC"
+Set rsProductionTrend = objConn.Execute(strSQL2)
+Do While Not rsProductionTrend.EOF
+ prodDate = rsProductionTrend("day_label") & ""
+ If prodLabels <> "" Then prodLabels = prodLabels & ","
+ If prodData <> "" Then prodData = prodData & ","
+ prodLabels = prodLabels & """" & prodDate & """"
+ prodData = prodData & rsProductionTrend("parts")
+ rsProductionTrend.MoveNext
+Loop
+rsProductionTrend.Close
+Set rsProductionTrend = Nothing
+If prodLabels = "" Then prodLabels = """No Data"""
+If prodData = "" Then prodData = "0"
+
+' Chart 2: OOT Rate Trend (daily OOT rate for date range)
+Dim rsOOTTrend, ootLabels, ootRateData, ootCountData, ootDay, dayRate
+ootLabels = ""
+ootRateData = ""
+ootCountData = ""
+strSQL2 = "SELECT DATE_FORMAT(DATE(p.programstart), '%m/%d') as day_label, " & _
+ "SUM(p.ootcount) as oot_count, COUNT(*) as total_parts, " & _
+ "ROUND(SUM(p.ootcount)*100.0/COUNT(*), 1) as oot_rate " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " GROUP BY DATE(p.programstart) ORDER BY DATE(p.programstart) ASC"
+Set rsOOTTrend = objConn.Execute(strSQL2)
+Do While Not rsOOTTrend.EOF
+ ootDay = rsOOTTrend("day_label") & ""
+ If ootLabels <> "" Then ootLabels = ootLabels & ","
+ If ootRateData <> "" Then ootRateData = ootRateData & ","
+ If ootCountData <> "" Then ootCountData = ootCountData & ","
+ ootLabels = ootLabels & """" & ootDay & """"
+ If IsNull(rsOOTTrend("oot_rate")) Then
+ dayRate = "0"
+ Else
+ dayRate = rsOOTTrend("oot_rate") & ""
+ End If
+ ootRateData = ootRateData & dayRate
+ ootCountData = ootCountData & (rsOOTTrend("oot_count") & "0")
+ rsOOTTrend.MoveNext
+Loop
+rsOOTTrend.Close
+Set rsOOTTrend = Nothing
+If ootLabels = "" Then ootLabels = """No Data"""
+If ootRateData = "" Then ootRateData = "0"
+If ootCountData = "" Then ootCountData = "0"
+
+' Chart 3: Machine Utilization (top 10 by runtime hours)
+Dim rsMachineUtil, machLabels, machData, machHours
+machLabels = ""
+machData = ""
+strSQL2 = "SELECT s.machinenumber, ROUND(SUM(p.cycletime)/3600, 1) as runtime_hours " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.cycletime IS NOT NULL AND p.cycletime > 0 " & _
+ "GROUP BY s.machinenumber ORDER BY runtime_hours DESC LIMIT 10"
+Set rsMachineUtil = objConn.Execute(strSQL2)
+Do While Not rsMachineUtil.EOF
+ If machLabels <> "" Then machLabels = machLabels & ","
+ If machData <> "" Then machData = machData & ","
+ machLabels = machLabels & """" & (rsMachineUtil("machinenumber") & "") & """"
+ If IsNull(rsMachineUtil("runtime_hours")) Then
+ machHours = "0"
+ Else
+ machHours = rsMachineUtil("runtime_hours") & ""
+ End If
+ machData = machData & machHours
+ rsMachineUtil.MoveNext
+Loop
+rsMachineUtil.Close
+Set rsMachineUtil = Nothing
+If machLabels = "" Then machLabels = """No Data"""
+If machData = "" Then machData = "0"
+
+' Chart 4: Top Operators (top 10 by parts produced)
+Dim rsTopOps, opLabels, opData
+opLabels = ""
+opData = ""
+strSQL2 = "SELECT p.badgenumber, COUNT(*) as parts_count " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.badgenumber IS NOT NULL AND p.badgenumber != '' " & _
+ "GROUP BY p.badgenumber ORDER BY parts_count DESC LIMIT 10"
+Set rsTopOps = objConn.Execute(strSQL2)
+Do While Not rsTopOps.EOF
+ If opLabels <> "" Then opLabels = opLabels & ","
+ If opData <> "" Then opData = opData & ","
+ opLabels = opLabels & """" & (rsTopOps("badgenumber") & "") & """"
+ opData = opData & rsTopOps("parts_count")
+ rsTopOps.MoveNext
+Loop
+rsTopOps.Close
+Set rsTopOps = Nothing
+If opLabels = "" Then opLabels = """No Data"""
+If opData = "" Then opData = "0"
+%>
+
+
+
+
+
+
+
+
+
+
+
" id="dashboard">
+
UDC Performance Dashboard
+
+
+
+
+
+
+
+
+
+
" id="liveactivity">
+
Active Machines Live
+
Machines currently running jobs. Data refreshes when page loads.
+<%
+' Get active sessions with optional machine/BU filter
+Dim rsActive, activeCount, activeWhereClause
+activeWhereClause = ""
+If filterMachine <> "" Then
+ activeWhereClause = " WHERE a.machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+ElseIf filterBU <> "" Then
+ activeWhereClause = " WHERE a.machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+strSQL2 = "SELECT a.machinenumber, a.partnumber, a.badgenumber, a.partsrun, a.lastupdate, a.sessionstart, " & _
+ "TIMESTAMPDIFF(MINUTE, a.sessionstart, NOW()) as runtime_minutes " & _
+ "FROM udcactivesessions a" & activeWhereClause & " ORDER BY a.lastupdate DESC"
+Set rsActive = objConn.Execute(strSQL2)
+activeCount = 0
+
+If rsActive.EOF Then
+%>
+
+ No active jobs detected
+
+<%
+Else
+%>
+
+
+
+
+ | Machine |
+ Part Number |
+ Operator Badge |
+ Parts Run |
+ Runtime |
+ Session Start |
+ Last Activity |
+
+
+
+<%
+ Dim runtimeMinutes, runtimeDisplay
+ Do While Not rsActive.EOF
+ activeCount = activeCount + 1
+ runtimeMinutes = rsActive("runtime_minutes")
+ If IsNull(runtimeMinutes) Or runtimeMinutes = "" Then
+ runtimeDisplay = "-"
+ ElseIf CLng(runtimeMinutes) >= 60 Then
+ runtimeDisplay = Int(CLng(runtimeMinutes) / 60) & "h " & (CLng(runtimeMinutes) Mod 60) & "m"
+ Else
+ runtimeDisplay = CLng(runtimeMinutes) & "m"
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsActive("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActive("partnumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActive("badgenumber") & "") & " | ")
+ Response.Write("" & rsActive("partsrun") & " | ")
+ Response.Write("" & runtimeDisplay & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActive("sessionstart") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsActive("lastupdate") & "") & " | ")
+ Response.Write("
")
+ rsActive.MoveNext
+ Loop
+%>
+
+
+
+
<%=activeCount%> machine(s) currently active
+<%
+End If
+rsActive.Close
+Set rsActive = Nothing
+%>
+
+
+
+
" id="operators">
+
Operator Performance Leaderboard
+
+
+
+
+ | Badge # |
+ Parts Run |
+ Avg Cycle (min) |
+ Avg Manual Response (sec) |
+ Last Active |
+
+
+
+<%
+' Get operator stats
+Dim rsOperators, opCycle, opManual, opRowNum, opRowStyle
+strSQL2 = "SELECT p.badgenumber, COUNT(*) as partsrun, " & _
+ "AVG(p.cycletime) as avgcycle, " & _
+ "MAX(p.programend) as lastactive, " & _
+ "(SELECT AVG(mr.responseseconds) FROM udcmanualrequests mr " & _
+ " JOIN udcparts p2 ON mr.partrunid = p2.partrunid WHERE p2.badgenumber = p.badgenumber) as avgmanual " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.badgenumber IS NOT NULL AND p.badgenumber != '' " & _
+ "GROUP BY p.badgenumber ORDER BY partsrun DESC, p.badgenumber ASC"
+Set rsOperators = objConn.Execute(strSQL2)
+opRowNum = 0
+If rsOperators.EOF Then
+ Response.Write("| No operator data found |
")
+Else
+ Do While Not rsOperators.EOF
+ opRowNum = opRowNum + 1
+ If Not IsNull(rsOperators("avgcycle")) Then
+ opCycle = FormatNumber(CDbl(rsOperators("avgcycle")) / 60, 1)
+ Else
+ opCycle = "-"
+ End If
+ If Not IsNull(rsOperators("avgmanual")) Then
+ opManual = FormatNumber(CDbl(rsOperators("avgmanual")), 0)
+ Else
+ opManual = "-"
+ End If
+
+ ' Highlight top 3 performers
+ opRowStyle = ""
+ If opRowNum = 1 Then
+ opRowStyle = "background-color:#28a745; color:#fff;"
+ ElseIf opRowNum = 2 Then
+ opRowStyle = "background-color:#20c997; color:#fff;"
+ ElseIf opRowNum = 3 Then
+ opRowStyle = "background-color:#17a2b8; color:#fff;"
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsOperators("badgenumber") & "") & " | ")
+ Response.Write("" & rsOperators("partsrun") & " | ")
+ Response.Write("" & opCycle & " | ")
+ Response.Write("" & opManual & " | ")
+ Response.Write("" & Server.HTMLEncode(rsOperators("lastactive") & "") & " | ")
+ Response.Write("
")
+ rsOperators.MoveNext
+ Loop
+End If
+rsOperators.Close
+Set rsOperators = Nothing
+%>
+
+
+
+
+
+
+
" id="machines">
+
Machine Performance Comparison
+
+
+
+
+ | Machine # |
+ Parts Run |
+ Avg Cycle (min) |
+ Avg Changeover (min) |
+ Parts with OOT |
+ OOT Rate |
+ Last Run |
+
+
+
+<%
+' Get machine stats
+Dim rsMachStats, machCycle, machChange, machOOTRate, machOOTBadge, machPartsWithOOT
+strSQL2 = "SELECT s.machinenumber, COUNT(*) as partsrun, " & _
+ "AVG(p.cycletime) as avgcycle, " & _
+ "AVG(p.changeover) as avgchangeover, " & _
+ "SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END) as partswithoot, " & _
+ "MAX(p.programend) as lastrun " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " GROUP BY s.machinenumber ORDER BY partsrun DESC, s.machinenumber ASC"
+Set rsMachStats = objConn.Execute(strSQL2)
+If rsMachStats.EOF Then
+ Response.Write("| No machine data found |
")
+Else
+ Do While Not rsMachStats.EOF
+ If Not IsNull(rsMachStats("avgcycle")) Then
+ machCycle = FormatNumber(CDbl(rsMachStats("avgcycle")) / 60, 1)
+ Else
+ machCycle = "-"
+ End If
+ If Not IsNull(rsMachStats("avgchangeover")) Then
+ machChange = FormatNumber(CDbl(rsMachStats("avgchangeover")) / 60, 1)
+ Else
+ machChange = "-"
+ End If
+ machPartsWithOOT = CLng("0" & rsMachStats("partswithoot"))
+ If CLng("0" & rsMachStats("partsrun")) > 0 Then
+ machOOTRate = FormatNumber(CDbl(machPartsWithOOT) / CDbl(rsMachStats("partsrun")) * 100, 2)
+ Else
+ machOOTRate = "0"
+ End If
+ If CDbl(machOOTRate) > 5 Then
+ machOOTBadge = "" & machOOTRate & "%"
+ ElseIf CDbl(machOOTRate) > 0 Then
+ machOOTBadge = "" & machOOTRate & "%"
+ Else
+ machOOTBadge = "" & machOOTRate & "%"
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsMachStats("machinenumber") & "") & " | ")
+ Response.Write("" & rsMachStats("partsrun") & " | ")
+ Response.Write("" & machCycle & " | ")
+ Response.Write("" & machChange & " | ")
+ Response.Write("" & machPartsWithOOT & " | ")
+ Response.Write("" & machOOTBadge & " | ")
+ Response.Write("" & Server.HTMLEncode(rsMachStats("lastrun") & "") & " | ")
+ Response.Write("
")
+ rsMachStats.MoveNext
+ Loop
+End If
+rsMachStats.Close
+Set rsMachStats = Nothing
+%>
+
+
+
+
+
+
+
" id="parts">
+
Part Number Analysis
+
+
+
+
+ | Part # |
+ Count |
+ Avg Cycle (min) |
+ Parts with OOT |
+ OOT Rate |
+
+
+
+<%
+' Get part stats
+Dim rsPartStats, partCycle, partOOTRate, partOOTBadge, partPartsWithOOT
+strSQL2 = "SELECT p.partnumber, COUNT(*) as cnt, " & _
+ "AVG(p.cycletime) as avgcycle, " & _
+ "SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END) as partswithoot " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.partnumber IS NOT NULL AND p.partnumber != '' " & _
+ "GROUP BY p.partnumber ORDER BY partswithoot DESC, cnt DESC, p.partnumber ASC LIMIT 50"
+Set rsPartStats = objConn.Execute(strSQL2)
+If rsPartStats.EOF Then
+ Response.Write("| No part data found |
")
+Else
+ Do While Not rsPartStats.EOF
+ If Not IsNull(rsPartStats("avgcycle")) Then
+ partCycle = FormatNumber(CDbl(rsPartStats("avgcycle")) / 60, 1)
+ Else
+ partCycle = "-"
+ End If
+ partPartsWithOOT = CLng("0" & rsPartStats("partswithoot"))
+ If CLng("0" & rsPartStats("cnt")) > 0 Then
+ partOOTRate = FormatNumber(CDbl(partPartsWithOOT) / CDbl(rsPartStats("cnt")) * 100, 2)
+ Else
+ partOOTRate = "0"
+ End If
+ If CDbl(partOOTRate) > 5 Then
+ partOOTBadge = "" & partOOTRate & "%"
+ ElseIf CDbl(partOOTRate) > 0 Then
+ partOOTBadge = "" & partOOTRate & "%"
+ Else
+ partOOTBadge = "0%"
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsPartStats("partnumber") & "") & " | ")
+ Response.Write("" & rsPartStats("cnt") & " | ")
+ Response.Write("" & partCycle & " | ")
+ Response.Write("" & partPartsWithOOT & " | ")
+ Response.Write("" & partOOTBadge & " | ")
+ Response.Write("
")
+ rsPartStats.MoveNext
+ Loop
+End If
+rsPartStats.Close
+Set rsPartStats = Nothing
+%>
+
+
+
+
+
+
+
" id="quality">
+
Out-of-Tolerance Analysis
+
+
+
OOT by Machine
+
+
+
+
+ | Machine |
+ Parts with OOT |
+ Parts Run |
+ OOT Rate |
+ Bar |
+
+
+
+<%
+' Get OOT by Machine
+Dim rsOOTMach, maxOOT, ootMachRate, barWidth, ootMachParts
+maxOOT = 1
+strSQL2 = "SELECT s.machinenumber, SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END) as partswithoot, COUNT(*) as partsrun " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " GROUP BY s.machinenumber ORDER BY partswithoot DESC, s.machinenumber ASC LIMIT 10"
+Set rsOOTMach = objConn.Execute(strSQL2)
+If rsOOTMach.EOF Then
+ Response.Write("| No OOT data found |
")
+Else
+ ' Find max for bar scaling
+ Do While Not rsOOTMach.EOF
+ If CLng("0" & rsOOTMach("partswithoot")) > maxOOT Then maxOOT = CLng("0" & rsOOTMach("partswithoot"))
+ rsOOTMach.MoveNext
+ Loop
+ rsOOTMach.Close
+ Set rsOOTMach = objConn.Execute(strSQL2)
+
+ Do While Not rsOOTMach.EOF
+ ootMachParts = CLng("0" & rsOOTMach("partswithoot"))
+ If CLng("0" & rsOOTMach("partsrun")) > 0 Then
+ ootMachRate = FormatNumber(CDbl(ootMachParts) / CDbl(rsOOTMach("partsrun")) * 100, 2)
+ Else
+ ootMachRate = "0"
+ End If
+ barWidth = Int((ootMachParts / maxOOT) * 100)
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsOOTMach("machinenumber") & "") & " | ")
+ Response.Write("" & ootMachParts & " | ")
+ Response.Write("" & rsOOTMach("partsrun") & " | ")
+ Response.Write("" & ootMachRate & "% | ")
+ Response.Write(" | ")
+ Response.Write("
")
+ rsOOTMach.MoveNext
+ Loop
+End If
+rsOOTMach.Close
+Set rsOOTMach = Nothing
+%>
+
+
+
+
+
+
Recent OOT Measurements
+
+
+
+
+ | Time |
+ Machine |
+ Part # |
+ Dimension |
+ Min |
+ Actual |
+ Max |
+
+
+
+<%
+' Get recent OOT measurements
+Dim rsOOT
+strSQL2 = "SELECT m.eventtime, s.machinenumber, p.partnumber, m.dimid, m.description, " & _
+ "m.minval, m.actualval, m.maxval " & _
+ "FROM udcmeasurements m " & _
+ "JOIN udcparts p ON m.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND m.oot = 1 " & _
+ "ORDER BY m.eventtime DESC LIMIT 50"
+Set rsOOT = objConn.Execute(strSQL2)
+If rsOOT.EOF Then
+ Response.Write("| No OOT measurements found |
")
+Else
+ Do While Not rsOOT.EOF
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsOOT("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsOOT("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsOOT("partnumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsOOT("dimid") & "") & " - " & Server.HTMLEncode(rsOOT("description") & "") & " | ")
+ Response.Write("" & rsOOT("minval") & " | ")
+ Response.Write("" & rsOOT("actualval") & " | ")
+ Response.Write("" & rsOOT("maxval") & " | ")
+ Response.Write("
")
+ rsOOT.MoveNext
+ Loop
+End If
+rsOOT.Close
+Set rsOOT = Nothing
+%>
+
+
+
+
+
+
Best Performing Machines (Lowest OOT Rates)
+
+
+
+
+ | Machine |
+ Parts Run |
+ OOT Count |
+ OOT Rate |
+ Quality Bar |
+
+
+
+<%
+' Get best performing machines (lowest OOT rate, min 10 parts)
+Dim rsBestMach, bestRate, bestStyle, qualityWidth, bestPartsWithOOT
+strSQL2 = "SELECT s.machinenumber, COUNT(*) as partsrun, " & _
+ "SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END) as partswithoot, " & _
+ "ROUND(SUM(CASE WHEN p.ootcount > 0 THEN 1 ELSE 0 END)/COUNT(*)*100, 2) as ootrate " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " GROUP BY s.machinenumber HAVING COUNT(*) >= 10 ORDER BY ootrate ASC, partsrun DESC, s.machinenumber ASC LIMIT 10"
+Set rsBestMach = objConn.Execute(strSQL2)
+If rsBestMach.EOF Then
+ Response.Write("| No machine data found (min 10 parts required) |
")
+Else
+ Do While Not rsBestMach.EOF
+ bestPartsWithOOT = CLng("0" & rsBestMach("partswithoot"))
+ bestRate = CDbl("0" & rsBestMach("ootrate"))
+ qualityWidth = 100 - Int(bestRate)
+ If qualityWidth < 0 Then qualityWidth = 0
+ If qualityWidth > 100 Then qualityWidth = 100
+
+ If bestRate = 0 Then
+ bestStyle = "background-color:#28a745; color:#fff;"
+ ElseIf bestRate < 5 Then
+ bestStyle = "background-color:#20c997; color:#fff;"
+ Else
+ bestStyle = ""
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsBestMach("machinenumber") & "") & " | ")
+ Response.Write("" & rsBestMach("partsrun") & " | ")
+ Response.Write("" & bestPartsWithOOT & " | ")
+ Response.Write("" & bestRate & "% | ")
+ Response.Write(" | ")
+ Response.Write("
")
+ rsBestMach.MoveNext
+ Loop
+End If
+rsBestMach.Close
+Set rsBestMach = Nothing
+%>
+
+
+
+
+
+
+
" id="timing">
+
Timing Analysis
+
+
+
Manual Response Time by Operator
+
+
+
+
+ | Badge # |
+ Requests |
+ Avg Response (sec) |
+ Max Response (sec) |
+
+
+
+<%
+' Get manual response time by operator
+Dim rsManualOp, manAvg, manMax
+strSQL2 = "SELECT p.badgenumber, COUNT(*) as requests, " & _
+ "AVG(mr.responseseconds) as avgresponse, " & _
+ "MAX(mr.responseseconds) as maxresponse " & _
+ "FROM udcmanualrequests mr " & _
+ "JOIN udcparts p ON mr.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.badgenumber IS NOT NULL AND p.badgenumber != ''" & shiftFilter & _
+ " GROUP BY p.badgenumber ORDER BY avgresponse ASC, p.badgenumber ASC"
+Set rsManualOp = objConn.Execute(strSQL2)
+If rsManualOp.EOF Then
+ Response.Write("| No manual request data found |
")
+Else
+ Do While Not rsManualOp.EOF
+ If Not IsNull(rsManualOp("avgresponse")) Then
+ manAvg = FormatNumber(CDbl(rsManualOp("avgresponse")), 0)
+ Else
+ manAvg = "-"
+ End If
+ manMax = CLng("0" & rsManualOp("maxresponse"))
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsManualOp("badgenumber") & "") & " | ")
+ Response.Write("" & rsManualOp("requests") & " | ")
+ Response.Write("" & manAvg & " | ")
+ Response.Write("" & manMax & " | ")
+ Response.Write("
")
+ rsManualOp.MoveNext
+ Loop
+End If
+rsManualOp.Close
+Set rsManualOp = Nothing
+%>
+
+
+
+
+
+
Slowest Manual Responses
+
+
+
+
+ | Request Time |
+ Machine |
+ Badge |
+ Description |
+ Response Time (sec) |
+
+
+
+<%
+' Get slowest manual responses
+Dim rsSlow, rowStyle
+strSQL2 = "SELECT mr.requesttime, s.machinenumber, p.badgenumber, mr.description, mr.responseseconds " & _
+ "FROM udcmanualrequests mr " & _
+ "JOIN udcparts p ON mr.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & shiftFilter & _
+ " ORDER BY mr.responseseconds DESC LIMIT 25"
+Set rsSlow = objConn.Execute(strSQL2)
+If rsSlow.EOF Then
+ Response.Write("| No manual requests found |
")
+Else
+ Do While Not rsSlow.EOF
+ If CLng("0" & rsSlow("responseseconds")) > 300 Then
+ rowStyle = "background-color:#dc3545; color:#fff;"
+ ElseIf CLng("0" & rsSlow("responseseconds")) > 120 Then
+ rowStyle = "background-color:#ffc107; color:#333;"
+ Else
+ rowStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsSlow("requesttime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsSlow("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsSlow("badgenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsSlow("description") & "") & " | ")
+ Response.Write("" & rsSlow("responseseconds") & " | ")
+ Response.Write("
")
+ rsSlow.MoveNext
+ Loop
+End If
+rsSlow.Close
+Set rsSlow = Nothing
+%>
+
+
+
+
+
+
Fastest Responses (Top Performers)
+
+
+
+
+ | Request Time |
+ Machine |
+ Badge |
+ Description |
+ Response Time (sec) |
+
+
+
+<%
+' Get fastest manual responses
+Dim rsFast, fastStyle
+strSQL2 = "SELECT mr.requesttime, s.machinenumber, p.badgenumber, mr.description, mr.responseseconds " & _
+ "FROM udcmanualrequests mr " & _
+ "JOIN udcparts p ON mr.partrunid = p.partrunid " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & shiftFilter & _
+ " AND mr.responseseconds > 0 ORDER BY mr.responseseconds ASC LIMIT 25"
+Set rsFast = objConn.Execute(strSQL2)
+If rsFast.EOF Then
+ Response.Write("| No manual requests found |
")
+Else
+ Do While Not rsFast.EOF
+ If CLng("0" & rsFast("responseseconds")) < 30 Then
+ fastStyle = "background-color:#28a745; color:#fff;"
+ ElseIf CLng("0" & rsFast("responseseconds")) < 60 Then
+ fastStyle = "background-color:#20c997; color:#fff;"
+ Else
+ fastStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsFast("requesttime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsFast("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsFast("badgenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsFast("description") & "") & " | ")
+ Response.Write("" & rsFast("responseseconds") & " | ")
+ Response.Write("
")
+ rsFast.MoveNext
+ Loop
+End If
+rsFast.Close
+Set rsFast = Nothing
+%>
+
+
+
+
+
+
+
" id="activitylog">
+
Activity Log
+
Badge changes and item crossing violations recorded during part runs.
+
+
+
Item Crossing Violations
+
When operators modify item crossing values during a program run.
+
+
+
+
+ | Time |
+ Machine |
+ Badge |
+ Crossing |
+ Item# |
+ Previous |
+ Current |
+ Change |
+
+
+
+<%
+' Get recent violations
+Dim rsViolations, violWhereClause, violPrev, violCurr, violChange, violStyle
+violWhereClause = " WHERE eventtime >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND eventtime <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+If filterMachine <> "" Then
+ violWhereClause = violWhereClause & " AND machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ violWhereClause = violWhereClause & " AND machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+If filterBadge <> "" Then
+ violWhereClause = violWhereClause & " AND badgenumber = '" & Replace(filterBadge, "'", "''") & "'"
+End If
+
+strSQL2 = "SELECT eventtime, machinenumber, badgenumber, crossingdesc, itemno, previousval, currentval " & _
+ "FROM udcviolations " & violWhereClause & _
+ " ORDER BY eventtime DESC LIMIT 50"
+Set rsViolations = objConn.Execute(strSQL2)
+If rsViolations.EOF Then
+ Response.Write("| No item violations found in date range |
")
+Else
+ Do While Not rsViolations.EOF
+ violPrev = CDbl("0" & rsViolations("previousval"))
+ violCurr = CDbl("0" & rsViolations("currentval"))
+ violChange = violCurr - violPrev
+
+ ' Color code based on change magnitude
+ If Abs(violChange) > 10 Then
+ violStyle = "background-color:#dc3545; color:#fff;"
+ ElseIf Abs(violChange) > 1 Then
+ violStyle = "background-color:#ffc107; color:#333;"
+ Else
+ violStyle = ""
+ End If
+
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsViolations("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsViolations("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsViolations("badgenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsViolations("crossingdesc") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsViolations("itemno") & "") & " | ")
+ Response.Write("" & FormatNumber(violPrev, 2) & " | ")
+ Response.Write("" & FormatNumber(violCurr, 2) & " | ")
+ If violChange > 0 Then
+ Response.Write("+" & FormatNumber(violChange, 2) & " | ")
+ ElseIf violChange < 0 Then
+ Response.Write("" & FormatNumber(violChange, 2) & " | ")
+ Else
+ Response.Write("0 | ")
+ End If
+ Response.Write("
")
+ rsViolations.MoveNext
+ Loop
+End If
+rsViolations.Close
+Set rsViolations = Nothing
+%>
+
+
+
+
+
+
Violations by Machine
+
+
+
+
+ | Machine |
+ Total Violations |
+ Unique Crossings |
+ Last Violation |
+
+
+
+<%
+' Get violations summary by machine
+Dim rsViolMach, violMachStyle
+strSQL2 = "SELECT machinenumber, COUNT(*) as cnt, COUNT(DISTINCT crossingdesc) as crossings, MAX(eventtime) as lasttime " & _
+ "FROM udcviolations " & violWhereClause & _
+ " GROUP BY machinenumber ORDER BY cnt DESC, machinenumber ASC LIMIT 10"
+Set rsViolMach = objConn.Execute(strSQL2)
+If rsViolMach.EOF Then
+ Response.Write("| No violations found |
")
+Else
+ Do While Not rsViolMach.EOF
+ If CLng("0" & rsViolMach("cnt")) > 100 Then
+ violMachStyle = "background-color:#dc3545; color:#fff;"
+ ElseIf CLng("0" & rsViolMach("cnt")) > 25 Then
+ violMachStyle = "background-color:#ffc107; color:#333;"
+ Else
+ violMachStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsViolMach("machinenumber") & "") & " | ")
+ Response.Write("" & rsViolMach("cnt") & " | ")
+ Response.Write("" & rsViolMach("crossings") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsViolMach("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsViolMach.MoveNext
+ Loop
+End If
+rsViolMach.Close
+Set rsViolMach = Nothing
+%>
+
+
+
+
+
+
Badge Changes
+
Operator badge scans and changes during part runs.
+
+
+
+
+ | Time |
+ Machine |
+ Badge |
+ Details |
+
+
+
+<%
+' Get recent badge changes
+Dim rsBadgeChanges, badgeWhereClause
+badgeWhereClause = " WHERE eventtime >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND eventtime <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+If filterMachine <> "" Then
+ badgeWhereClause = badgeWhereClause & " AND machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ badgeWhereClause = badgeWhereClause & " AND machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+If filterBadge <> "" Then
+ badgeWhereClause = badgeWhereClause & " AND badgenumber = '" & Replace(filterBadge, "'", "''") & "'"
+End If
+
+strSQL2 = "SELECT eventtime, machinenumber, badgenumber, details, description " & _
+ "FROM udcheaderupdates " & badgeWhereClause & _
+ " ORDER BY eventtime DESC LIMIT 50"
+Set rsBadgeChanges = objConn.Execute(strSQL2)
+If rsBadgeChanges.EOF Then
+ Response.Write("| No badge changes found in date range |
")
+Else
+ Do While Not rsBadgeChanges.EOF
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsBadgeChanges("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsBadgeChanges("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsBadgeChanges("badgenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsBadgeChanges("description") & "") & " | ")
+ Response.Write("
")
+ rsBadgeChanges.MoveNext
+ Loop
+End If
+rsBadgeChanges.Close
+Set rsBadgeChanges = Nothing
+%>
+
+
+
+
+
+
Badge Activity by Operator
+
+
+
+
+ | Badge # |
+ Badge Scans |
+ Machines Used |
+ Last Activity |
+
+
+
+<%
+' Get badge activity summary
+Dim rsBadgeSum
+strSQL2 = "SELECT badgenumber, COUNT(*) as cnt, COUNT(DISTINCT machinenumber) as machines, MAX(eventtime) as lasttime " & _
+ "FROM udcheaderupdates " & badgeWhereClause & _
+ " AND badgenumber IS NOT NULL AND badgenumber != '' " & _
+ " GROUP BY badgenumber ORDER BY cnt DESC, badgenumber ASC LIMIT 15"
+Set rsBadgeSum = objConn.Execute(strSQL2)
+If rsBadgeSum.EOF Then
+ Response.Write("| No badge activity found |
")
+Else
+ Do While Not rsBadgeSum.EOF
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsBadgeSum("badgenumber") & "") & " | ")
+ Response.Write("" & rsBadgeSum("cnt") & " | ")
+ Response.Write("" & rsBadgeSum("machines") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsBadgeSum("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsBadgeSum.MoveNext
+ Loop
+End If
+rsBadgeSum.Close
+Set rsBadgeSum = Nothing
+%>
+
+
+
+
+
+
+
" id="toolhealth">
+
Tool Health
+
Tool offset measurements and wear tracking.
+
+
+
Tool Measurements by Machine
+
+
+
+
+ | Machine |
+ Measurements |
+ Unique Tools |
+ OOT Count |
+ Last Measurement |
+
+
+
+<%
+' Get tool data summary by machine
+Dim rsToolMach, toolWhereClause, toolMachStyle
+toolWhereClause = " WHERE t.eventtime >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND t.eventtime <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+If filterMachine <> "" Then
+ toolWhereClause = toolWhereClause & " AND s.machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ toolWhereClause = toolWhereClause & " AND s.machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+
+strSQL2 = "SELECT s.machinenumber, COUNT(*) as cnt, COUNT(DISTINCT t.toolnumber) as tools, " & _
+ "SUM(t.oot) as ootcount, MAX(t.eventtime) as lasttime " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ toolWhereClause & _
+ " GROUP BY s.machinenumber ORDER BY cnt DESC, s.machinenumber ASC LIMIT 15"
+Set rsToolMach = objConn.Execute(strSQL2)
+If rsToolMach.EOF Then
+ Response.Write("| No tool data found in date range |
")
+Else
+ Do While Not rsToolMach.EOF
+ If CLng("0" & rsToolMach("ootcount")) > 0 Then
+ toolMachStyle = "background-color:#ffc107; color:#333;"
+ Else
+ toolMachStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsToolMach("machinenumber") & "") & " | ")
+ Response.Write("" & rsToolMach("cnt") & " | ")
+ Response.Write("" & rsToolMach("tools") & " | ")
+ Response.Write("")
+ If CLng("0" & rsToolMach("ootcount")) > 0 Then
+ Response.Write("" & rsToolMach("ootcount") & "")
+ Else
+ Response.Write("0")
+ End If
+ Response.Write(" | ")
+ Response.Write("" & Server.HTMLEncode(rsToolMach("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsToolMach.MoveNext
+ Loop
+End If
+rsToolMach.Close
+Set rsToolMach = Nothing
+%>
+
+
+
+
+
+<%
+If filterMachine <> "" Then
+%>
+
Most Used Tools on Machine <%=Server.HTMLEncode(filterMachine)%>
+
+
+
+
+ | Tool # |
+ Description |
+ Measurements |
+ Avg Deviation |
+ OOT Count |
+
+
+
+<%
+' Get tool usage by tool number for this specific machine
+Dim rsToolNum, toolNumStyle, avgDev
+strSQL2 = "SELECT t.toolnumber, MAX(t.description) as description, COUNT(*) as cnt, " & _
+ "AVG(ABS(t.deviation)) as avgdev, SUM(t.oot) as ootcount " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ toolWhereClause & _
+ " AND t.toolnumber IS NOT NULL " & _
+ " GROUP BY t.toolnumber ORDER BY cnt DESC, t.toolnumber ASC LIMIT 20"
+Set rsToolNum = objConn.Execute(strSQL2)
+If rsToolNum.EOF Then
+ Response.Write("| No tool data found |
")
+Else
+ Do While Not rsToolNum.EOF
+ If CLng("0" & rsToolNum("ootcount")) > 0 Then
+ toolNumStyle = "background-color:#ffc107; color:#333;"
+ Else
+ toolNumStyle = ""
+ End If
+ If Not IsNull(rsToolNum("avgdev")) Then
+ avgDev = FormatNumber(CDbl(rsToolNum("avgdev")), 4)
+ Else
+ avgDev = "-"
+ End If
+ Response.Write("")
+ Response.Write("| Tool " & rsToolNum("toolnumber") & " | ")
+ Response.Write("" & Server.HTMLEncode(Trim(rsToolNum("description") & "")) & " | ")
+ Response.Write("" & rsToolNum("cnt") & " | ")
+ Response.Write("" & avgDev & " | ")
+ Response.Write("")
+ If CLng("0" & rsToolNum("ootcount")) > 0 Then
+ Response.Write("" & rsToolNum("ootcount") & "")
+ Else
+ Response.Write("0")
+ End If
+ Response.Write(" | ")
+ Response.Write("
")
+ rsToolNum.MoveNext
+ Loop
+End If
+rsToolNum.Close
+Set rsToolNum = Nothing
+%>
+
+
+
+<%
+End If ' filterMachine
+%>
+
+
+
Recent Tool Measurements
+
+
+
+
+ | Time |
+ Machine |
+ Tool # |
+ Description |
+ Min |
+ Actual |
+ Max |
+ Status |
+
+
+
+<%
+' Get recent tool measurements
+Dim rsToolRecent, toolRecentStyle
+strSQL2 = "SELECT t.eventtime, s.machinenumber, t.toolnumber, t.description, " & _
+ "t.minval, t.actualval, t.maxval, t.oot " & _
+ "FROM udctooldata t " & _
+ "JOIN udcsessions s ON t.sessionid = s.sessionid " & _
+ toolWhereClause & _
+ " ORDER BY t.eventtime DESC LIMIT 30"
+Set rsToolRecent = objConn.Execute(strSQL2)
+If rsToolRecent.EOF Then
+ Response.Write("| No tool measurements found |
")
+Else
+ Do While Not rsToolRecent.EOF
+ If CLng("0" & rsToolRecent("oot")) > 0 Then
+ toolRecentStyle = "background-color:#dc3545; color:#fff;"
+ Else
+ toolRecentStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsToolRecent("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsToolRecent("machinenumber") & "") & " | ")
+ Response.Write("Tool " & rsToolRecent("toolnumber") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsToolRecent("description") & "") & " | ")
+ Response.Write("" & rsToolRecent("minval") & " | ")
+ Response.Write("" & rsToolRecent("actualval") & " | ")
+ Response.Write("" & rsToolRecent("maxval") & " | ")
+ If CLng("0" & rsToolRecent("oot")) > 0 Then
+ Response.Write("OOT | ")
+ Else
+ Response.Write("OK | ")
+ End If
+ Response.Write("
")
+ rsToolRecent.MoveNext
+ Loop
+End If
+rsToolRecent.Close
+Set rsToolRecent = Nothing
+%>
+
+
+
+
+
+
+
" id="uptime">
+
Machine Uptime
+
Runtime calculated from actual part cycle times within the selected date range.
+
+
+
+<%
+' Calculate uptime summary
+Dim rsUptimeSummary, totalRuntimeHours, totalMachines, avgUtilization
+strSQL2 = "SELECT COUNT(DISTINCT s.machinenumber) as machines, " & _
+ "ROUND(SUM(p.cycletime)/3600, 1) as total_hours, " & _
+ "ROUND(AVG(p.cycletime)/60, 1) as avg_cycle " & _
+ "FROM udcparts p " & _
+ "JOIN udcsessions s ON p.sessionid = s.sessionid " & _
+ whereClause & _
+ " AND p.cycletime IS NOT NULL AND p.cycletime > 0"
+Set rsUptimeSummary = objConn.Execute(strSQL2)
+If Not rsUptimeSummary.EOF Then
+ totalMachines = CLng("0" & rsUptimeSummary("machines"))
+ If Not IsNull(rsUptimeSummary("total_hours")) Then
+ totalRuntimeHours = FormatNumber(CDbl(rsUptimeSummary("total_hours")), 1)
+ Else
+ totalRuntimeHours = "0"
+ End If
+Else
+ totalMachines = 0
+ totalRuntimeHours = "0"
+End If
+rsUptimeSummary.Close
+Set rsUptimeSummary = Nothing
+%>
+
+
+
+
<%=totalRuntimeHours%>
+ Total Runtime Hours
+
+
+
+
+
+
+
<%=totalMachines%>
+ Active Machines
+
+
+
+
+
+
+
<%=totalParts%>
+ Parts Produced
+
+
+
+
+
+
+
Runtime by Machine
+
+
+
+
+
" id="itdiagnostics">
+
IT Diagnostics
+
+
+
Error Summary by Type
+
+
+
+
+ | Error Type |
+ Count |
+ Machines Affected |
+ Last Occurrence |
+
+
+
+<%
+' Get error summary by type
+Dim rsErrSummary, errWhereClause, errRowStyle
+errWhereClause = " WHERE eventtime >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND eventtime <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+If filterMachine <> "" Then
+ errWhereClause = errWhereClause & " AND machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ errWhereClause = errWhereClause & " AND machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+
+strSQL2 = "SELECT errortype, COUNT(*) as cnt, COUNT(DISTINCT machinenumber) as machines, MAX(eventtime) as lasttime " & _
+ "FROM udcerrors " & errWhereClause & _
+ " GROUP BY errortype ORDER BY cnt DESC, errortype ASC LIMIT 10"
+Set rsErrSummary = objConn.Execute(strSQL2)
+If rsErrSummary.EOF Then
+ Response.Write("| No errors found in date range |
")
+Else
+ Do While Not rsErrSummary.EOF
+ If CLng("0" & rsErrSummary("cnt")) > 50 Then
+ errRowStyle = "background-color:#dc3545; color:#fff;"
+ ElseIf CLng("0" & rsErrSummary("cnt")) > 10 Then
+ errRowStyle = "background-color:#ffc107; color:#333;"
+ Else
+ errRowStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsErrSummary("errortype") & "") & " | ")
+ Response.Write("" & rsErrSummary("cnt") & " | ")
+ Response.Write("" & rsErrSummary("machines") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsErrSummary("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsErrSummary.MoveNext
+ Loop
+End If
+rsErrSummary.Close
+Set rsErrSummary = Nothing
+%>
+
+
+
+
+
+
Errors by Machine
+
+
+
+
+ | Machine |
+ Total Errors |
+ Error Types |
+ Last Error |
+
+
+
+<%
+' Get errors by machine
+Dim rsErrMach, errMachStyle
+strSQL2 = "SELECT machinenumber, COUNT(*) as cnt, COUNT(DISTINCT errortype) as types, MAX(eventtime) as lasttime " & _
+ "FROM udcerrors " & errWhereClause & _
+ " GROUP BY machinenumber ORDER BY cnt DESC, machinenumber ASC LIMIT 10"
+Set rsErrMach = objConn.Execute(strSQL2)
+If rsErrMach.EOF Then
+ Response.Write("| No errors found |
")
+Else
+ Do While Not rsErrMach.EOF
+ If CLng("0" & rsErrMach("cnt")) > 100 Then
+ errMachStyle = "background-color:#dc3545; color:#fff;"
+ ElseIf CLng("0" & rsErrMach("cnt")) > 25 Then
+ errMachStyle = "background-color:#ffc107; color:#333;"
+ Else
+ errMachStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsErrMach("machinenumber") & "") & " | ")
+ Response.Write("" & rsErrMach("cnt") & " | ")
+ Response.Write("" & rsErrMach("types") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsErrMach("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsErrMach.MoveNext
+ Loop
+End If
+rsErrMach.Close
+Set rsErrMach = Nothing
+%>
+
+
+
+
+
+
Recent Errors
+
+
+
+
+ | Time |
+ Machine |
+ Type |
+ Message |
+
+
+
+<%
+' Get recent errors
+Dim rsRecentErr, recentErrStyle
+strSQL2 = "SELECT eventtime, machinenumber, errortype, errormessage " & _
+ "FROM udcerrors " & errWhereClause & _
+ " ORDER BY eventtime DESC LIMIT 25"
+Set rsRecentErr = objConn.Execute(strSQL2)
+If rsRecentErr.EOF Then
+ Response.Write("| No errors found |
")
+Else
+ Do While Not rsRecentErr.EOF
+ If InStr(1, rsRecentErr("errortype") & "", "Exception", 1) > 0 Then
+ recentErrStyle = "background-color:#dc3545; color:#fff;"
+ Else
+ recentErrStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsRecentErr("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentErr("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentErr("errortype") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(Left(rsRecentErr("errormessage") & "", 100)) & " | ")
+ Response.Write("
")
+ rsRecentErr.MoveNext
+ Loop
+End If
+rsRecentErr.Close
+Set rsRecentErr = Nothing
+%>
+
+
+
+
+
+
Connection Events by Machine
+
+
+
+
+ | Machine |
+ Total Events |
+ COM Ports Used |
+ Last Event |
+
+
+
+<%
+' Get connection events by machine
+Dim rsConnMach, connWhereClause
+connWhereClause = " WHERE eventtime >= '" & Replace(filterStart, "'", "''") & "' " & _
+ " AND eventtime <= '" & Replace(filterEnd, "'", "''") & " 23:59:59'"
+If filterMachine <> "" Then
+ connWhereClause = connWhereClause & " AND machinenumber = '" & Replace(filterMachine, "'", "''") & "'"
+End If
+If filterBU <> "" Then
+ connWhereClause = connWhereClause & " AND machinenumber IN (SELECT machinenumber FROM machines WHERE businessunitid = " & CLng(filterBU) & ")"
+End If
+
+strSQL2 = "SELECT machinenumber, COUNT(*) as cnt, COUNT(DISTINCT comport) as ports, MAX(eventtime) as lasttime " & _
+ "FROM udcconnections " & connWhereClause & _
+ " GROUP BY machinenumber ORDER BY cnt DESC, machinenumber ASC LIMIT 10"
+Set rsConnMach = objConn.Execute(strSQL2)
+If rsConnMach.EOF Then
+ Response.Write("| No connection events found |
")
+Else
+ Do While Not rsConnMach.EOF
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsConnMach("machinenumber") & "") & " | ")
+ Response.Write("" & rsConnMach("cnt") & " | ")
+ Response.Write("" & rsConnMach("ports") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsConnMach("lasttime") & "") & " | ")
+ Response.Write("
")
+ rsConnMach.MoveNext
+ Loop
+End If
+rsConnMach.Close
+Set rsConnMach = Nothing
+%>
+
+
+
+
+
+
Recent Connection Events
+
+
+
+
+ | Time |
+ Machine |
+ Event |
+ COM Port |
+ Details |
+
+
+
+<%
+' Get recent connection events
+Dim rsRecentConn, connStyle
+strSQL2 = "SELECT eventtime, machinenumber, eventtype, comport, details " & _
+ "FROM udcconnections " & connWhereClause & _
+ " ORDER BY eventtime DESC LIMIT 25"
+Set rsRecentConn = objConn.Execute(strSQL2)
+If rsRecentConn.EOF Then
+ Response.Write("| No connection events found |
")
+Else
+ Do While Not rsRecentConn.EOF
+ If rsRecentConn("eventtype") & "" = "OPEN" Then
+ connStyle = "background-color:#28a745; color:#fff;"
+ ElseIf rsRecentConn("eventtype") & "" = "CLOSE" Then
+ connStyle = "background-color:#6c757d; color:#fff;"
+ Else
+ connStyle = ""
+ End If
+ Response.Write("")
+ Response.Write("| " & Server.HTMLEncode(rsRecentConn("eventtime") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentConn("machinenumber") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentConn("eventtype") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentConn("comport") & "") & " | ")
+ Response.Write("" & Server.HTMLEncode(rsRecentConn("details") & "") & " | ")
+ Response.Write("
")
+ rsRecentConn.MoveNext
+ Loop
+End If
+rsRecentConn.Close
+Set rsRecentConn = Nothing
+%>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<%
+objConn.Close
+%>
diff --git a/docs/API.md b/docs/API.md
index 42b3776..1dbef42 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -906,6 +906,191 @@ Monitor these metrics:
---
+## UDC Log Data Endpoints
+
+These endpoints provide access to parsed UDC (Universal Data Collector) log data for management reporting.
+
+### 5. `getUDCPartRuns`
+
+**Purpose:** Get part run data with cycle times and measurement counts
+
+**Method:** GET
+
+**Parameters (all optional):**
+- `machinenumber` - Filter by machine number (e.g., "3110")
+- `startdate` - Start date filter (YYYY-MM-DD)
+- `enddate` - End date filter (YYYY-MM-DD)
+- `badgenumber` - Filter by operator badge
+
+**Response:**
+```json
+{
+ "success": true,
+ "partruns": [
+ {
+ "partrunid": 123,
+ "machinenumber": "3110",
+ "partnumber": "4096525-725G01",
+ "opernumber": "00602",
+ "serialnumber": "FGB0T7LH",
+ "programname": "03100042",
+ "jobnumber": "8J2R4",
+ "badgenumber": "020620BZ",
+ "programstart": "11/19/2025 10:02:53 AM",
+ "programend": "11/20/2025 2:05:16 AM",
+ "cycletime": 57743,
+ "changeover": 720,
+ "measurementcount": 205,
+ "manualcount": 25,
+ "probecount": 180,
+ "ootcount": 1
+ }
+ ]
+}
+```
+
+**Example:**
+```bash
+curl "http://server/api.asp?action=getUDCPartRuns&machinenumber=3110&startdate=2025-11-01"
+```
+
+---
+
+### 6. `getUDCOperatorStats`
+
+**Purpose:** Get aggregated operator statistics including average cycle times and manual response times
+
+**Method:** GET
+
+**Parameters (all optional):**
+- `startdate` - Start date filter (YYYY-MM-DD)
+- `enddate` - End date filter (YYYY-MM-DD)
+
+**Response:**
+```json
+{
+ "success": true,
+ "operators": [
+ {
+ "badgenumber": "020620BZ",
+ "partsrun": 156,
+ "avgcycletime": 19347,
+ "avgchangeover": 5000,
+ "avgmanualtime": 245,
+ "totalmeasurements": 27920,
+ "totalmanual": 3500,
+ "totaloot": 10,
+ "firstrun": "11/1/2025 9:15:51 AM",
+ "lastrun": "12/10/2025 6:54:28 AM"
+ }
+ ]
+}
+```
+
+**Example:**
+```bash
+curl "http://server/api.asp?action=getUDCOperatorStats&startdate=2025-11-01&enddate=2025-12-31"
+```
+
+---
+
+### 7. `getUDCMachineStats`
+
+**Purpose:** Get aggregated machine statistics including parts produced and OOT rates
+
+**Method:** GET
+
+**Parameters (all optional):**
+- `startdate` - Start date filter (YYYY-MM-DD)
+- `enddate` - End date filter (YYYY-MM-DD)
+
+**Response:**
+```json
+{
+ "success": true,
+ "machines": [
+ {
+ "machinenumber": "4003",
+ "partsrun": 156,
+ "avgcycletime": 19347,
+ "avgchangeover": 5000,
+ "totalmeasurements": 27920,
+ "totaloot": 10,
+ "firstrun": "5/4/2025 9:15:51 AM",
+ "lastrun": "6/17/2025 6:54:28 AM"
+ }
+ ]
+}
+```
+
+**Example:**
+```bash
+curl "http://server/api.asp?action=getUDCMachineStats"
+```
+
+---
+
+### 8. `getUDCManualTiming`
+
+**Purpose:** Get manual data entry response times (time from request prompt to operator entry)
+
+**Method:** GET
+
+**Parameters (all optional):**
+- `machinenumber` - Filter by machine number
+- `startdate` - Start date filter (YYYY-MM-DD)
+- `enddate` - End date filter (YYYY-MM-DD)
+
+**Response:**
+```json
+{
+ "success": true,
+ "manualrequests": [
+ {
+ "requestid": 123,
+ "badgenumber": "020620BZ",
+ "machinenumber": "3110",
+ "requesttime": "11/19/2025 10:00:27 AM",
+ "responsetime": "11/19/2025 10:05:31 AM",
+ "responseseconds": 304,
+ "description": "GAGE CUT STG4 BLADE DROP"
+ }
+ ]
+}
+```
+
+**Example:**
+```bash
+curl "http://server/api.asp?action=getUDCManualTiming&machinenumber=3110"
+```
+
+---
+
+## UDC Data Import
+
+UDC log files are imported using the Python parser at `/home/camp/projects/UDC/parser/udcparser.py`.
+
+**Usage:**
+```bash
+# Import all log files from default directory
+python3 udcparser.py
+
+# Import specific file
+python3 udcparser.py --file /path/to/UDC_Log_3110.log
+
+# Specify custom directory
+python3 udcparser.py --dir /path/to/logs
+```
+
+**Database Tables:**
+- `udcsessions` - Log file sessions
+- `udcparts` - Part runs with cycle times
+- `udcmeasurements` - Individual measurements (PROCESSDATA, TOOLDATA)
+- `udcevents` - Item crossings, messages
+- `udcmanualrequests` - Manual data entry timing
+
+---
+
## Future Enhancements
### Planned Features:
@@ -926,7 +1111,7 @@ Monitor these metrics:
---
-**Version:** 1.1
-**Last Updated:** 2025-12-11
+**Version:** 1.2
+**Last Updated:** 2025-12-12
**Maintained By:** ShopDB Development Team
**Support:** Review `/logs/api.log` for troubleshooting
diff --git a/includes/leftsidebar.asp b/includes/leftsidebar.asp
index 1c36f87..f293e75 100644
--- a/includes/leftsidebar.asp
+++ b/includes/leftsidebar.asp
@@ -1,6 +1,7 @@
<%
' Calculate fiscal week (GE fiscal year starts first Monday of January)
Dim fwToday, fwYearStart, fwFirstMonday, fwDayOfWeek, fwDaysFromStart, fiscalWeek
+Dim fwPrevYearStart, fwPrevFirstMonday, fwPrevDayOfWeek
fwToday = Date()
' Find first Monday of current year
@@ -14,7 +15,6 @@ End If
' If we're before the first Monday, use previous year's week count
If fwToday < fwFirstMonday Then
- Dim fwPrevYearStart, fwPrevFirstMonday, fwPrevDayOfWeek
fwPrevYearStart = DateSerial(Year(fwToday) - 1, 1, 1)
fwPrevDayOfWeek = Weekday(fwPrevYearStart, vbMonday)
If fwPrevDayOfWeek = 1 Then
@@ -82,7 +82,11 @@ End If
Reports
-
+
+
+ UDC Reports
+
+
Network
diff --git a/sql/udctables.sql b/sql/udctables.sql
new file mode 100644
index 0000000..b41d90a
--- /dev/null
+++ b/sql/udctables.sql
@@ -0,0 +1,292 @@
+-- ============================================================================
+-- UDC Log Parser Database Schema
+-- Stores parsed data from UDC (Universal Data Collector) log files
+-- Created: 2025-12-12
+-- ============================================================================
+
+-- Sessions table - tracks each log file imported
+CREATE TABLE IF NOT EXISTS udcsessions (
+ sessionid INT AUTO_INCREMENT PRIMARY KEY,
+ machineid INT,
+ machinenumber VARCHAR(20),
+ logfilename VARCHAR(255) NOT NULL,
+ sessionstart DATETIME,
+ sessionend DATETIME,
+ recordcount INT DEFAULT 0,
+ dateadded DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_machineid (machineid),
+ INDEX idx_machinenumber (machinenumber),
+ INDEX idx_sessionstart (sessionstart),
+ UNIQUE INDEX idx_logfilename (logfilename(191))
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Parts table - tracks each part run (serial number cycle)
+CREATE TABLE IF NOT EXISTS udcparts (
+ partrunid INT AUTO_INCREMENT PRIMARY KEY,
+ sessionid INT NOT NULL,
+ machineid INT,
+ partnumber VARCHAR(50),
+ opernumber VARCHAR(20),
+ serialnumber VARCHAR(50),
+ programname VARCHAR(50),
+ jobnumber VARCHAR(50),
+ badgenumber VARCHAR(20),
+ programstart DATETIME,
+ programend DATETIME,
+ cycletime INT,
+ changeover INT,
+ measurementcount INT DEFAULT 0,
+ manualcount INT DEFAULT 0,
+ probecount INT DEFAULT 0,
+ ootcount INT DEFAULT 0,
+ dateadded DATETIME DEFAULT CURRENT_TIMESTAMP,
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_machineid (machineid),
+ INDEX idx_serialnumber (serialnumber),
+ INDEX idx_partnumber (partnumber),
+ INDEX idx_jobnumber (jobnumber),
+ INDEX idx_badgenumber (badgenumber),
+ INDEX idx_programstart (programstart),
+ CONSTRAINT fk_udcparts_session FOREIGN KEY (sessionid) REFERENCES udcsessions(sessionid) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Measurements table - all PROCESSDATA, TOOLDATA, MACHINEDATA entries
+CREATE TABLE IF NOT EXISTS udcmeasurements (
+ measurementid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ sessionid INT NOT NULL,
+ eventtime DATETIME,
+ eventtype VARCHAR(20),
+ method VARCHAR(20),
+ dimid VARCHAR(20),
+ description VARCHAR(255),
+ seqnumber INT,
+ minval DECIMAL(12,6),
+ maxval DECIMAL(12,6),
+ actualval DECIMAL(12,6),
+ deviation DECIMAL(12,6),
+ oot TINYINT DEFAULT 0,
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_eventtime (eventtime),
+ INDEX idx_method (method),
+ INDEX idx_oot (oot),
+ CONSTRAINT fk_udcmeasurements_partrun FOREIGN KEY (partrunid) REFERENCES udcparts(partrunid) ON DELETE CASCADE,
+ CONSTRAINT fk_udcmeasurements_session FOREIGN KEY (sessionid) REFERENCES udcsessions(sessionid) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Events table - item crossings, messages, manual requests
+CREATE TABLE IF NOT EXISTS udcevents (
+ eventid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ sessionid INT NOT NULL,
+ eventtime DATETIME,
+ eventtype VARCHAR(30),
+ itemnumber VARCHAR(20),
+ description TEXT,
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_eventtime (eventtime),
+ INDEX idx_eventtype (eventtype),
+ CONSTRAINT fk_udcevents_partrun FOREIGN KEY (partrunid) REFERENCES udcparts(partrunid) ON DELETE CASCADE,
+ CONSTRAINT fk_udcevents_session FOREIGN KEY (sessionid) REFERENCES udcsessions(sessionid) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Manual requests table - tracks timing of manual data entry
+CREATE TABLE IF NOT EXISTS udcmanualrequests (
+ requestid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ measurementid INT,
+ requesttime DATETIME,
+ responsetime DATETIME,
+ responseseconds INT,
+ description VARCHAR(255),
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_requesttime (requesttime),
+ INDEX idx_responseseconds (responseseconds),
+ CONSTRAINT fk_udcmanualrequests_partrun FOREIGN KEY (partrunid) REFERENCES udcparts(partrunid) ON DELETE CASCADE,
+ CONSTRAINT fk_udcmanualrequests_measurement FOREIGN KEY (measurementid) REFERENCES udcmeasurements(measurementid) ON DELETE SET NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Tool data table - TOOLDATA entries (tool offsets, wear, corner radius)
+CREATE TABLE IF NOT EXISTS udctooldata (
+ tooldataid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ sessionid INT NOT NULL,
+ eventtime DATETIME,
+ method VARCHAR(20),
+ dimid VARCHAR(20),
+ description VARCHAR(255),
+ toolnumber INT,
+ minval DECIMAL(12,6),
+ maxval DECIMAL(12,6),
+ actualval DECIMAL(12,6),
+ deviation DECIMAL(12,6),
+ oot TINYINT DEFAULT 0,
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_eventtime (eventtime),
+ INDEX idx_toolnumber (toolnumber),
+ INDEX idx_oot (oot),
+ CONSTRAINT fk_udctooldata_partrun FOREIGN KEY (partrunid) REFERENCES udcparts(partrunid) ON DELETE SET NULL,
+ CONSTRAINT fk_udctooldata_session FOREIGN KEY (sessionid) REFERENCES udcsessions(sessionid) ON DELETE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Errors table - error events from UDC logs
+CREATE TABLE IF NOT EXISTS udcerrors (
+ errorid INT AUTO_INCREMENT PRIMARY KEY,
+ sessionid INT,
+ machinenumber VARCHAR(20),
+ eventtime DATETIME,
+ errortype VARCHAR(100),
+ errormessage TEXT,
+ sourcemethod VARCHAR(255),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_machinenumber (machinenumber),
+ INDEX idx_eventtime (eventtime),
+ INDEX idx_errortype (errortype)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Connections table - serial/network connection events
+CREATE TABLE IF NOT EXISTS udcconnections (
+ connectionid INT AUTO_INCREMENT PRIMARY KEY,
+ sessionid INT,
+ machinenumber VARCHAR(20),
+ eventtime DATETIME,
+ eventtype VARCHAR(20),
+ comport VARCHAR(20),
+ details VARCHAR(255),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_machinenumber (machinenumber),
+ INDEX idx_eventtime (eventtime),
+ INDEX idx_eventtype (eventtype)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Active sessions table - tracks currently running machines
+CREATE TABLE IF NOT EXISTS udcactivesessions (
+ activeid INT AUTO_INCREMENT PRIMARY KEY,
+ machinenumber VARCHAR(20) NOT NULL,
+ sessionid INT,
+ partnumber VARCHAR(50),
+ badgenumber VARCHAR(20),
+ partsrun INT DEFAULT 0,
+ sessionstart DATETIME,
+ lastupdate DATETIME,
+ UNIQUE INDEX idx_machinenumber (machinenumber),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_lastupdate (lastupdate)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Header updates table - badge changes during part runs
+CREATE TABLE IF NOT EXISTS udcheaderupdates (
+ updateid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ sessionid INT,
+ machinenumber VARCHAR(20),
+ eventtime DATETIME,
+ details VARCHAR(255),
+ description VARCHAR(255),
+ badgenumber VARCHAR(20),
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_machinenumber (machinenumber),
+ INDEX idx_eventtime (eventtime)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- Violations table - item crossing value changes
+CREATE TABLE IF NOT EXISTS udcviolations (
+ violationid INT AUTO_INCREMENT PRIMARY KEY,
+ partrunid INT,
+ sessionid INT,
+ machinenumber VARCHAR(20),
+ eventtime DATETIME,
+ previousval DECIMAL(12,4),
+ currentval DECIMAL(12,4),
+ badgenumber VARCHAR(20),
+ itemno VARCHAR(20),
+ crossingdesc VARCHAR(255),
+ INDEX idx_partrunid (partrunid),
+ INDEX idx_sessionid (sessionid),
+ INDEX idx_machinenumber (machinenumber),
+ INDEX idx_eventtime (eventtime)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
+
+-- ============================================================================
+-- Useful Views for Reporting
+-- ============================================================================
+
+-- Part runs with machine info
+CREATE OR REPLACE VIEW vwudcpartruns AS
+SELECT
+ p.partrunid,
+ p.sessionid,
+ p.machineid,
+ s.machinenumber,
+ p.partnumber,
+ p.opernumber,
+ p.serialnumber,
+ p.programname,
+ p.jobnumber,
+ p.badgenumber,
+ p.programstart,
+ p.programend,
+ p.cycletime,
+ p.changeover,
+ p.measurementcount,
+ p.manualcount,
+ p.probecount,
+ p.ootcount
+FROM udcparts p
+JOIN udcsessions s ON p.sessionid = s.sessionid;
+
+-- Operator stats aggregation
+CREATE OR REPLACE VIEW vwudcoperatorstats AS
+SELECT
+ badgenumber,
+ COUNT(*) AS partsrun,
+ AVG(cycletime) AS avgcycletime,
+ AVG(changeover) AS avgchangeover,
+ SUM(measurementcount) AS totalmeasurements,
+ SUM(manualcount) AS totalmanual,
+ SUM(ootcount) AS totaloot,
+ MIN(programstart) AS firstrun,
+ MAX(programend) AS lastrun
+FROM udcparts
+WHERE badgenumber IS NOT NULL AND badgenumber != ''
+GROUP BY badgenumber;
+
+-- Machine stats aggregation
+CREATE OR REPLACE VIEW vwudcmachinestats AS
+SELECT
+ s.machinenumber,
+ p.machineid,
+ COUNT(*) AS partsrun,
+ AVG(p.cycletime) AS avgcycletime,
+ AVG(p.changeover) AS avgchangeover,
+ SUM(p.measurementcount) AS totalmeasurements,
+ SUM(p.ootcount) AS totaloot,
+ MIN(p.programstart) AS firstrun,
+ MAX(p.programend) AS lastrun
+FROM udcparts p
+JOIN udcsessions s ON p.sessionid = s.sessionid
+GROUP BY s.machinenumber, p.machineid;
+
+-- Manual request response times
+CREATE OR REPLACE VIEW vwudcmanualtiming AS
+SELECT
+ r.requestid,
+ p.badgenumber,
+ s.machinenumber,
+ r.requesttime,
+ r.responsetime,
+ r.responseseconds,
+ r.description
+FROM udcmanualrequests r
+JOIN udcparts p ON r.partrunid = p.partrunid
+JOIN udcsessions s ON p.sessionid = s.sessionid;
+
+-- ============================================================================
+-- Verify
+-- ============================================================================
+SELECT 'UDC tables created successfully' AS status;
+SHOW TABLES LIKE 'udc%';