Add UDC Performance Dashboard and Tool Health features
- Add displayudc.asp with Dashboard tab containing: - Production Trend chart (daily parts) - OOT Rate Trend chart (daily OOT %) - Machine Utilization chart (top 10 by runtime hours) - Top Operators chart (top 10 by parts produced) - Add tabs for drill-down: Live Activity, Operators, Machines, Parts, Quality/OOT, Timing, Activity Log, Tool Health, Uptime, IT Diagnostics - Add Tool Health section to displaymachine.asp UDC tab: - Summary cards (tools monitored, measurements, OOT count) - Tool status table with health indicators - Recent OOT events display - Add UDC API endpoints in api.asp: - getUDCPartRuns, getUDCOperatorStats, getUDCMachineStats, getUDCManualTiming - Add sql/udctables.sql schema for UDC data storage - Update docs/API.md with UDC endpoint documentation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
360
api.asp
360
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
|
||||
|
||||
|
||||
@@ -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
|
||||
%>
|
||||
|
||||
<body class="bg-theme <%=Server.HTMLEncode(theme)%>">
|
||||
@@ -143,6 +161,12 @@
|
||||
<h5 class="card-text"><%=Server.HTMLEncode(rs("machinetype") & "")%></h5>
|
||||
<%' machinedescription column doesn't exist in Phase 2 schema %>
|
||||
<p class="card-text"><%=Server.HTMLEncode(rs("machinenotes") & "")%></p>
|
||||
<%
|
||||
' Only show Print Badge for equipment (has machinenumber), not servers/network devices
|
||||
If Trim(rs("machinenumber") & "") <> "" Then
|
||||
%>
|
||||
<a href="./printbadge.asp?machineid=<%=Server.HTMLEncode(machineid)%>" target="_blank" class="btn btn-primary btn-sm mt-3">Print Badge</a>
|
||||
<% End If %>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -168,6 +192,11 @@
|
||||
<li class="nav-item">
|
||||
<a href="javascript:void();" data-target="#applications" data-toggle="pill" class="nav-link"><i class="zmdi zmdi-apps"></i> <span class="hidden-xs">Applications</span></a>
|
||||
</li>
|
||||
<% End If %>
|
||||
<% If hasUDCData Then %>
|
||||
<li class="nav-item">
|
||||
<a href="javascript:void();" data-target="#udc" data-toggle="pill" class="nav-link"><i class="zmdi zmdi-chart"></i> <span class="hidden-xs">UDC</span></a>
|
||||
</li>
|
||||
<% End If %>
|
||||
<li class="nav-item">
|
||||
<a href="./machineedit.asp?machineid=<%=Server.HTMLEncode(machineid)%>" class="nav-link" style="background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); color: white;"><i class="zmdi zmdi-edit"></i> <span class="hidden-xs">Edit Machine</span></a>
|
||||
@@ -408,6 +437,7 @@ End If
|
||||
<tr>
|
||||
<th>PC Hostname</th>
|
||||
<th>IP Address</th>
|
||||
<th>Location</th>
|
||||
<th>Relationship</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -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("<tr><td colspan='3' class='text-muted text-center'>No controlling PC assigned</td></tr>")
|
||||
Response.Write("<tr><td colspan='4' class='text-muted text-center'>No controlling PC assigned</td></tr>")
|
||||
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("<tr>")
|
||||
Response.Write("<td><a href='./displaypc.asp?machineid=" & pcMachineID & "'>" & Server.HTMLEncode(pcHostname) & "</a></td>")
|
||||
Response.Write("<td>" & pcIP & "</td>")
|
||||
Response.Write("<td class='text-center'><a href='#' class='location-link text-info' data-machineid='" & pcMachineID & "' data-name='" & Server.HTMLEncode(pcHostname) & "'><i class='zmdi zmdi-pin' style='font-size:1.2rem;'></i></a></td>")
|
||||
Response.Write("<td><span class='badge badge-primary'>" & Server.HTMLEncode(rs2("relationshiptype") & "") & "</span></td>")
|
||||
Response.Write("</tr>")
|
||||
rs2.MoveNext
|
||||
@@ -787,6 +819,338 @@ End If
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<% End If %>
|
||||
<% If hasUDCData Then %>
|
||||
<div class="tab-pane" id="udc">
|
||||
<h5 class="mb-3">UDC Performance Data</h5>
|
||||
|
||||
<!-- Today's Stats Summary Cards -->
|
||||
<div class="row mb-4">
|
||||
<%
|
||||
' 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
|
||||
%>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-success text-white">
|
||||
<div class="card-body text-center">
|
||||
<h3 class="mb-0"><%=todayParts%></h3>
|
||||
<small>Parts Today</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-info text-white">
|
||||
<div class="card-body text-center">
|
||||
<h3 class="mb-0"><%=todayAvgCycle%>m</h3>
|
||||
<small>Avg Cycle Time</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card <% If todayOOT > 0 Then Response.Write("bg-danger") Else Response.Write("bg-secondary") End If %> text-white">
|
||||
<div class="card-body text-center">
|
||||
<h3 class="mb-0"><%=todayOOT%></h3>
|
||||
<small>OOT Today</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body text-center">
|
||||
<h3 class="mb-0"><%If todayLastBadge <> "" Then Response.Write(Server.HTMLEncode(todayLastBadge)) Else Response.Write("-")%></h3>
|
||||
<small>Current Operator</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Recent Activity Log -->
|
||||
<h6 class="mb-2"><i class="zmdi zmdi-time-restore"></i> Recent Activity</h6>
|
||||
<div class="table-responsive mb-4">
|
||||
<table class="table table-hover table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Type</th>
|
||||
<th>Badge</th>
|
||||
<th>Details</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
' 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("<tr><td colspan='4' class='text-muted text-center'>No recent activity</td></tr>")
|
||||
Else
|
||||
Do While Not rsActivity.EOF
|
||||
If rsActivity("acttype") = "Violation" Then
|
||||
actBadge = "<span class='badge badge-light'>Setting Change</span>"
|
||||
Else
|
||||
actBadge = "<span class='badge badge-info'>Badge</span>"
|
||||
End If
|
||||
|
||||
Response.Write("<tr>")
|
||||
Response.Write("<td class='small'>" & Server.HTMLEncode(rsActivity("eventtime") & "") & "</td>")
|
||||
Response.Write("<td>" & actBadge & "</td>")
|
||||
Response.Write("<td>" & Server.HTMLEncode(rsActivity("badgenumber") & "") & "</td>")
|
||||
Response.Write("<td class='small'>" & Server.HTMLEncode(rsActivity("details") & "") & "</td>")
|
||||
Response.Write("</tr>")
|
||||
rsActivity.MoveNext
|
||||
Loop
|
||||
End If
|
||||
rsActivity.Close
|
||||
Set rsActivity = Nothing
|
||||
%>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Tool Health Section -->
|
||||
<h6 class="mb-2 mt-4"><i class="zmdi zmdi-settings"></i> Tool Health</h6>
|
||||
<%
|
||||
' 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
|
||||
%>
|
||||
<!-- Tool Health Summary Cards -->
|
||||
<div class="row mb-3">
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-secondary text-white">
|
||||
<div class="card-body text-center py-2">
|
||||
<h4 class="mb-0"><%=toolCount%></h4>
|
||||
<small>Tools Monitored</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-info text-white">
|
||||
<div class="card-body text-center py-2">
|
||||
<h4 class="mb-0"><%=toolMeasurements%></h4>
|
||||
<small>Measurements (30d)</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card <% If toolOOT > 0 Then Response.Write("bg-danger") Else Response.Write("bg-success") End If %> text-white">
|
||||
<div class="card-body text-center py-2">
|
||||
<h4 class="mb-0"><%=toolOOT%></h4>
|
||||
<small>Out of Tolerance</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card bg-primary text-white">
|
||||
<div class="card-body text-center py-2">
|
||||
<h6 class="mb-0"><%If toolLastCheck <> "" Then Response.Write(Server.HTMLEncode(Left(toolLastCheck, 16))) Else Response.Write("-")%></h6>
|
||||
<small>Last Tool Check</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tool Status Table -->
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table table-hover table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tool #</th>
|
||||
<th>Description</th>
|
||||
<th>Checks</th>
|
||||
<th>Avg Dev</th>
|
||||
<th>Max Dev</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
' 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("<tr><td colspan='6' class='text-muted text-center'>No tool data available</td></tr>")
|
||||
Else
|
||||
Do While Not rsTools.EOF
|
||||
' Calculate status based on OOT and deviation
|
||||
If CLng(rsTools("oot_count") & "0") > 0 Then
|
||||
toolStatus = "<i class='zmdi zmdi-alert-circle'></i> <strong>OOT</strong>"
|
||||
toolStatusClass = "bg-danger text-white"
|
||||
Else
|
||||
toolStatus = "<i class='zmdi zmdi-check-circle text-success'></i> 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("<tr class='" & toolStatusClass & "'>")
|
||||
Response.Write("<td><strong>" & Server.HTMLEncode(rsTools("toolnumber") & "") & "</strong></td>")
|
||||
Response.Write("<td class='small'>" & Server.HTMLEncode(Left(rsTools("description") & "", 30)) & "</td>")
|
||||
Response.Write("<td>" & rsTools("measurements") & "</td>")
|
||||
Response.Write("<td>" & toolAvgDev & "</td>")
|
||||
Response.Write("<td>" & toolMaxDev & "</td>")
|
||||
Response.Write("<td>" & toolStatus & "</td>")
|
||||
Response.Write("</tr>")
|
||||
rsTools.MoveNext
|
||||
Loop
|
||||
End If
|
||||
rsTools.Close
|
||||
Set rsTools = Nothing
|
||||
%>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<%
|
||||
' 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 OOT Events -->
|
||||
<h6 class="mb-2"><i class="zmdi zmdi-alert-triangle text-warning"></i> Recent Out-of-Tolerance Events (7 days)</h6>
|
||||
<div class="table-responsive mb-3">
|
||||
<table class="table table-hover table-sm">
|
||||
<thead class="thead-light">
|
||||
<tr>
|
||||
<th>Time</th>
|
||||
<th>Tool #</th>
|
||||
<th>Description</th>
|
||||
<th>Actual</th>
|
||||
<th>Min/Max</th>
|
||||
<th>Deviation</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<%
|
||||
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("<tr class='bg-warning'>")
|
||||
Response.Write("<td class='small'>" & Server.HTMLEncode(rsOOTEvents("eventtime") & "") & "</td>")
|
||||
Response.Write("<td><strong>" & Server.HTMLEncode(rsOOTEvents("toolnumber") & "") & "</strong></td>")
|
||||
Response.Write("<td class='small'>" & Server.HTMLEncode(Left(rsOOTEvents("description") & "", 25)) & "</td>")
|
||||
Response.Write("<td>" & FormatNumber(CDbl(rsOOTEvents("actualval") & "0"), 4) & "</td>")
|
||||
Response.Write("<td class='small'>" & FormatNumber(CDbl(rsOOTEvents("minval") & "0"), 4) & " / " & FormatNumber(CDbl(rsOOTEvents("maxval") & "0"), 4) & "</td>")
|
||||
Response.Write("<td class='text-danger'><strong>" & FormatNumber(CDbl(rsOOTEvents("deviation") & "0"), 4) & "</strong></td>")
|
||||
Response.Write("</tr>")
|
||||
rsOOTEvents.MoveNext
|
||||
Loop
|
||||
rsOOTEvents.Close
|
||||
Set rsOOTEvents = Nothing
|
||||
%>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<%
|
||||
End If ' ootEventCount > 0
|
||||
Else ' toolMeasurements = 0
|
||||
%>
|
||||
<div class="alert alert-secondary">
|
||||
<i class="zmdi zmdi-info-outline"></i> No tool measurement data available for this machine.
|
||||
</div>
|
||||
<%
|
||||
End If ' toolMeasurements > 0
|
||||
%>
|
||||
|
||||
<!-- Link to Full Dashboard -->
|
||||
<div class="text-center">
|
||||
<a href="./displayudc.asp?machine=<%=Server.URLEncode(rs("machinenumber") & "")%>" class="btn btn-primary">
|
||||
<i class="zmdi zmdi-chart"></i> View Full UDC Dashboard
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<% End If %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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();
|
||||
|
||||
2173
displayudc.asp
Normal file
2173
displayudc.asp
Normal file
File diff suppressed because it is too large
Load Diff
189
docs/API.md
189
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
|
||||
|
||||
@@ -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
|
||||
<i class="zmdi zmdi-collection-image text-yellow"></i><span>Reports</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="./displayudc.asp">
|
||||
<i class="zmdi zmdi-chart text-info"></i><span>UDC Reports</span>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="sidebar-header">Admin</li>
|
||||
<li><a href="./displaysubnets.asp"><i class="zmdi zmdi-network text-danger"></i><span>Network</span></a></li>
|
||||
|
||||
292
sql/udctables.sql
Normal file
292
sql/udctables.sql
Normal file
@@ -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%';
|
||||
Reference in New Issue
Block a user