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>
This commit is contained in:
cproudlock
2025-12-17 13:47:56 -05:00
parent a5b4013949
commit a4096ace94
25 changed files with 1744 additions and 355 deletions

View File

@@ -53,17 +53,44 @@ Dim theme, strSQL, rs, objConn
If filterEnd = "" Then filterEnd = Year(Date()) & "-" & Right("0" & Month(Date()), 2) & "-" & Right("0" & Day(Date()), 2)
' Period shortcuts
Dim periodLabel
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
filterStart = Year(DateAdd("d", -7, Date())) & "-" & Right("0" & Month(DateAdd("d", -7, Date())), 2) & "-" & Right("0" & Day(DateAdd("d", -7, Date())), 2)
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
filterStart = Year(DateAdd("d", -30, Date())) & "-" & Right("0" & Month(DateAdd("d", -30, Date())), 2) & "-" & Right("0" & Day(DateAdd("d", -30, Date())), 2)
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
@@ -99,8 +126,11 @@ Dim theme, strSQL, rs, objConn
<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="week" <%If periodFilter="week" Then Response.Write("selected")%>>This Week</option>
<option value="month" <%If periodFilter="month" Then Response.Write("selected")%>>This Month</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">
@@ -177,18 +207,19 @@ Set rsBadges = Nothing
%>
</select>
</div>
<div class="col-md-2 d-flex align-items-end">
<button type="submit" class="btn btn-primary btn-sm mr-2">Filter</button>
<a href="displayudc.asp" class="btn btn-secondary btn-sm">Clear</a>
</div>
</div>
<div class="row mt-2">
<div class="col-12">
<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>
@@ -442,6 +473,278 @@ 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 -->
@@ -451,10 +754,10 @@ If opData = "" Then opData = "0"
<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')"><i class="zmdi zmdi-chart"></i> Dashboard</a>
<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')"><i class="zmdi zmdi-dot-circle text-success"></i> Live Activity</a>
<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>
@@ -483,19 +786,22 @@ If opData = "" Then opData = "0"
<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"><i class="zmdi zmdi-chart"></i> UDC Performance Dashboard</h5>
<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">
<i class="zmdi zmdi-trending-up"></i> Production Trend
Production Trend
</div>
<div class="card-body">
<div style="height: 220px;">
@@ -507,7 +813,7 @@ If opData = "" Then opData = "0"
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-danger text-white py-2">
<i class="zmdi zmdi-alert-triangle"></i> OOT Rate Trend
OOT Rate Trend
</div>
<div class="card-body">
<div style="height: 220px;">
@@ -523,7 +829,7 @@ If opData = "" Then opData = "0"
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-info text-white py-2">
<i class="zmdi zmdi-time"></i> Machine Utilization (Hours)
Machine Utilization (Hours)
</div>
<div class="card-body">
<div style="height: 220px;">
@@ -535,7 +841,7 @@ If opData = "" Then opData = "0"
<div class="col-lg-6 mb-3">
<div class="card">
<div class="card-header bg-gradient-success text-white py-2">
<i class="zmdi zmdi-accounts"></i> Top Operators (Parts)
Top Operators (Parts)
</div>
<div class="card-body">
<div style="height: 220px;">
@@ -549,7 +855,7 @@ If opData = "" Then opData = "0"
<!-- Tab: Live Activity -->
<div class="tab-pane<%If activeTab="liveactivity" Then Response.Write(" active")%>" id="liveactivity">
<h5 class="mb-3"><i class="zmdi zmdi-dot-circle text-success"></i> Active Machines <span class="badge badge-success">Live</span></h5>
<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
@@ -569,7 +875,7 @@ activeCount = 0
If rsActive.EOF Then
%>
<div class="alert alert-secondary text-center">
<i class="zmdi zmdi-info-outline"></i> No active jobs detected
No active jobs detected
</div>
<%
Else
@@ -2001,6 +2307,204 @@ Set rsRecentConn = Nothing
</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>
@@ -2032,6 +2536,22 @@ 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)
@@ -2163,6 +2683,260 @@ $(function() {
}
}
});
// ========================================
// 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>