Files
shopdb/displayudc.asp
cproudlock a4096ace94 Fix network device description/machinenotes display and edit
- Fix ADO cursor issue where reading rs("description") twice caused
  empty values (IsNull check consumed the field value)
- Change all device pages to read description field once using
  `description = rs("description") & ""` pattern
- Add deviceDescription variable in displaydevice.asp
- Fix machinetypeid mapping: IDF=17, Camera=18 (was swapped)
- Add model dropdown fix to include currently assigned model
- Add server application tracking feature
- Various other improvements and fixes

Files affected:
- displaydevice.asp, displaylocationdevice.asp
- deviceaccesspoint.asp, deviceserver.asp, deviceswitch.asp
- devicecamera.asp, deviceidf.asp
- savenetworkdevice.asp, networkdevices.asp

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 13:47:56 -05:00

2948 lines
123 KiB
Plaintext

<%@ 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
%>
<!DOCTYPE html>
<html lang="en">
<head>
<!--#include file="./includes/header.asp"-->
<!--#include file="./includes/sql.asp"-->
<title>UDC Dashboard - ShopDB</title>
</head>
<%
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, tempDate
If periodFilter = "today" Then
filterStart = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
filterEnd = filterStart
periodLabel = "Today"
ElseIf periodFilter = "yesterday" Then
tempDate = DateAdd("d", -1, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = filterStart
periodLabel = "Yesterday"
ElseIf periodFilter = "7days" Then
tempDate = DateAdd("d", -6, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "Last 7 Days"
ElseIf periodFilter = "14days" Then
tempDate = DateAdd("d", -13, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "Last 14 Days"
ElseIf periodFilter = "30days" Then
tempDate = DateAdd("d", -29, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "Last 30 Days"
ElseIf periodFilter = "90days" Then
tempDate = DateAdd("d", -89, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "Last 90 Days"
ElseIf periodFilter = "week" Then
tempDate = DateAdd("d", -7, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "This Week"
ElseIf periodFilter = "month" Then
tempDate = DateAdd("d", -30, Date())
filterStart = Year(tempDate) & "-" & Right("0" & Month(tempDate), 2) & "-" & Right("0" & Day(tempDate), 2)
filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
periodLabel = "This Month"
Else
periodLabel = "Custom Range"
End If
%>
<body class="bg-theme <%=Server.HTMLEncode(theme)%>">
<!-- start loader -->
<div id="pageloader-overlay" class="visible incoming"><div class="loader-wrapper-outer"><div class="loader-wrapper-inner"><div class="loader"></div></div></div></div>
<div id="wrapper">
<!--#include file="./includes/leftsidebar.asp"-->
<!--#include file="./includes/topbarheader.asp"-->
<div class="clearfix"></div>
<div class="content-wrapper">
<div class="container-fluid">
<!-- Page Header -->
<div class="row mt-3">
<div class="col-12">
<div class="card">
<div class="card-header" style="background: linear-gradient(45deg, #667eea 0%, #764ba2 100%); color: white;">
<h5 class="mb-0">UDC Performance Dashboard</h5>
</div>
<div class="card-body">
<!-- Filter Controls -->
<form id="udcFilterForm" method="get" class="mb-0">
<div class="row">
<div class="col-md-2">
<label class="small">Quick Range</label>
<select name="period" class="form-control form-control-sm" onchange="this.form.submit()">
<option value="">Custom</option>
<option value="today" <%If periodFilter="today" Then Response.Write("selected")%>>Today</option>
<option value="yesterday" <%If periodFilter="yesterday" Then Response.Write("selected")%>>Yesterday</option>
<option value="7days" <%If periodFilter="7days" Then Response.Write("selected")%>>Last 7 Days</option>
<option value="14days" <%If periodFilter="14days" Then Response.Write("selected")%>>Last 14 Days</option>
<option value="30days" <%If periodFilter="30days" Then Response.Write("selected")%>>Last 30 Days</option>
<option value="90days" <%If periodFilter="90days" Then Response.Write("selected")%>>Last 90 Days</option>
</select>
</div>
<div class="col-md-2">
<label class="small">Start Date</label>
<input type="date" name="startdate" class="form-control form-control-sm" value="<%=Server.HTMLEncode(filterStart)%>">
</div>
<div class="col-md-2">
<label class="small">End Date</label>
<input type="date" name="enddate" class="form-control form-control-sm" value="<%=Server.HTMLEncode(filterEnd)%>">
</div>
<div class="col-md-2">
<label class="small">Business Unit</label>
<select name="bu" id="buFilter" class="form-control form-control-sm" onchange="this.form.submit()">
<option value="">All BUs</option>
<%
' Get list of business units with UDC machines
Dim rsBUs
Set rsBUs = objConn.Execute("SELECT DISTINCT b.businessunitid, b.businessunit FROM businessunits b " & _
"JOIN machines m ON m.businessunitid = b.businessunitid " & _
"JOIN udcsessions s ON m.machinenumber = s.machinenumber " & _
"ORDER BY b.businessunit")
Do While Not rsBUs.EOF
Response.Write("<option value=""" & Server.HTMLEncode(rsBUs("businessunitid") & "") & """")
If filterBU = rsBUs("businessunitid") & "" Then Response.Write(" selected")
Response.Write(">" & Server.HTMLEncode(rsBUs("businessunit") & "") & "</option>")
rsBUs.MoveNext
Loop
rsBUs.Close
Set rsBUs = Nothing
%>
</select>
</div>
<div class="col-md-2">
<label class="small">Machine</label>
<select name="machine" class="form-control form-control-sm">
<option value="">All Machines</option>
<%
' Get list of machines with UDC data, filtered by BU if selected
Dim rsMachines, machineSQL
machineSQL = "SELECT DISTINCT s.machinenumber FROM udcsessions s " & _
"JOIN machines m ON m.machinenumber = s.machinenumber "
If filterBU <> "" Then
machineSQL = machineSQL & "WHERE m.businessunitid = " & CLng(filterBU) & " "
End If
machineSQL = machineSQL & "ORDER BY s.machinenumber"
Set rsMachines = objConn.Execute(machineSQL)
Do While Not rsMachines.EOF
Response.Write("<option value=""" & Server.HTMLEncode(rsMachines("machinenumber") & "") & """")
If filterMachine = rsMachines("machinenumber") & "" Then Response.Write(" selected")
Response.Write(">" & Server.HTMLEncode(rsMachines("machinenumber") & "") & "</option>")
rsMachines.MoveNext
Loop
rsMachines.Close
Set rsMachines = Nothing
%>
</select>
</div>
<div class="col-md-2">
<label class="small">Operator Badge</label>
<select name="badge" class="form-control form-control-sm">
<option value="">All Operators</option>
<%
' Get list of operators
Dim rsBadges
Set rsBadges = objConn.Execute("SELECT DISTINCT badgenumber FROM udcparts WHERE badgenumber IS NOT NULL AND badgenumber != '' ORDER BY badgenumber")
Do While Not rsBadges.EOF
Response.Write("<option value=""" & Server.HTMLEncode(rsBadges("badgenumber") & "") & """")
If filterBadge = rsBadges("badgenumber") & "" Then Response.Write(" selected")
Response.Write(">" & Server.HTMLEncode(rsBadges("badgenumber") & "") & "</option>")
rsBadges.MoveNext
Loop
rsBadges.Close
Set rsBadges = Nothing
%>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col-6">
<div class="form-check form-check-inline">
<input type="checkbox" class="form-check-input" id="excludeshift" name="excludeshift" value="1" <%If excludeShiftSpan Then Response.Write("checked")%>>
<label class="form-check-label small" for="excludeshift">Exclude idle time (removes responses over 30 min)</label>
</div>
</div>
<div class="col-6 text-right">
<button type="submit" class="btn btn-primary btn-sm mr-2">Filter</button>
<a href="displayudc.asp" class="btn btn-secondary btn-sm mr-2">Clear</a>
<button type="button" class="btn btn-outline-info btn-sm" onclick="copyFilterLink(this)" title="Copy a shareable link with your current filters">Share This View</button>
</div>
</div>
<input type="hidden" name="tab" id="activeTabInput" value="<%=Server.HTMLEncode(activeTab)%>">
</form>
</div>
</div>
</div>
</div>
<!-- Summary Cards Row -->
<%
' 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
%>
<!-- Summary Cards -->
<div class="row mt-3">
<div class="col-lg-3 col-md-6">
<div class="card bg-success text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="media-body">
<h4 class="mb-0"><%=totalParts%></h4>
<span>Total Parts Produced</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card bg-info text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="media-body">
<h4 class="mb-0"><%=avgCycleTime%>m</h4>
<span>Avg Cycle Time</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<%
If CDbl(ootRate) > 5 Then
ootCardClass = "bg-danger"
ElseIf CDbl(ootRate) > 0 Then
ootCardClass = "bg-warning"
Else
ootCardClass = "bg-success"
End If
%>
<div class="card <%=ootCardClass%> text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="media-body">
<h4 class="mb-0"><%=ootRate%>%</h4>
<span>Parts with OOT (<%=partsWithOOT%> of <%=totalParts%>)</span>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="card bg-primary text-white">
<div class="card-body">
<div class="d-flex align-items-center">
<div class="media-body">
<h4 class="mb-0"><%=avgManualResp%>s</h4>
<span>Avg Manual Response</span>
</div>
</div>
</div>
</div>
</div>
</div>
<%
' ============================================================================
' 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"
' ============================================================================
' HISTORICAL TRENDS DATA (from summary tables - survives 90-day purge)
' ============================================================================
' Monthly measurement trends (last 12 months)
Dim rsMonthlyMeas, monthlyLabels, monthlyMeasData, monthlyOOTData, monthlyOOTRate
monthlyLabels = ""
monthlyMeasData = ""
monthlyOOTData = ""
monthlyOOTRate = ""
strSQL2 = "SELECT yearmonth, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot, " & _
"ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _
"FROM vwudcmeasurements_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12"
Set rsMonthlyMeas = objConn.Execute(strSQL2)
Dim monthlyArr(11,3), monthlyIdx
monthlyIdx = 0
Do While Not rsMonthlyMeas.EOF And monthlyIdx < 12
monthlyArr(monthlyIdx, 0) = rsMonthlyMeas("yearmonth") & ""
monthlyArr(monthlyIdx, 1) = rsMonthlyMeas("total_meas") & ""
monthlyArr(monthlyIdx, 2) = rsMonthlyMeas("total_oot") & ""
If IsNull(rsMonthlyMeas("oot_rate")) Then
monthlyArr(monthlyIdx, 3) = "0"
Else
monthlyArr(monthlyIdx, 3) = rsMonthlyMeas("oot_rate") & ""
End If
monthlyIdx = monthlyIdx + 1
rsMonthlyMeas.MoveNext
Loop
rsMonthlyMeas.Close
Set rsMonthlyMeas = Nothing
' Reverse order for chronological display
Dim mi
For mi = monthlyIdx - 1 To 0 Step -1
If monthlyLabels <> "" Then monthlyLabels = monthlyLabels & ","
If monthlyMeasData <> "" Then monthlyMeasData = monthlyMeasData & ","
If monthlyOOTData <> "" Then monthlyOOTData = monthlyOOTData & ","
If monthlyOOTRate <> "" Then monthlyOOTRate = monthlyOOTRate & ","
monthlyLabels = monthlyLabels & """" & monthlyArr(mi, 0) & """"
monthlyMeasData = monthlyMeasData & monthlyArr(mi, 1)
monthlyOOTData = monthlyOOTData & monthlyArr(mi, 2)
monthlyOOTRate = monthlyOOTRate & monthlyArr(mi, 3)
Next
If monthlyLabels = "" Then monthlyLabels = """No Data"""
If monthlyMeasData = "" Then monthlyMeasData = "0"
If monthlyOOTData = "" Then monthlyOOTData = "0"
If monthlyOOTRate = "" Then monthlyOOTRate = "0"
' Machine comparison from summaries (total measurements by machine, all time)
Dim rsMachHist, machHistLabels, machHistMeas, machHistOOT
machHistLabels = ""
machHistMeas = ""
machHistOOT = ""
strSQL2 = "SELECT machinenumber, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot " & _
"FROM udcmeasurements_daily GROUP BY machinenumber ORDER BY total_meas DESC LIMIT 15"
Set rsMachHist = objConn.Execute(strSQL2)
Do While Not rsMachHist.EOF
If machHistLabels <> "" Then machHistLabels = machHistLabels & ","
If machHistMeas <> "" Then machHistMeas = machHistMeas & ","
If machHistOOT <> "" Then machHistOOT = machHistOOT & ","
machHistLabels = machHistLabels & """" & (rsMachHist("machinenumber") & "") & """"
machHistMeas = machHistMeas & (rsMachHist("total_meas") & "")
machHistOOT = machHistOOT & (rsMachHist("total_oot") & "")
rsMachHist.MoveNext
Loop
rsMachHist.Close
Set rsMachHist = Nothing
If machHistLabels = "" Then machHistLabels = """No Data"""
If machHistMeas = "" Then machHistMeas = "0"
If machHistOOT = "" Then machHistOOT = "0"
' Weekly trends for the last 26 weeks
Dim rsWeeklyTrend, weeklyLabels, weeklyMeasData, weeklyOOTRate
weeklyLabels = ""
weeklyMeasData = ""
weeklyOOTRate = ""
strSQL2 = "SELECT week_start, SUM(measurement_count) as total_meas, " & _
"ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _
"FROM vwudcmeasurements_weekly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearweek, week_start ORDER BY week_start DESC LIMIT 26"
Set rsWeeklyTrend = objConn.Execute(strSQL2)
Dim weeklyArr(25,2), weeklyIdx
weeklyIdx = 0
Do While Not rsWeeklyTrend.EOF And weeklyIdx < 26
weeklyArr(weeklyIdx, 0) = Month(rsWeeklyTrend("week_start")) & "/" & Day(rsWeeklyTrend("week_start"))
weeklyArr(weeklyIdx, 1) = rsWeeklyTrend("total_meas") & ""
If IsNull(rsWeeklyTrend("oot_rate")) Then
weeklyArr(weeklyIdx, 2) = "0"
Else
weeklyArr(weeklyIdx, 2) = rsWeeklyTrend("oot_rate") & ""
End If
weeklyIdx = weeklyIdx + 1
rsWeeklyTrend.MoveNext
Loop
rsWeeklyTrend.Close
Set rsWeeklyTrend = Nothing
' Reverse for chronological
Dim wi
For wi = weeklyIdx - 1 To 0 Step -1
If weeklyLabels <> "" Then weeklyLabels = weeklyLabels & ","
If weeklyMeasData <> "" Then weeklyMeasData = weeklyMeasData & ","
If weeklyOOTRate <> "" Then weeklyOOTRate = weeklyOOTRate & ","
weeklyLabels = weeklyLabels & """" & weeklyArr(wi, 0) & """"
weeklyMeasData = weeklyMeasData & weeklyArr(wi, 1)
weeklyOOTRate = weeklyOOTRate & weeklyArr(wi, 2)
Next
If weeklyLabels = "" Then weeklyLabels = """No Data"""
If weeklyMeasData = "" Then weeklyMeasData = "0"
If weeklyOOTRate = "" Then weeklyOOTRate = "0"
' Monthly parts production trends (from udcpartsdaily)
Dim rsMonthlyParts, monthlyPartsLabels, monthlyPartsData
monthlyPartsLabels = ""
monthlyPartsData = ""
strSQL2 = "SELECT yearmonth, SUM(partscount) as total_parts " & _
"FROM vwudcparts_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12"
Set rsMonthlyParts = objConn.Execute(strSQL2)
Dim partsArr(11,1), partsIdx
partsIdx = 0
Do While Not rsMonthlyParts.EOF And partsIdx < 12
partsArr(partsIdx, 0) = rsMonthlyParts("yearmonth") & ""
partsArr(partsIdx, 1) = rsMonthlyParts("total_parts") & ""
partsIdx = partsIdx + 1
rsMonthlyParts.MoveNext
Loop
rsMonthlyParts.Close
Set rsMonthlyParts = Nothing
Dim pi
For pi = partsIdx - 1 To 0 Step -1
If monthlyPartsLabels <> "" Then monthlyPartsLabels = monthlyPartsLabels & ","
If monthlyPartsData <> "" Then monthlyPartsData = monthlyPartsData & ","
monthlyPartsLabels = monthlyPartsLabels & """" & partsArr(pi, 0) & """"
monthlyPartsData = monthlyPartsData & partsArr(pi, 1)
Next
If monthlyPartsLabels = "" Then monthlyPartsLabels = """No Data"""
If monthlyPartsData = "" Then monthlyPartsData = "0"
' Monthly response time trends (from udcmanualrequestsdaily)
Dim rsMonthlyResp, monthlyRespLabels, monthlyRespData
monthlyRespLabels = ""
monthlyRespData = ""
strSQL2 = "SELECT yearmonth, ROUND(AVG(avgresponseseconds), 1) as avg_resp " & _
"FROM vwudcmanualrequests_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12"
Set rsMonthlyResp = objConn.Execute(strSQL2)
Dim respArr(11,1), respIdx
respIdx = 0
Do While Not rsMonthlyResp.EOF And respIdx < 12
respArr(respIdx, 0) = rsMonthlyResp("yearmonth") & ""
If IsNull(rsMonthlyResp("avg_resp")) Then
respArr(respIdx, 1) = "0"
Else
respArr(respIdx, 1) = rsMonthlyResp("avg_resp") & ""
End If
respIdx = respIdx + 1
rsMonthlyResp.MoveNext
Loop
rsMonthlyResp.Close
Set rsMonthlyResp = Nothing
Dim ri
For ri = respIdx - 1 To 0 Step -1
If monthlyRespLabels <> "" Then monthlyRespLabels = monthlyRespLabels & ","
If monthlyRespData <> "" Then monthlyRespData = monthlyRespData & ","
monthlyRespLabels = monthlyRespLabels & """" & respArr(ri, 0) & """"
monthlyRespData = monthlyRespData & respArr(ri, 1)
Next
If monthlyRespLabels = "" Then monthlyRespLabels = """No Data"""
If monthlyRespData = "" Then monthlyRespData = "0"
' Monthly violations trends (CLM specific)
Dim rsMonthlyViol, monthlyViolLabels, monthlyViolData
monthlyViolLabels = ""
monthlyViolData = ""
strSQL2 = "SELECT yearmonth, SUM(violationcount) as total_violations " & _
"FROM vwudcviolations_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12"
Set rsMonthlyViol = objConn.Execute(strSQL2)
Dim violArr(11,1), violIdx
violIdx = 0
Do While Not rsMonthlyViol.EOF And violIdx < 12
violArr(violIdx, 0) = rsMonthlyViol("yearmonth") & ""
If IsNull(rsMonthlyViol("total_violations")) Then
violArr(violIdx, 1) = "0"
Else
violArr(violIdx, 1) = rsMonthlyViol("total_violations") & ""
End If
violIdx = violIdx + 1
rsMonthlyViol.MoveNext
Loop
rsMonthlyViol.Close
Set rsMonthlyViol = Nothing
Dim vi
For vi = violIdx - 1 To 0 Step -1
If monthlyViolLabels <> "" Then monthlyViolLabels = monthlyViolLabels & ","
If monthlyViolData <> "" Then monthlyViolData = monthlyViolData & ","
monthlyViolLabels = monthlyViolLabels & """" & violArr(vi, 0) & """"
monthlyViolData = monthlyViolData & violArr(vi, 1)
Next
If monthlyViolLabels = "" Then monthlyViolLabels = """No Data"""
If monthlyViolData = "" Then monthlyViolData = "0"
' Monthly changeover time trends
Dim rsMonthlyChg, monthlyChgLabels, monthlyChgData
monthlyChgLabels = ""
monthlyChgData = ""
strSQL2 = "SELECT yearmonth, ROUND(AVG(avgchangeover)/60, 1) as avg_changeover_min " & _
"FROM vwudcchangeover_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 12"
Set rsMonthlyChg = objConn.Execute(strSQL2)
Dim chgArr(11,1), chgIdx
chgIdx = 0
Do While Not rsMonthlyChg.EOF And chgIdx < 12
chgArr(chgIdx, 0) = rsMonthlyChg("yearmonth") & ""
If IsNull(rsMonthlyChg("avg_changeover_min")) Then
chgArr(chgIdx, 1) = "0"
Else
chgArr(chgIdx, 1) = rsMonthlyChg("avg_changeover_min") & ""
End If
chgIdx = chgIdx + 1
rsMonthlyChg.MoveNext
Loop
rsMonthlyChg.Close
Set rsMonthlyChg = Nothing
Dim ci
For ci = chgIdx - 1 To 0 Step -1
If monthlyChgLabels <> "" Then monthlyChgLabels = monthlyChgLabels & ","
If monthlyChgData <> "" Then monthlyChgData = monthlyChgData & ","
monthlyChgLabels = monthlyChgLabels & """" & chgArr(ci, 0) & """"
monthlyChgData = monthlyChgData & chgArr(ci, 1)
Next
If monthlyChgLabels = "" Then monthlyChgLabels = """No Data"""
If monthlyChgData = "" Then monthlyChgData = "0"
' Violations by machine (top 10)
Dim rsViolByMachine, violMachLabels, violMachData
violMachLabels = ""
violMachData = ""
strSQL2 = "SELECT machinenumber, SUM(violationcount) as total_violations " & _
"FROM vwudcviolations_monthly " & _
"GROUP BY machinenumber ORDER BY total_violations DESC LIMIT 10"
Set rsViolByMachine = objConn.Execute(strSQL2)
Do While Not rsViolByMachine.EOF
If violMachLabels <> "" Then violMachLabels = violMachLabels & ","
If violMachData <> "" Then violMachData = violMachData & ","
violMachLabels = violMachLabels & """" & rsViolByMachine("machinenumber") & """"
violMachData = violMachData & rsViolByMachine("total_violations")
rsViolByMachine.MoveNext
Loop
rsViolByMachine.Close
Set rsViolByMachine = Nothing
If violMachLabels = "" Then violMachLabels = """No Data"""
If violMachData = "" Then violMachData = "0"
%>
<!-- Tabbed Content Area -->
<div class="row mt-3">
<div class="col-12">
<div class="card">
<div class="card-body">
<ul class="nav nav-tabs nav-tabs-primary" id="udcTabs">
<li class="nav-item">
<a href="#dashboard" data-toggle="tab" class="nav-link<%If activeTab="dashboard" Then Response.Write(" active")%>" onclick="setActiveTab('dashboard')">Dashboard</a>
</li>
<li class="nav-item">
<a href="#liveactivity" data-toggle="tab" class="nav-link<%If activeTab="liveactivity" Then Response.Write(" active")%>" onclick="setActiveTab('liveactivity')">Live Activity</a>
</li>
<li class="nav-item">
<a href="#operators" data-toggle="tab" class="nav-link<%If activeTab="operators" Then Response.Write(" active")%>" onclick="setActiveTab('operators')">Operators</a>
</li>
<li class="nav-item">
<a href="#machines" data-toggle="tab" class="nav-link<%If activeTab="machines" Then Response.Write(" active")%>" onclick="setActiveTab('machines')">Machines</a>
</li>
<li class="nav-item">
<a href="#parts" data-toggle="tab" class="nav-link<%If activeTab="parts" Then Response.Write(" active")%>" onclick="setActiveTab('parts')">Parts</a>
</li>
<li class="nav-item">
<a href="#quality" data-toggle="tab" class="nav-link<%If activeTab="quality" Then Response.Write(" active")%>" onclick="setActiveTab('quality')">Quality/OOT</a>
</li>
<li class="nav-item">
<a href="#timing" data-toggle="tab" class="nav-link<%If activeTab="timing" Then Response.Write(" active")%>" onclick="setActiveTab('timing')">Timing</a>
</li>
<li class="nav-item">
<a href="#activitylog" data-toggle="tab" class="nav-link<%If activeTab="activitylog" Then Response.Write(" active")%>" onclick="setActiveTab('activitylog')">Activity Log</a>
</li>
<li class="nav-item">
<a href="#toolhealth" data-toggle="tab" class="nav-link<%If activeTab="toolhealth" Then Response.Write(" active")%>" onclick="setActiveTab('toolhealth')">Tool Health</a>
</li>
<li class="nav-item">
<a href="#uptime" data-toggle="tab" class="nav-link<%If activeTab="uptime" Then Response.Write(" active")%>" onclick="setActiveTab('uptime')">Uptime</a>
</li>
<li class="nav-item">
<a href="#itdiagnostics" data-toggle="tab" class="nav-link<%If activeTab="itdiagnostics" Then Response.Write(" active")%>" onclick="setActiveTab('itdiagnostics')">IT Diagnostics</a>
</li>
<li class="nav-item">
<a href="#trends" data-toggle="tab" class="nav-link<%If activeTab="trends" Then Response.Write(" active")%>" onclick="setActiveTab('trends')">Historical Trends</a>
</li>
</ul>
<div class="tab-content p-3">
<!-- Tab: Dashboard (Charts) -->
<div class="tab-pane<%If activeTab="dashboard" Then Response.Write(" active")%>" id="dashboard">
<h5 class="mb-3">UDC Performance Dashboard</h5>
<!-- Charts Row 1 -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-primary text-white py-2">
Production Trend
</div>
<div class="card-body">
<div style="height: 220px;">
<canvas id="productionChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-danger text-white py-2">
OOT Rate Trend
</div>
<div class="card-body">
<div style="height: 220px;">
<canvas id="ootChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row 2 -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-info text-white py-2">
Machine Utilization (Hours)
</div>
<div class="card-body">
<div style="height: 220px;">
<canvas id="machineChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-success text-white py-2">
Top Operators (Parts)
</div>
<div class="card-body">
<div style="height: 220px;">
<canvas id="operatorChart"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Tab: Live Activity -->
<div class="tab-pane<%If activeTab="liveactivity" Then Response.Write(" active")%>" id="liveactivity">
<h5 class="mb-3">Active Machines <span class="badge badge-success">Live</span></h5>
<p class="text-muted small mb-3">Machines currently running jobs. Data refreshes when page loads.</p>
<%
' 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
%>
<div class="alert alert-secondary text-center">
No active jobs detected
</div>
<%
Else
%>
<div class="table-responsive">
<table class="table table-hover table-striped" id="activeTable">
<thead>
<tr>
<th>Machine</th>
<th>Part Number</th>
<th>Operator Badge</th>
<th>Parts Run</th>
<th>Runtime</th>
<th>Session Start</th>
<th>Last Activity</th>
</tr>
</thead>
<tbody>
<%
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("<tr>")
Response.Write("<td><a href='displaymachine.asp?machinenumber=" & Server.URLEncode(rsActive("machinenumber") & "") & "'><strong>" & Server.HTMLEncode(rsActive("machinenumber") & "") & "</strong></a></td>")
Response.Write("<td>" & Server.HTMLEncode(rsActive("partnumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsActive("badgenumber") & "") & "</td>")
Response.Write("<td><span class='badge badge-info'>" & rsActive("partsrun") & "</span></td>")
Response.Write("<td>" & runtimeDisplay & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsActive("sessionstart") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsActive("lastupdate") & "") & "</td>")
Response.Write("</tr>")
rsActive.MoveNext
Loop
%>
</tbody>
</table>
</div>
<p class="text-muted small mt-2 mb-0"><strong><%=activeCount%></strong> machine(s) currently active</p>
<%
End If
rsActive.Close
Set rsActive = Nothing
%>
</div>
<!-- Tab: Operator Performance -->
<div class="tab-pane<%If activeTab="operators" Then Response.Write(" active")%>" id="operators">
<h5 class="mb-3">Operator Performance Leaderboard</h5>
<div class="table-responsive">
<table class="table table-hover table-striped" id="operatorTable">
<thead>
<tr>
<th>Badge #</th>
<th>Parts Run</th>
<th>Avg Cycle (min)</th>
<th>Avg Manual Response (sec)</th>
<th>Last Active</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No operator data found</td></tr>")
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("<tr style='" & opRowStyle & "'>")
Response.Write("<td><a href='displayudc.asp?badge=" & Server.URLEncode(rsOperators("badgenumber") & "") & "' style='color:inherit;'>" & Server.HTMLEncode(rsOperators("badgenumber") & "") & "</a></td>")
Response.Write("<td>" & rsOperators("partsrun") & "</td>")
Response.Write("<td>" & opCycle & "</td>")
Response.Write("<td>" & opManual & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsOperators("lastactive") & "") & "</td>")
Response.Write("</tr>")
rsOperators.MoveNext
Loop
End If
rsOperators.Close
Set rsOperators = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 2: Machine Performance -->
<div class="tab-pane<%If activeTab="machines" Then Response.Write(" active")%>" id="machines">
<h5 class="mb-3">Machine Performance Comparison</h5>
<div class="table-responsive">
<table class="table table-hover table-striped" id="machineTable">
<thead>
<tr>
<th>Machine #</th>
<th>Parts Run</th>
<th>Avg Cycle (min)</th>
<th>Avg Changeover (min)</th>
<th>Parts with OOT</th>
<th>OOT Rate</th>
<th>Last Run</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='7' class='text-muted text-center'>No machine data found</td></tr>")
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 = "<span class='badge badge-danger'>" & machOOTRate & "%</span>"
ElseIf CDbl(machOOTRate) > 0 Then
machOOTBadge = "<span class='badge badge-warning'>" & machOOTRate & "%</span>"
Else
machOOTBadge = "<span class='badge badge-success'>" & machOOTRate & "%</span>"
End If
Response.Write("<tr>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsMachStats("machinenumber") & "") & "'>" & Server.HTMLEncode(rsMachStats("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsMachStats("partsrun") & "</td>")
Response.Write("<td>" & machCycle & "</td>")
Response.Write("<td>" & machChange & "</td>")
Response.Write("<td>" & machPartsWithOOT & "</td>")
Response.Write("<td>" & machOOTBadge & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsMachStats("lastrun") & "") & "</td>")
Response.Write("</tr>")
rsMachStats.MoveNext
Loop
End If
rsMachStats.Close
Set rsMachStats = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 3: Part Analysis -->
<div class="tab-pane<%If activeTab="parts" Then Response.Write(" active")%>" id="parts">
<h5 class="mb-3">Part Number Analysis</h5>
<div class="table-responsive">
<table class="table table-hover table-striped" id="partsTable">
<thead>
<tr>
<th>Part #</th>
<th>Count</th>
<th>Avg Cycle (min)</th>
<th>Parts with OOT</th>
<th>OOT Rate</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No part data found</td></tr>")
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 = "<span class='badge badge-danger'>" & partOOTRate & "%</span>"
ElseIf CDbl(partOOTRate) > 0 Then
partOOTBadge = "<span class='badge badge-warning'>" & partOOTRate & "%</span>"
Else
partOOTBadge = "<span class='badge badge-success'>0%</span>"
End If
Response.Write("<tr>")
Response.Write("<td>" & Server.HTMLEncode(rsPartStats("partnumber") & "") & "</td>")
Response.Write("<td>" & rsPartStats("cnt") & "</td>")
Response.Write("<td>" & partCycle & "</td>")
Response.Write("<td>" & partPartsWithOOT & "</td>")
Response.Write("<td>" & partOOTBadge & "</td>")
Response.Write("</tr>")
rsPartStats.MoveNext
Loop
End If
rsPartStats.Close
Set rsPartStats = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 4: Quality/OOT Analysis -->
<div class="tab-pane<%If activeTab="quality" Then Response.Write(" active")%>" id="quality">
<h5 class="mb-3">Out-of-Tolerance Analysis</h5>
<!-- OOT Summary by Machine -->
<h6 class="mt-3 mb-2">OOT by Machine</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Parts with OOT</th>
<th>Parts Run</th>
<th>OOT Rate</th>
<th style="width:40%">Bar</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No OOT data found</td></tr>")
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("<tr>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsOOTMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsOOTMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & ootMachParts & "</td>")
Response.Write("<td>" & rsOOTMach("partsrun") & "</td>")
Response.Write("<td>" & ootMachRate & "%</td>")
Response.Write("<td><div style='background:#dc3545;height:20px;width:" & barWidth & "%;border-radius:3px;'></div></td>")
Response.Write("</tr>")
rsOOTMach.MoveNext
Loop
End If
rsOOTMach.Close
Set rsOOTMach = Nothing
%>
</tbody>
</table>
</div>
<!-- Recent OOT Measurements -->
<h6 class="mt-4 mb-2">Recent OOT Measurements</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Part #</th>
<th>Dimension</th>
<th>Min</th>
<th>Actual</th>
<th>Max</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='7' class='text-muted text-center'>No OOT measurements found</td></tr>")
Else
Do While Not rsOOT.EOF
Response.Write("<tr style='background-color:#dc3545; color:#fff;'>")
Response.Write("<td>" & Server.HTMLEncode(rsOOT("eventtime") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsOOT("machinenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsOOT("partnumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsOOT("dimid") & "") & " - " & Server.HTMLEncode(rsOOT("description") & "") & "</td>")
Response.Write("<td>" & rsOOT("minval") & "</td>")
Response.Write("<td><strong>" & rsOOT("actualval") & "</strong></td>")
Response.Write("<td>" & rsOOT("maxval") & "</td>")
Response.Write("</tr>")
rsOOT.MoveNext
Loop
End If
rsOOT.Close
Set rsOOT = Nothing
%>
</tbody>
</table>
</div>
<!-- Best Performing Machines -->
<h6 class="mt-4 mb-2">Best Performing Machines (Lowest OOT Rates)</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Parts Run</th>
<th>OOT Count</th>
<th>OOT Rate</th>
<th style="width:40%">Quality Bar</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No machine data found (min 10 parts required)</td></tr>")
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("<tr style='" & bestStyle & "'>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsBestMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsBestMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsBestMach("partsrun") & "</td>")
Response.Write("<td>" & bestPartsWithOOT & "</td>")
Response.Write("<td>" & bestRate & "%</td>")
Response.Write("<td><div style='background:#28a745;height:20px;width:" & qualityWidth & "%;border-radius:3px;'></div></td>")
Response.Write("</tr>")
rsBestMach.MoveNext
Loop
End If
rsBestMach.Close
Set rsBestMach = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 5: Timing Analysis -->
<div class="tab-pane<%If activeTab="timing" Then Response.Write(" active")%>" id="timing">
<h5 class="mb-3">Timing Analysis</h5>
<!-- Manual Response Time by Operator -->
<h6 class="mt-3 mb-2">Manual Response Time by Operator</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Badge #</th>
<th>Requests</th>
<th>Avg Response (sec)</th>
<th>Max Response (sec)</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No manual request data found</td></tr>")
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("<tr>")
Response.Write("<td><a href='displayudc.asp?badge=" & Server.URLEncode(rsManualOp("badgenumber") & "") & "'>" & Server.HTMLEncode(rsManualOp("badgenumber") & "") & "</a></td>")
Response.Write("<td>" & rsManualOp("requests") & "</td>")
Response.Write("<td>" & manAvg & "</td>")
Response.Write("<td>" & manMax & "</td>")
Response.Write("</tr>")
rsManualOp.MoveNext
Loop
End If
rsManualOp.Close
Set rsManualOp = Nothing
%>
</tbody>
</table>
</div>
<!-- Slowest Manual Responses -->
<h6 class="mt-4 mb-2">Slowest Manual Responses</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Request Time</th>
<th>Machine</th>
<th>Badge</th>
<th>Description</th>
<th>Response Time (sec)</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No manual requests found</td></tr>")
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("<tr style='" & rowStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsSlow("requesttime") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsSlow("machinenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsSlow("badgenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsSlow("description") & "") & "</td>")
Response.Write("<td>" & rsSlow("responseseconds") & "</td>")
Response.Write("</tr>")
rsSlow.MoveNext
Loop
End If
rsSlow.Close
Set rsSlow = Nothing
%>
</tbody>
</table>
</div>
<!-- Fastest Manual Responses -->
<h6 class="mt-4 mb-2">Fastest Responses (Top Performers)</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Request Time</th>
<th>Machine</th>
<th>Badge</th>
<th>Description</th>
<th>Response Time (sec)</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No manual requests found</td></tr>")
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("<tr style='" & fastStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsFast("requesttime") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsFast("machinenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsFast("badgenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsFast("description") & "") & "</td>")
Response.Write("<td>" & rsFast("responseseconds") & "</td>")
Response.Write("</tr>")
rsFast.MoveNext
Loop
End If
rsFast.Close
Set rsFast = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 6: Activity Log (Violations & Badge Changes) -->
<div class="tab-pane<%If activeTab="activitylog" Then Response.Write(" active")%>" id="activitylog">
<h5 class="mb-3">Activity Log</h5>
<p class="text-muted small mb-3">Badge changes and item crossing violations recorded during part runs.</p>
<!-- Item Violations Summary -->
<h6 class="mt-3 mb-2">Item Crossing Violations</h6>
<p class="text-muted small">When operators modify item crossing values during a program run.</p>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Badge</th>
<th>Crossing</th>
<th>Item#</th>
<th>Previous</th>
<th>Current</th>
<th>Change</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='8' class='text-muted text-center'>No item violations found in date range</td></tr>")
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("<tr style='" & violStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsViolations("eventtime") & "") & "</td>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsViolations("machinenumber") & "") & "'>" & Server.HTMLEncode(rsViolations("machinenumber") & "") & "</a></td>")
Response.Write("<td><a href='displayudc.asp?badge=" & Server.URLEncode(rsViolations("badgenumber") & "") & "'>" & Server.HTMLEncode(rsViolations("badgenumber") & "") & "</a></td>")
Response.Write("<td>" & Server.HTMLEncode(rsViolations("crossingdesc") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsViolations("itemno") & "") & "</td>")
Response.Write("<td>" & FormatNumber(violPrev, 2) & "</td>")
Response.Write("<td><strong>" & FormatNumber(violCurr, 2) & "</strong></td>")
If violChange > 0 Then
Response.Write("<td><span class='text-success'>+" & FormatNumber(violChange, 2) & "</span></td>")
ElseIf violChange < 0 Then
Response.Write("<td><span class='text-danger'>" & FormatNumber(violChange, 2) & "</span></td>")
Else
Response.Write("<td>0</td>")
End If
Response.Write("</tr>")
rsViolations.MoveNext
Loop
End If
rsViolations.Close
Set rsViolations = Nothing
%>
</tbody>
</table>
</div>
<!-- Violations by Machine -->
<h6 class="mt-4 mb-2">Violations by Machine</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Total Violations</th>
<th>Unique Crossings</th>
<th>Last Violation</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No violations found</td></tr>")
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("<tr style='" & violMachStyle & "'>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsViolMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsViolMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsViolMach("cnt") & "</td>")
Response.Write("<td>" & rsViolMach("crossings") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsViolMach("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsViolMach.MoveNext
Loop
End If
rsViolMach.Close
Set rsViolMach = Nothing
%>
</tbody>
</table>
</div>
<!-- Badge Changes -->
<h6 class="mt-4 mb-2">Badge Changes</h6>
<p class="text-muted small">Operator badge scans and changes during part runs.</p>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Badge</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No badge changes found in date range</td></tr>")
Else
Do While Not rsBadgeChanges.EOF
Response.Write("<tr>")
Response.Write("<td>" & Server.HTMLEncode(rsBadgeChanges("eventtime") & "") & "</td>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsBadgeChanges("machinenumber") & "") & "'>" & Server.HTMLEncode(rsBadgeChanges("machinenumber") & "") & "</a></td>")
Response.Write("<td><a href='displayudc.asp?badge=" & Server.URLEncode(rsBadgeChanges("badgenumber") & "") & "'><span class='badge badge-info'>" & Server.HTMLEncode(rsBadgeChanges("badgenumber") & "") & "</span></a></td>")
Response.Write("<td>" & Server.HTMLEncode(rsBadgeChanges("description") & "") & "</td>")
Response.Write("</tr>")
rsBadgeChanges.MoveNext
Loop
End If
rsBadgeChanges.Close
Set rsBadgeChanges = Nothing
%>
</tbody>
</table>
</div>
<!-- Badge Activity by Operator -->
<h6 class="mt-4 mb-2">Badge Activity by Operator</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Badge #</th>
<th>Badge Scans</th>
<th>Machines Used</th>
<th>Last Activity</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No badge activity found</td></tr>")
Else
Do While Not rsBadgeSum.EOF
Response.Write("<tr>")
Response.Write("<td><a href='displayudc.asp?badge=" & Server.URLEncode(rsBadgeSum("badgenumber") & "") & "'><span class='badge badge-info'>" & Server.HTMLEncode(rsBadgeSum("badgenumber") & "") & "</span></a></td>")
Response.Write("<td>" & rsBadgeSum("cnt") & "</td>")
Response.Write("<td>" & rsBadgeSum("machines") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsBadgeSum("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsBadgeSum.MoveNext
Loop
End If
rsBadgeSum.Close
Set rsBadgeSum = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 7: Tool Health -->
<div class="tab-pane<%If activeTab="toolhealth" Then Response.Write(" active")%>" id="toolhealth">
<h5 class="mb-3">Tool Health</h5>
<p class="text-muted small mb-3">Tool offset measurements and wear tracking.</p>
<!-- Tool Summary by Machine -->
<h6 class="mt-3 mb-2">Tool Measurements by Machine</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Measurements</th>
<th>Unique Tools</th>
<th>OOT Count</th>
<th>Last Measurement</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No tool data found in date range</td></tr>")
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("<tr style='" & toolMachStyle & "'>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsToolMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsToolMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsToolMach("cnt") & "</td>")
Response.Write("<td>" & rsToolMach("tools") & "</td>")
Response.Write("<td>")
If CLng("0" & rsToolMach("ootcount")) > 0 Then
Response.Write("<span class='badge badge-danger'>" & rsToolMach("ootcount") & "</span>")
Else
Response.Write("<span class='badge badge-success'>0</span>")
End If
Response.Write("</td>")
Response.Write("<td>" & Server.HTMLEncode(rsToolMach("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsToolMach.MoveNext
Loop
End If
rsToolMach.Close
Set rsToolMach = Nothing
%>
</tbody>
</table>
</div>
<!-- Tool Usage by Tool Number - Only shown when machine filter selected -->
<%
If filterMachine <> "" Then
%>
<h6 class="mt-4 mb-2">Most Used Tools on Machine <%=Server.HTMLEncode(filterMachine)%></h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Tool #</th>
<th>Description</th>
<th>Measurements</th>
<th>Avg Deviation</th>
<th>OOT Count</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No tool data found</td></tr>")
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("<tr style='" & toolNumStyle & "'>")
Response.Write("<td><strong>Tool " & rsToolNum("toolnumber") & "</strong></td>")
Response.Write("<td>" & Server.HTMLEncode(Trim(rsToolNum("description") & "")) & "</td>")
Response.Write("<td>" & rsToolNum("cnt") & "</td>")
Response.Write("<td>" & avgDev & "</td>")
Response.Write("<td>")
If CLng("0" & rsToolNum("ootcount")) > 0 Then
Response.Write("<span class='badge badge-danger'>" & rsToolNum("ootcount") & "</span>")
Else
Response.Write("<span class='badge badge-success'>0</span>")
End If
Response.Write("</td>")
Response.Write("</tr>")
rsToolNum.MoveNext
Loop
End If
rsToolNum.Close
Set rsToolNum = Nothing
%>
</tbody>
</table>
</div>
<%
End If ' filterMachine
%>
<!-- Recent Tool Measurements -->
<h6 class="mt-4 mb-2">Recent Tool Measurements</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Tool #</th>
<th>Description</th>
<th>Min</th>
<th>Actual</th>
<th>Max</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='8' class='text-muted text-center'>No tool measurements found</td></tr>")
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("<tr style='" & toolRecentStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsToolRecent("eventtime") & "") & "</td>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsToolRecent("machinenumber") & "") & "'>" & Server.HTMLEncode(rsToolRecent("machinenumber") & "") & "</a></td>")
Response.Write("<td>Tool " & rsToolRecent("toolnumber") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsToolRecent("description") & "") & "</td>")
Response.Write("<td>" & rsToolRecent("minval") & "</td>")
Response.Write("<td><strong>" & rsToolRecent("actualval") & "</strong></td>")
Response.Write("<td>" & rsToolRecent("maxval") & "</td>")
If CLng("0" & rsToolRecent("oot")) > 0 Then
Response.Write("<td><span class='badge badge-danger'>OOT</span></td>")
Else
Response.Write("<td><span class='badge badge-success'>OK</span></td>")
End If
Response.Write("</tr>")
rsToolRecent.MoveNext
Loop
End If
rsToolRecent.Close
Set rsToolRecent = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 8: Uptime -->
<div class="tab-pane<%If activeTab="uptime" Then Response.Write(" active")%>" id="uptime">
<h5 class="mb-3">Machine Uptime</h5>
<p class="text-muted small mb-3">Runtime calculated from actual part cycle times within the selected date range.</p>
<!-- Uptime Summary Cards -->
<div class="row mb-4">
<%
' 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
%>
<div class="col-md-4">
<div class="card bg-info text-white">
<div class="card-body text-center">
<h3 class="mb-0"><%=totalRuntimeHours%></h3>
<small>Total Runtime Hours</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card bg-success text-white">
<div class="card-body text-center">
<h3 class="mb-0"><%=totalMachines%></h3>
<small>Active Machines</small>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card bg-primary text-white">
<div class="card-body text-center">
<h3 class="mb-0"><%=totalParts%></h3>
<small>Parts Produced</small>
</div>
</div>
</div>
</div>
<!-- Machine Uptime Table -->
<h6 class="mt-3 mb-2">Runtime by Machine</h6>
<div class="table-responsive">
<table class="table table-hover table-striped" id="uptimeTable">
<thead>
<tr>
<th>Machine</th>
<th>Runtime (hrs)</th>
<th>Parts Run</th>
<th>Avg Cycle (min)</th>
<th>Days Active</th>
<th>Utilization</th>
</tr>
</thead>
<tbody>
<%
' Get uptime by machine
Dim rsUptime, uptimeHours, uptimeCycle, uptimeDays, uptimeUtil, uptimeUtilClass
strSQL2 = "SELECT s.machinenumber, " & _
"ROUND(SUM(p.cycletime)/3600, 1) as runtime_hours, " & _
"COUNT(*) as parts_run, " & _
"ROUND(AVG(p.cycletime)/60, 1) as avg_cycle_min, " & _
"DATEDIFF(MAX(p.programend), MIN(p.programstart)) + 1 as days_active, " & _
"MIN(p.programstart) as first_run, " & _
"MAX(p.programend) as last_run " & _
"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"
Set rsUptime = objConn.Execute(strSQL2)
If rsUptime.EOF Then
Response.Write("<tr><td colspan='6' class='text-muted text-center'>No uptime data found</td></tr>")
Else
Do While Not rsUptime.EOF
If Not IsNull(rsUptime("runtime_hours")) Then
uptimeHours = FormatNumber(CDbl(rsUptime("runtime_hours")), 1)
Else
uptimeHours = "0"
End If
If Not IsNull(rsUptime("avg_cycle_min")) Then
uptimeCycle = FormatNumber(CDbl(rsUptime("avg_cycle_min")), 1)
Else
uptimeCycle = "-"
End If
uptimeDays = CLng("0" & rsUptime("days_active"))
If uptimeDays < 1 Then uptimeDays = 1
' Calculate utilization (runtime hours / (days * 16 hours for 2 shifts) * 100)
If uptimeDays > 0 And Not IsNull(rsUptime("runtime_hours")) Then
uptimeUtil = Round((CDbl(rsUptime("runtime_hours")) / (uptimeDays * 16)) * 100, 1)
If uptimeUtil > 100 Then uptimeUtil = 100
Else
uptimeUtil = 0
End If
' Color code utilization
If uptimeUtil >= 70 Then
uptimeUtilClass = "badge badge-success"
ElseIf uptimeUtil >= 40 Then
uptimeUtilClass = "badge badge-warning"
Else
uptimeUtilClass = "badge badge-danger"
End If
Response.Write("<tr>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsUptime("machinenumber") & "") & "'>" & Server.HTMLEncode(rsUptime("machinenumber") & "") & "</a></td>")
Response.Write("<td><strong>" & uptimeHours & "</strong></td>")
Response.Write("<td>" & rsUptime("parts_run") & "</td>")
Response.Write("<td>" & uptimeCycle & "</td>")
Response.Write("<td>" & uptimeDays & "</td>")
Response.Write("<td><span class='" & uptimeUtilClass & "'>" & uptimeUtil & "%</span></td>")
Response.Write("</tr>")
rsUptime.MoveNext
Loop
End If
rsUptime.Close
Set rsUptime = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab 9: IT Diagnostics -->
<div class="tab-pane<%If activeTab="itdiagnostics" Then Response.Write(" active")%>" id="itdiagnostics">
<h5 class="mb-3">IT Diagnostics</h5>
<!-- Error Summary by Type -->
<h6 class="mt-3 mb-2">Error Summary by Type</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Error Type</th>
<th>Count</th>
<th>Machines Affected</th>
<th>Last Occurrence</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No errors found in date range</td></tr>")
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("<tr style='" & errRowStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsErrSummary("errortype") & "") & "</td>")
Response.Write("<td>" & rsErrSummary("cnt") & "</td>")
Response.Write("<td>" & rsErrSummary("machines") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsErrSummary("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsErrSummary.MoveNext
Loop
End If
rsErrSummary.Close
Set rsErrSummary = Nothing
%>
</tbody>
</table>
</div>
<!-- Error Summary by Machine -->
<h6 class="mt-4 mb-2">Errors by Machine</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Total Errors</th>
<th>Error Types</th>
<th>Last Error</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No errors found</td></tr>")
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("<tr style='" & errMachStyle & "'>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsErrMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsErrMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsErrMach("cnt") & "</td>")
Response.Write("<td>" & rsErrMach("types") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsErrMach("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsErrMach.MoveNext
Loop
End If
rsErrMach.Close
Set rsErrMach = Nothing
%>
</tbody>
</table>
</div>
<!-- Recent Errors -->
<h6 class="mt-4 mb-2">Recent Errors</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Type</th>
<th>Message</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No errors found</td></tr>")
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("<tr style='" & recentErrStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentErr("eventtime") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentErr("machinenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentErr("errortype") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(Left(rsRecentErr("errormessage") & "", 100)) & "</td>")
Response.Write("</tr>")
rsRecentErr.MoveNext
Loop
End If
rsRecentErr.Close
Set rsRecentErr = Nothing
%>
</tbody>
</table>
</div>
<!-- Connection Events -->
<h6 class="mt-4 mb-2">Connection Events by Machine</h6>
<div class="table-responsive mb-4">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Machine</th>
<th>Total Events</th>
<th>COM Ports Used</th>
<th>Last Event</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='4' class='text-muted text-center'>No connection events found</td></tr>")
Else
Do While Not rsConnMach.EOF
Response.Write("<tr>")
Response.Write("<td><a href='displayudc.asp?machine=" & Server.URLEncode(rsConnMach("machinenumber") & "") & "'>" & Server.HTMLEncode(rsConnMach("machinenumber") & "") & "</a></td>")
Response.Write("<td>" & rsConnMach("cnt") & "</td>")
Response.Write("<td>" & rsConnMach("ports") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsConnMach("lasttime") & "") & "</td>")
Response.Write("</tr>")
rsConnMach.MoveNext
Loop
End If
rsConnMach.Close
Set rsConnMach = Nothing
%>
</tbody>
</table>
</div>
<!-- Recent Connection Events -->
<h6 class="mt-4 mb-2">Recent Connection Events</h6>
<div class="table-responsive">
<table class="table table-hover table-striped table-sm">
<thead>
<tr>
<th>Time</th>
<th>Machine</th>
<th>Event</th>
<th>COM Port</th>
<th>Details</th>
</tr>
</thead>
<tbody>
<%
' 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("<tr><td colspan='5' class='text-muted text-center'>No connection events found</td></tr>")
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("<tr style='" & connStyle & "'>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentConn("eventtime") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentConn("machinenumber") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentConn("eventtype") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentConn("comport") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(rsRecentConn("details") & "") & "</td>")
Response.Write("</tr>")
rsRecentConn.MoveNext
Loop
End If
rsRecentConn.Close
Set rsRecentConn = Nothing
%>
</tbody>
</table>
</div>
</div>
<!-- Tab: Historical Trends (from summary tables) -->
<div class="tab-pane<%If activeTab="trends" Then Response.Write(" active")%>" id="trends">
<div class="alert mb-3" style="background-color: #e7f3ff; border: 1px solid #b6d4fe; color: #084298;">
<strong>Historical Data:</strong> This data comes from daily summaries and includes all historical data beyond the 90-day retention period. Individual measurements are aggregated into daily/weekly/monthly totals.
</div>
<!-- Charts Row 1: Monthly Trends -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-info text-white py-2">
Monthly Measurement Trend (12 Months)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyMeasChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-danger text-white py-2">
Monthly OOT Rate Trend
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyOOTChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row 2: Production and Response Times -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-success text-white py-2">
Monthly Production Trend (Parts)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyPartsChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-warning text-white py-2">
Monthly Avg Response Time (seconds)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyResponseChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row 3: Weekly and Machine Comparison -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-primary text-white py-2">
Weekly Measurement Trend (26 Weeks)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="weeklyMeasChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-secondary text-white py-2">
All-Time Machine Comparison (Top 15)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="machineHistChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row 4: CLM-Specific - Violations and Changeover -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header text-white py-2" style="background: linear-gradient(to right, #dc3545, #c82333);">
Monthly Parameter Violations (CLM)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyViolChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header text-white py-2" style="background: linear-gradient(to right, #17a2b8, #138496);">
Monthly Avg Changeover Time (minutes)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="monthlyChangeoverChart"></canvas>
</div>
</div>
</div>
</div>
</div>
<!-- Charts Row 5: Violations by Machine -->
<div class="row">
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header text-white py-2" style="background: linear-gradient(to right, #6f42c1, #5a32a3);">
Violations by Machine (All Time Top 10)
</div>
<div class="card-body">
<div style="height: 250px;">
<canvas id="violByMachineChart"></canvas>
</div>
</div>
</div>
</div>
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-dark text-white py-2">
CLM Data Notes
</div>
<div class="card-body">
<p><strong>Parameter Violations:</strong> Tracked when operators change machine parameters outside allowed limits during CLM runs. High violation counts may indicate calibration issues or training needs.</p>
<p><strong>Changeover Time:</strong> Time between consecutive part runs on the same machine. Helps identify efficiency opportunities and scheduling patterns.</p>
<p class="mb-0 text-muted"><small>Note: CLM data comes from JSON files in CLM_Data folder. Violations and changeover times are only tracked for CLM sessions, not UDC log sessions.</small></p>
</div>
</div>
</div>
</div>
<!-- Summary Table -->
<div class="card">
<div class="card-header bg-gradient-dark text-white py-2">
Monthly Summary Data
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-sm table-striped table-hover" id="monthlySummaryTable">
<thead class="thead-dark">
<tr>
<th>Month</th>
<th>Total Measurements</th>
<th>OOT Count</th>
<th>OOT Rate</th>
</tr>
</thead>
<tbody>
<%
Dim rsMonthlySummary
strSQL2 = "SELECT yearmonth, SUM(measurement_count) as total_meas, SUM(oot_count) as total_oot, " & _
"ROUND(SUM(oot_count)*100.0/NULLIF(SUM(measurement_count),0), 2) as oot_rate " & _
"FROM vwudcmeasurements_monthly "
If filterMachine <> "" Then
strSQL2 = strSQL2 & "WHERE machinenumber = '" & Replace(filterMachine, "'", "''") & "' "
End If
strSQL2 = strSQL2 & "GROUP BY yearmonth ORDER BY yearmonth DESC LIMIT 24"
Set rsMonthlySummary = objConn.Execute(strSQL2)
Do While Not rsMonthlySummary.EOF
Dim ootRateVal
If IsNull(rsMonthlySummary("oot_rate")) Then
ootRateVal = "0.00"
Else
ootRateVal = rsMonthlySummary("oot_rate") & ""
End If
Response.Write("<tr>")
Response.Write("<td>" & Server.HTMLEncode(rsMonthlySummary("yearmonth") & "") & "</td>")
Response.Write("<td>" & Server.HTMLEncode(FormatNumber(rsMonthlySummary("total_meas"), 0)) & "</td>")
Response.Write("<td>" & Server.HTMLEncode(FormatNumber(rsMonthlySummary("total_oot"), 0)) & "</td>")
Response.Write("<td>" & Server.HTMLEncode(ootRateVal) & "%</td>")
Response.Write("</tr>")
rsMonthlySummary.MoveNext
Loop
rsMonthlySummary.Close
Set rsMonthlySummary = Nothing
%>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div><!-- End container-fluid -->
</div><!-- End content-wrapper -->
<a href="javaScript:void();" class="back-to-top"><i class="fa fa-angle-double-up"></i></a>
<footer class="footer">
<div class="container"><div class="text-center"></div></div>
</footer>
</div><!-- End wrapper -->
<!-- JavaScript -->
<script src="assets/js/jquery.min.js"></script>
<script src="assets/js/popper.min.js"></script>
<script src="assets/js/bootstrap.min.js"></script>
<script src="assets/plugins/simplebar/js/simplebar.js"></script>
<script src="assets/js/sidebar-menu.js"></script>
<script src="assets/js/app-script.js"></script>
<script src="assets/plugins/Chart.js/Chart.min.js"></script>
<script>
// Tab persistence - update hidden input when tab is clicked
function setActiveTab(tabName) {
document.getElementById('activeTabInput').value = tabName;
}
// Copy current URL with filters to clipboard
function copyFilterLink(btn) {
var url = window.location.href;
var temp = document.createElement('textarea');
temp.value = url;
document.body.appendChild(temp);
temp.select();
document.execCommand('copy');
document.body.removeChild(temp);
// Brief feedback
var original = btn.innerHTML;
btn.innerHTML = 'Copied!';
setTimeout(function() { btn.innerHTML = original; }, 1000);
}
// Dashboard Charts
$(function() {
// Chart 1: Production Trend (Line Chart)
var ctxProd = document.getElementById('productionChart').getContext('2d');
new Chart(ctxProd, {
type: 'line',
data: {
labels: [<%=prodLabels%>],
datasets: [{
label: 'Parts Produced',
data: [<%=prodData%>],
backgroundColor: 'rgba(102, 126, 234, 0.2)',
borderColor: 'rgba(102, 126, 234, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(102, 126, 234, 1)',
pointRadius: 4,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true } }],
xAxes: [{ gridLines: { display: false } }]
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel + ' parts';
}
}
}
}
});
// Chart 2: OOT Rate Trend (Line Chart)
var ctxOOT = document.getElementById('ootChart').getContext('2d');
new Chart(ctxOOT, {
type: 'line',
data: {
labels: [<%=ootLabels%>],
datasets: [{
label: 'OOT Rate %',
data: [<%=ootRateData%>],
backgroundColor: 'rgba(220, 53, 69, 0.2)',
borderColor: 'rgba(220, 53, 69, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(220, 53, 69, 1)',
pointRadius: 4,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true, callback: function(value) { return value + '%'; } } }],
xAxes: [{ gridLines: { display: false } }]
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel + '% OOT';
}
}
}
}
});
// Chart 3: Machine Utilization (Horizontal Bar Chart)
var ctxMach = document.getElementById('machineChart').getContext('2d');
new Chart(ctxMach, {
type: 'horizontalBar',
data: {
labels: [<%=machLabels%>],
datasets: [{
label: 'Runtime Hours',
data: [<%=machData%>],
backgroundColor: 'rgba(23, 162, 184, 0.7)',
borderColor: 'rgba(23, 162, 184, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
xAxes: [{ ticks: { beginAtZero: true } }],
yAxes: [{ gridLines: { display: false } }]
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.xLabel + ' hours';
}
}
}
}
});
// Chart 4: Top Operators (Horizontal Bar Chart)
var ctxOps = document.getElementById('operatorChart').getContext('2d');
new Chart(ctxOps, {
type: 'horizontalBar',
data: {
labels: [<%=opLabels%>],
datasets: [{
label: 'Parts Produced',
data: [<%=opData%>],
backgroundColor: 'rgba(40, 167, 69, 0.7)',
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
xAxes: [{ ticks: { beginAtZero: true } }],
yAxes: [{ gridLines: { display: false } }]
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.xLabel + ' parts';
}
}
}
}
});
// ========================================
// Historical Trends Charts (from summaries)
// ========================================
// Monthly Measurement Trend
var ctxMonthlyMeas = document.getElementById('monthlyMeasChart');
if (ctxMonthlyMeas) {
new Chart(ctxMonthlyMeas.getContext('2d'), {
type: 'bar',
data: {
labels: [<%=monthlyLabels%>],
datasets: [{
label: 'Measurements',
data: [<%=monthlyMeasData%>],
backgroundColor: 'rgba(23, 162, 184, 0.7)',
borderColor: 'rgba(23, 162, 184, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Monthly OOT Rate Trend
var ctxMonthlyOOT = document.getElementById('monthlyOOTChart');
if (ctxMonthlyOOT) {
new Chart(ctxMonthlyOOT.getContext('2d'), {
type: 'line',
data: {
labels: [<%=monthlyLabels%>],
datasets: [{
label: 'OOT Rate %',
data: [<%=monthlyOOTRate%>],
backgroundColor: 'rgba(220, 53, 69, 0.2)',
borderColor: 'rgba(220, 53, 69, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(220, 53, 69, 1)',
pointRadius: 4,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + '%'; } } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Weekly Measurement Trend
var ctxWeeklyMeas = document.getElementById('weeklyMeasChart');
if (ctxWeeklyMeas) {
new Chart(ctxWeeklyMeas.getContext('2d'), {
type: 'line',
data: {
labels: [<%=weeklyLabels%>],
datasets: [{
label: 'Measurements',
data: [<%=weeklyMeasData%>],
backgroundColor: 'rgba(102, 126, 234, 0.2)',
borderColor: 'rgba(102, 126, 234, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(102, 126, 234, 1)',
pointRadius: 3,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Machine Historical Comparison
var ctxMachHist = document.getElementById('machineHistChart');
if (ctxMachHist) {
new Chart(ctxMachHist.getContext('2d'), {
type: 'horizontalBar',
data: {
labels: [<%=machHistLabels%>],
datasets: [{
label: 'Total Measurements',
data: [<%=machHistMeas%>],
backgroundColor: 'rgba(108, 117, 125, 0.7)',
borderColor: 'rgba(108, 117, 125, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
xAxes: [{ ticks: { beginAtZero: true } }],
yAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Monthly Parts Production Trend
var ctxMonthlyParts = document.getElementById('monthlyPartsChart');
if (ctxMonthlyParts) {
new Chart(ctxMonthlyParts.getContext('2d'), {
type: 'bar',
data: {
labels: [<%=monthlyPartsLabels%>],
datasets: [{
label: 'Parts Produced',
data: [<%=monthlyPartsData%>],
backgroundColor: 'rgba(40, 167, 69, 0.7)',
borderColor: 'rgba(40, 167, 69, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Monthly Response Time Trend
var ctxMonthlyResp = document.getElementById('monthlyResponseChart');
if (ctxMonthlyResp) {
new Chart(ctxMonthlyResp.getContext('2d'), {
type: 'line',
data: {
labels: [<%=monthlyRespLabels%>],
datasets: [{
label: 'Avg Response (sec)',
data: [<%=monthlyRespData%>],
backgroundColor: 'rgba(255, 193, 7, 0.2)',
borderColor: 'rgba(255, 193, 7, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(255, 193, 7, 1)',
pointRadius: 4,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + 's'; } } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// ========================================
// CLM-Specific Charts
// ========================================
// Monthly Violations Trend (CLM)
var ctxMonthlyViol = document.getElementById('monthlyViolChart');
if (ctxMonthlyViol) {
new Chart(ctxMonthlyViol.getContext('2d'), {
type: 'bar',
data: {
labels: [<%=monthlyViolLabels%>],
datasets: [{
label: 'Violations',
data: [<%=monthlyViolData%>],
backgroundColor: 'rgba(220, 53, 69, 0.7)',
borderColor: 'rgba(220, 53, 69, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Monthly Changeover Time Trend
var ctxMonthlyChg = document.getElementById('monthlyChangeoverChart');
if (ctxMonthlyChg) {
new Chart(ctxMonthlyChg.getContext('2d'), {
type: 'line',
data: {
labels: [<%=monthlyChgLabels%>],
datasets: [{
label: 'Avg Changeover (min)',
data: [<%=monthlyChgData%>],
backgroundColor: 'rgba(23, 162, 184, 0.2)',
borderColor: 'rgba(23, 162, 184, 1)',
borderWidth: 2,
pointBackgroundColor: 'rgba(23, 162, 184, 1)',
pointRadius: 4,
fill: true
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
yAxes: [{ ticks: { beginAtZero: true, callback: function(v) { return v + ' min'; } } }],
xAxes: [{ gridLines: { display: false } }]
}
}
});
}
// Violations by Machine (Horizontal Bar)
var ctxViolMach = document.getElementById('violByMachineChart');
if (ctxViolMach) {
new Chart(ctxViolMach.getContext('2d'), {
type: 'horizontalBar',
data: {
labels: [<%=violMachLabels%>],
datasets: [{
label: 'Violations',
data: [<%=violMachData%>],
backgroundColor: 'rgba(111, 66, 193, 0.7)',
borderColor: 'rgba(111, 66, 193, 1)',
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
legend: { display: false },
scales: {
xAxes: [{ ticks: { beginAtZero: true } }],
yAxes: [{ gridLines: { display: false } }]
}
}
});
}
});
</script>
</body>
</html>
<%
objConn.Close
%>