1753 lines
No EOL
56 KiB
Text
1753 lines
No EOL
56 KiB
Text
@* Views/Admin/SurveyAnalysis/BatchAnalysisProgress.cshtml *@
|
|
|
|
@{
|
|
ViewData["Title"] = $"Batch Analysis - {ViewBag.QuestionnaireName}";
|
|
}
|
|
|
|
@section Styles {
|
|
<style>
|
|
@@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&family=Space+Grotesk:wght@300;400;500;600;700&display=swap');
|
|
|
|
:root {
|
|
--neon-blue: #60a5fa;
|
|
--neon-purple: #c084fc;
|
|
--neon-green: #34d399;
|
|
--neon-pink: #f472b6;
|
|
--neon-yellow: #fbbf24;
|
|
--neon-red: #f87171;
|
|
--neon-cyan: #22d3ee;
|
|
--neon-orange: #fb923c;
|
|
--dark-900: #0f172a;
|
|
--dark-800: #1e293b;
|
|
--dark-700: #334155;
|
|
--dark-600: #475569;
|
|
--dark-500: #64748b;
|
|
--dark-400: #94a3b8;
|
|
--dark-300: #cbd5e1;
|
|
--dark-200: #e2e8f0;
|
|
--dark-100: #f1f5f9;
|
|
--glass-bg: rgba(255, 255, 255, 0.05);
|
|
--glass-border: rgba(255, 255, 255, 0.1);
|
|
--glass-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
|
--font-main: 'Space Grotesk', sans-serif;
|
|
--font-mono: 'JetBrains Mono', monospace;
|
|
--success-gradient: linear-gradient(135deg, var(--neon-green), var(--neon-cyan));
|
|
--warning-gradient: linear-gradient(135deg, var(--neon-yellow), var(--neon-orange));
|
|
--danger-gradient: linear-gradient(135deg, var(--neon-red), #dc2626);
|
|
--info-gradient: linear-gradient(135deg, var(--neon-blue), var(--neon-purple));
|
|
--primary-gradient: linear-gradient(135deg, var(--neon-blue), var(--neon-cyan));
|
|
}
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
body {
|
|
font-family: var(--font-main);
|
|
background: var(--dark-900);
|
|
color: #e2e8f0;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
.nexgen-batch-dashboard {
|
|
min-height: 100vh;
|
|
position: relative;
|
|
}
|
|
|
|
/* Dynamic Background */
|
|
.bg-pattern {
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100vw;
|
|
height: 100vh;
|
|
z-index: -1;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.grid-overlay {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background-image: linear-gradient(rgba(34, 211, 238, 0.1) 1px, transparent 1px), linear-gradient(90deg, rgba(34, 211, 238, 0.1) 1px, transparent 1px);
|
|
background-size: 60px 60px;
|
|
animation: gridMove 20s linear infinite;
|
|
}
|
|
|
|
.gradient-mesh {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: radial-gradient(circle at 20% 20%, rgba(34, 211, 238, 0.15) 0%, transparent 50%), radial-gradient(circle at 80% 60%, rgba(96, 165, 250, 0.15) 0%, transparent 50%), radial-gradient(circle at 40% 80%, rgba(192, 132, 252, 0.15) 0%, transparent 50%);
|
|
animation: meshShift 15s ease-in-out infinite;
|
|
}
|
|
|
|
/* Top Navigation */
|
|
.top-nav {
|
|
position: relative;
|
|
z-index: 100;
|
|
padding: 1rem 0;
|
|
background: rgba(15, 23, 42, 0.8);
|
|
backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid rgba(34, 211, 238, 0.2);
|
|
}
|
|
|
|
.nav-container {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 0 2rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 3rem;
|
|
}
|
|
|
|
.nav-brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.brand-icon {
|
|
width: 40px;
|
|
height: 40px;
|
|
background: linear-gradient(135deg, var(--neon-cyan), var(--neon-blue));
|
|
border-radius: 8px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
color: white;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.brand-name {
|
|
font-family: var(--font-mono);
|
|
font-weight: 700;
|
|
font-size: 1.1rem;
|
|
letter-spacing: 0.1em;
|
|
color: #e2e8f0;
|
|
}
|
|
|
|
.brand-version {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.7rem;
|
|
color: var(--neon-cyan);
|
|
background: rgba(34, 211, 238, 0.1);
|
|
padding: 0.2rem 0.5rem;
|
|
border-radius: 4px;
|
|
border: 1px solid rgba(34, 211, 238, 0.3);
|
|
}
|
|
|
|
.nav-center {
|
|
flex: 1;
|
|
display: flex;
|
|
justify-content: center;
|
|
}
|
|
|
|
.breadcrumb-nexgen {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.crumb {
|
|
color: var(--dark-400);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.crumb:hover {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.crumb.active {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.breadcrumb-nexgen i {
|
|
color: var(--dark-500);
|
|
font-size: 0.6rem;
|
|
}
|
|
|
|
.nav-actions {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.nav-btn {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.6rem 1.2rem;
|
|
background: var(--glass-bg);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 8px;
|
|
color: #e2e8f0;
|
|
font-size: 0.8rem;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
backdrop-filter: blur(10px);
|
|
text-decoration: none;
|
|
}
|
|
|
|
.nav-btn:hover {
|
|
background: rgba(34, 211, 238, 0.1);
|
|
border-color: rgba(34, 211, 238, 0.3);
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
/* Hero Section */
|
|
.hero-nexgen {
|
|
padding: 4rem 0 2rem;
|
|
text-align: center;
|
|
position: relative;
|
|
z-index: 10;
|
|
}
|
|
|
|
.hero-badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
padding: 0.5rem 1.2rem;
|
|
background: rgba(34, 211, 238, 0.1);
|
|
border: 1px solid rgba(34, 211, 238, 0.3);
|
|
border-radius: 50px;
|
|
margin-bottom: 2rem;
|
|
font-family: var(--font-mono);
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.1em;
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.badge-dot {
|
|
width: 6px;
|
|
height: 6px;
|
|
background: var(--neon-cyan);
|
|
border-radius: 50%;
|
|
animation: pulse 2s infinite;
|
|
}
|
|
|
|
.hero-title {
|
|
font-size: 3.5rem;
|
|
font-weight: 700;
|
|
line-height: 1.1;
|
|
margin-bottom: 1.5rem;
|
|
color: #ffffff;
|
|
}
|
|
|
|
.title-gradient {
|
|
background: linear-gradient(135deg, var(--neon-cyan), var(--neon-blue), var(--neon-purple));
|
|
-webkit-background-clip: text;
|
|
-webkit-text-fill-color: transparent;
|
|
background-clip: text;
|
|
}
|
|
|
|
.hero-description {
|
|
font-size: 1.1rem;
|
|
color: var(--dark-300);
|
|
max-width: 600px;
|
|
margin: 0 auto 2rem;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
/* Processing Status Card */
|
|
.processing-card {
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(20px);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
box-shadow: var(--glass-shadow);
|
|
margin-bottom: 3rem;
|
|
position: relative;
|
|
}
|
|
|
|
.processing-header {
|
|
background: var(--primary-gradient);
|
|
padding: 2rem;
|
|
position: relative;
|
|
}
|
|
|
|
.processing-header::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%);
|
|
}
|
|
|
|
.header-content {
|
|
position: relative;
|
|
z-index: 2;
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
}
|
|
|
|
.header-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.header-title {
|
|
font-family: var(--font-mono);
|
|
font-size: 1.3rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.05em;
|
|
color: white;
|
|
margin-bottom: 0.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.header-subtitle {
|
|
color: rgba(255, 255, 255, 0.8);
|
|
font-size: 0.9rem;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.status-badge {
|
|
background: rgba(255, 255, 255, 0.2);
|
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
border-radius: 20px;
|
|
padding: 0.6rem 1.2rem;
|
|
font-family: var(--font-mono);
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.1em;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.status-badge.processing {
|
|
background: rgba(251, 191, 36, 0.2);
|
|
border-color: var(--neon-yellow);
|
|
color: var(--neon-yellow);
|
|
}
|
|
|
|
.status-badge.success {
|
|
background: rgba(52, 211, 153, 0.2);
|
|
border-color: var(--neon-green);
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.status-badge.error {
|
|
background: rgba(248, 113, 113, 0.2);
|
|
border-color: var(--neon-red);
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
/* Progress Section */
|
|
.progress-section {
|
|
padding: 2rem;
|
|
}
|
|
|
|
.progress-header {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.progress-title {
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
font-size: 1.1rem;
|
|
}
|
|
|
|
.progress-percentage {
|
|
font-family: var(--font-mono);
|
|
font-weight: 700;
|
|
font-size: 1.2rem;
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.progress-container {
|
|
position: relative;
|
|
margin-bottom: 1.5rem;
|
|
}
|
|
|
|
.progress-bar-nexgen {
|
|
height: 20px;
|
|
background: rgba(255, 255, 255, 0.1);
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
position: relative;
|
|
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.progress-fill {
|
|
height: 100%;
|
|
background: var(--primary-gradient);
|
|
border-radius: 10px;
|
|
transition: width 0.3s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.progress-fill.animated {
|
|
background: linear-gradient(90deg, var(--neon-cyan) 0%, var(--neon-blue) 25%, var(--neon-cyan) 50%, var(--neon-blue) 75%, var(--neon-cyan) 100%);
|
|
background-size: 200% 100%;
|
|
animation: progressShimmer 2s linear infinite;
|
|
}
|
|
|
|
.progress-fill.complete {
|
|
background: var(--success-gradient);
|
|
animation: none;
|
|
}
|
|
|
|
.progress-text {
|
|
position: absolute;
|
|
top: 50%;
|
|
left: 50%;
|
|
transform: translate(-50%, -50%);
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
font-weight: 700;
|
|
color: white;
|
|
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
|
|
}
|
|
|
|
.progress-info {
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.progress-count {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
color: var(--dark-300);
|
|
}
|
|
|
|
.estimated-time {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
color: var(--dark-300);
|
|
}
|
|
|
|
/* Pipeline Section */
|
|
.pipeline-section {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 2rem;
|
|
padding: 0 2rem 2rem;
|
|
}
|
|
|
|
.pipeline-container {
|
|
background: rgba(255, 255, 255, 0.03);
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
border-radius: 12px;
|
|
padding: 1.5rem;
|
|
}
|
|
|
|
.pipeline-title {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.05em;
|
|
color: #ffffff;
|
|
margin-bottom: 1.5rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.pipeline-title i {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.pipeline-steps {
|
|
list-style: none;
|
|
padding: 0;
|
|
}
|
|
|
|
.pipeline-step {
|
|
padding: 0.8rem 0;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
color: var(--dark-400);
|
|
transition: all 0.3s ease;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.pipeline-step.active {
|
|
color: var(--neon-blue);
|
|
}
|
|
|
|
.pipeline-step.completed {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.step-icon {
|
|
width: 20px;
|
|
text-align: center;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
.pipeline-step.active .step-icon {
|
|
animation: spin 1s linear infinite;
|
|
}
|
|
|
|
.pipeline-step.completed .step-icon {
|
|
animation: checkPulse 0.5s ease-in-out;
|
|
}
|
|
|
|
/* Statistics Grid */
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 1rem;
|
|
}
|
|
|
|
.stat-card {
|
|
background: rgba(255, 255, 255, 0.03);
|
|
border: 1px solid rgba(255, 255, 255, 0.08);
|
|
border-radius: 12px;
|
|
padding: 1.5rem;
|
|
text-align: center;
|
|
transition: all 0.3s ease;
|
|
position: relative;
|
|
overflow: hidden;
|
|
}
|
|
|
|
.stat-card:hover {
|
|
transform: translateY(-2px);
|
|
background: rgba(255, 255, 255, 0.05);
|
|
}
|
|
|
|
.stat-icon {
|
|
font-size: 1.5rem;
|
|
margin-bottom: 0.8rem;
|
|
}
|
|
|
|
.stat-card.positive .stat-icon {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.stat-card.negative .stat-icon {
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
.stat-card.low-risk .stat-icon {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.stat-card.high-risk .stat-icon {
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
.stat-value {
|
|
font-family: var(--font-mono);
|
|
font-size: 1.8rem;
|
|
font-weight: 700;
|
|
color: #ffffff;
|
|
margin-bottom: 0.5rem;
|
|
line-height: 1;
|
|
}
|
|
|
|
.stat-label {
|
|
font-size: 0.7rem;
|
|
color: var(--dark-400);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
/* Control Footer */
|
|
.control-footer {
|
|
padding: 1.5rem 2rem;
|
|
background: rgba(30, 41, 59, 0.5);
|
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
}
|
|
|
|
.current-status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
color: var(--dark-300);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.control-buttons {
|
|
display: flex;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.btn-nexgen {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.6rem;
|
|
padding: 0.8rem 1.5rem;
|
|
border-radius: 8px;
|
|
font-family: var(--font-mono);
|
|
font-size: 0.7rem;
|
|
font-weight: 600;
|
|
letter-spacing: 0.05em;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
border: 1px solid;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.btn-nexgen.success {
|
|
background: rgba(52, 211, 153, 0.1);
|
|
border-color: rgba(52, 211, 153, 0.3);
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.btn-nexgen.success:hover {
|
|
background: rgba(52, 211, 153, 0.2);
|
|
color: var(--neon-green);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn-nexgen.danger {
|
|
background: rgba(248, 113, 113, 0.1);
|
|
border-color: rgba(248, 113, 113, 0.3);
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
.btn-nexgen.danger:hover {
|
|
background: rgba(248, 113, 113, 0.2);
|
|
color: var(--neon-red);
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn-nexgen:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
/* Results Section */
|
|
.results-section {
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(20px);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
box-shadow: var(--glass-shadow);
|
|
margin-bottom: 3rem;
|
|
}
|
|
|
|
.results-header {
|
|
background: var(--success-gradient);
|
|
padding: 2rem;
|
|
position: relative;
|
|
}
|
|
|
|
.results-header::before {
|
|
content: '';
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
background: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, transparent 50%);
|
|
}
|
|
|
|
.results-title {
|
|
position: relative;
|
|
z-index: 2;
|
|
font-family: var(--font-mono);
|
|
font-size: 1.3rem;
|
|
font-weight: 700;
|
|
letter-spacing: 0.05em;
|
|
color: white;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.results-body {
|
|
padding: 2rem;
|
|
}
|
|
|
|
.results-stats {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
gap: 2rem;
|
|
margin-bottom: 2rem;
|
|
text-align: center;
|
|
}
|
|
|
|
.result-stat {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.result-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 50%;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
color: white;
|
|
}
|
|
|
|
.result-stat.processed .result-icon {
|
|
background: var(--info-gradient);
|
|
}
|
|
|
|
.result-stat.high-risk .result-icon {
|
|
background: var(--danger-gradient);
|
|
}
|
|
|
|
.result-stat.positive .result-icon {
|
|
background: var(--success-gradient);
|
|
}
|
|
|
|
.result-stat.time .result-icon {
|
|
background: var(--primary-gradient);
|
|
}
|
|
|
|
.result-value {
|
|
font-family: var(--font-mono);
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: #ffffff;
|
|
line-height: 1;
|
|
}
|
|
|
|
.result-label {
|
|
font-size: 0.8rem;
|
|
color: var(--dark-400);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.completion-alert {
|
|
background: rgba(52, 211, 153, 0.1);
|
|
border: 1px solid rgba(52, 211, 153, 0.3);
|
|
border-radius: 12px;
|
|
padding: 2rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.alert-title {
|
|
font-family: var(--font-mono);
|
|
font-size: 1.1rem;
|
|
font-weight: 700;
|
|
color: var(--neon-green);
|
|
margin-bottom: 1rem;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.alert-description {
|
|
color: var(--dark-200);
|
|
line-height: 1.6;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.result-actions {
|
|
display: flex;
|
|
justify-content: center;
|
|
gap: 1rem;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.btn-nexgen.primary {
|
|
background: var(--info-gradient);
|
|
border-color: transparent;
|
|
color: white;
|
|
}
|
|
|
|
.btn-nexgen.primary:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 10px 20px rgba(96, 165, 250, 0.3);
|
|
color: white;
|
|
}
|
|
|
|
/* Processing Log */
|
|
.log-section {
|
|
background: var(--glass-bg);
|
|
backdrop-filter: blur(20px);
|
|
border: 1px solid var(--glass-border);
|
|
border-radius: 20px;
|
|
overflow: hidden;
|
|
box-shadow: var(--glass-shadow);
|
|
}
|
|
|
|
.log-header {
|
|
padding: 1.5rem 2rem;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
|
display: flex;
|
|
justify-content: between;
|
|
align-items: center;
|
|
}
|
|
|
|
.log-title {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: #ffffff;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.log-title i {
|
|
color: var(--neon-purple);
|
|
}
|
|
|
|
.log-toggle {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0.5rem;
|
|
padding: 0.5rem 1rem;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
border-radius: 6px;
|
|
color: var(--dark-300);
|
|
font-size: 0.8rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.log-toggle:hover {
|
|
background: rgba(255, 255, 255, 0.1);
|
|
color: #ffffff;
|
|
}
|
|
|
|
.log-container {
|
|
background: var(--dark-800);
|
|
padding: 1.5rem;
|
|
max-height: 300px;
|
|
overflow-y: auto;
|
|
border-top: 1px solid rgba(255, 255, 255, 0.08);
|
|
}
|
|
|
|
.log-entry {
|
|
font-family: var(--font-mono);
|
|
font-size: 0.8rem;
|
|
line-height: 1.4;
|
|
margin-bottom: 0.5rem;
|
|
padding: 0.2rem 0;
|
|
animation: fadeInUp 0.3s ease-out;
|
|
}
|
|
|
|
.log-entry.info {
|
|
color: var(--neon-cyan);
|
|
}
|
|
|
|
.log-entry.success {
|
|
color: var(--neon-green);
|
|
}
|
|
|
|
.log-entry.warning {
|
|
color: var(--neon-yellow);
|
|
}
|
|
|
|
.log-entry.error {
|
|
color: var(--neon-red);
|
|
}
|
|
|
|
.timestamp {
|
|
color: var(--dark-400);
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* Animations */
|
|
@@keyframes gridMove {
|
|
0%
|
|
|
|
{
|
|
transform: translate(0, 0);
|
|
}
|
|
|
|
100% {
|
|
transform: translate(60px, 60px);
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes meshShift {
|
|
0%, 100%
|
|
|
|
{
|
|
filter: hue-rotate(0deg);
|
|
transform: scale(1);
|
|
}
|
|
|
|
50% {
|
|
filter: hue-rotate(30deg);
|
|
transform: scale(1.05);
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes pulse {
|
|
0%, 100%
|
|
|
|
{
|
|
opacity: 1;
|
|
transform: scale(1);
|
|
}
|
|
|
|
50% {
|
|
opacity: 0.7;
|
|
transform: scale(1.1);
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes progressShimmer {
|
|
0%
|
|
|
|
{
|
|
background-position: -200% 0;
|
|
}
|
|
|
|
100% {
|
|
background-position: 200% 0;
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes spin {
|
|
from
|
|
|
|
{
|
|
transform: rotate(0deg);
|
|
}
|
|
|
|
to {
|
|
transform: rotate(360deg);
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes checkPulse {
|
|
0%
|
|
|
|
{
|
|
transform: scale(1);
|
|
}
|
|
|
|
50% {
|
|
transform: scale(1.2);
|
|
}
|
|
|
|
100% {
|
|
transform: scale(1);
|
|
}
|
|
|
|
}
|
|
|
|
@@keyframes fadeInUp {
|
|
from
|
|
|
|
{
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
|
|
}
|
|
|
|
/* Responsive Design */
|
|
@@media (max-width: 1200px) {
|
|
.pipeline-section
|
|
|
|
{
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
}
|
|
|
|
@@media (max-width: 768px) {
|
|
.nav-container
|
|
|
|
{
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.nav-center {
|
|
order: 3;
|
|
flex-basis: 100%;
|
|
justify-content: flex-start;
|
|
}
|
|
|
|
.hero-title {
|
|
font-size: 2.5rem;
|
|
}
|
|
|
|
.header-content {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.stats-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.results-stats {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
|
|
.control-footer {
|
|
flex-direction: column;
|
|
gap: 1rem;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.result-actions {
|
|
flex-direction: column;
|
|
align-items: stretch;
|
|
}
|
|
|
|
}
|
|
|
|
@@media (max-width: 480px) {
|
|
.processing-card, .results-section, .log-section
|
|
|
|
{
|
|
margin-left: 1rem;
|
|
margin-right: 1rem;
|
|
}
|
|
|
|
.results-stats {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
}
|
|
|
|
/* Print Styles */
|
|
@@media print {
|
|
.bg-pattern, .top-nav, .btn-nexgen, .log-section
|
|
|
|
{
|
|
display: none !important;
|
|
}
|
|
|
|
.processing-card,
|
|
.results-section {
|
|
break-inside: avoid;
|
|
border: 1px solid #333;
|
|
background: white;
|
|
color: black;
|
|
}
|
|
|
|
.nexgen-batch-dashboard {
|
|
background: white;
|
|
}
|
|
|
|
}
|
|
|
|
/* Accessibility */
|
|
@@media (prefers-reduced-motion: reduce) {
|
|
*, *::before, *::after
|
|
|
|
{
|
|
animation-duration: 0.01ms !important;
|
|
animation-iteration-count: 1 !important;
|
|
transition-duration: 0.01ms !important;
|
|
}
|
|
|
|
}
|
|
|
|
/* High Contrast Mode */
|
|
@@media (prefers-contrast: high) {
|
|
: root
|
|
|
|
{
|
|
--neon-cyan: #00e5ff;
|
|
--neon-blue: #4d9fff;
|
|
--neon-green: #4dff88;
|
|
--dark-300: #ffffff;
|
|
--dark-400: #cccccc;
|
|
}
|
|
|
|
.processing-card,
|
|
.results-section,
|
|
.log-section {
|
|
border-width: 2px;
|
|
}
|
|
|
|
}
|
|
</style>
|
|
}
|
|
|
|
<div class="nexgen-batch-dashboard">
|
|
<!-- Dynamic Background -->
|
|
<div class="bg-pattern">
|
|
<div class="grid-overlay"></div>
|
|
<div class="gradient-mesh"></div>
|
|
</div>
|
|
|
|
<!-- Top Navigation Bar -->
|
|
<nav class="top-nav">
|
|
<div class="nav-container">
|
|
<div class="nav-brand">
|
|
<div class="brand-icon">
|
|
<i class="fas fa-layer-group"></i>
|
|
</div>
|
|
<div class="brand-text">
|
|
<span class="brand-name">BATCH PROCESSOR</span>
|
|
<span class="brand-version">v1.0</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="nav-center">
|
|
<nav class="breadcrumb-nexgen">
|
|
<a href="@Url.Action("Index")" class="crumb">
|
|
<i class="fas fa-brain"></i> ANALYSIS DASHBOARD
|
|
</a>
|
|
<i class="fas fa-chevron-right"></i>
|
|
<a href="@Url.Action("AnalyzeQuestionnaire", new { id = ViewBag.QuestionnaireId })" class="crumb">
|
|
@ViewBag.QuestionnaireName?.ToUpper()
|
|
</a>
|
|
<i class="fas fa-chevron-right"></i>
|
|
<span class="crumb active">BATCH ANALYSIS</span>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="nav-actions">
|
|
<button type="button" class="nav-btn" onclick="goBack()">
|
|
<i class="fas fa-arrow-left"></i>
|
|
<span>Back to Analysis</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<!-- Hero Section -->
|
|
<section class="hero-nexgen">
|
|
<div class="container-fluid">
|
|
<div class="hero-content">
|
|
<div class="hero-badge">
|
|
<span class="badge-dot"></span>
|
|
<span>AI BATCH PROCESSING SYSTEM</span>
|
|
</div>
|
|
<h1 class="hero-title">
|
|
Batch AI
|
|
<span class="title-gradient">Analysis</span>
|
|
Processing
|
|
</h1>
|
|
<p class="hero-description">
|
|
Processing @ViewBag.TotalRequests mental health survey responses using advanced neural networks
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Main Content -->
|
|
<main class="main-content">
|
|
<div class="container-fluid">
|
|
<!-- Processing Status Card -->
|
|
<div class="processing-card">
|
|
<div class="processing-header">
|
|
<div class="header-content">
|
|
<div class="header-info">
|
|
<h2 class="header-title">
|
|
<i class="fas fa-cogs"></i>
|
|
AI Analysis in Progress
|
|
</h2>
|
|
<p class="header-subtitle">Analyzing responses using Azure Language Service and OpenAI</p>
|
|
</div>
|
|
<div id="statusBadge" class="status-badge">
|
|
<i class="fas fa-clock"></i> INITIALIZING...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="progress-section">
|
|
<div class="progress-header">
|
|
<div class="progress-title">Analysis Progress</div>
|
|
<div id="progressPercentage" class="progress-percentage">0%</div>
|
|
</div>
|
|
|
|
<div class="progress-container">
|
|
<div class="progress-bar-nexgen">
|
|
<div id="progressBar" class="progress-fill animated" style="width: 0%">
|
|
<div id="progressText" class="progress-text">Starting...</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="progress-info">
|
|
<div class="progress-count">
|
|
<span id="processedCount">0</span> of @ViewBag.TotalRequests responses processed
|
|
</div>
|
|
<div id="estimatedTime" class="estimated-time">
|
|
Estimated time: Calculating...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pipeline-section">
|
|
<div class="pipeline-container">
|
|
<h3 class="pipeline-title">
|
|
<i class="fas fa-list-check"></i>
|
|
Processing Pipeline
|
|
</h3>
|
|
<ul class="pipeline-steps">
|
|
<li id="step1" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle-notch"></i>
|
|
</div>
|
|
<span>Connecting to Azure AI services...</span>
|
|
</li>
|
|
<li id="step2" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Anonymizing personal information...</span>
|
|
</li>
|
|
<li id="step3" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Running sentiment analysis...</span>
|
|
</li>
|
|
<li id="step4" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Extracting key phrases and themes...</span>
|
|
</li>
|
|
<li id="step5" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Assessing mental health risk levels...</span>
|
|
</li>
|
|
<li id="step6" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Generating workplace insights...</span>
|
|
</li>
|
|
<li id="step7" class="pipeline-step">
|
|
<div class="step-icon">
|
|
<i class="fas fa-circle"></i>
|
|
</div>
|
|
<span>Creating executive summary...</span>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="pipeline-container">
|
|
<h3 class="pipeline-title">
|
|
<i class="fas fa-chart-bar"></i>
|
|
Real-time Statistics
|
|
</h3>
|
|
<div class="stats-grid">
|
|
<div class="stat-card positive">
|
|
<div class="stat-icon">
|
|
<i class="fas fa-smile"></i>
|
|
</div>
|
|
<div id="positiveCount" class="stat-value">0</div>
|
|
<div class="stat-label">Positive Responses</div>
|
|
</div>
|
|
<div class="stat-card negative">
|
|
<div class="stat-icon">
|
|
<i class="fas fa-frown"></i>
|
|
</div>
|
|
<div id="negativeCount" class="stat-value">0</div>
|
|
<div class="stat-label">Negative Responses</div>
|
|
</div>
|
|
<div class="stat-card low-risk">
|
|
<div class="stat-icon">
|
|
<i class="fas fa-shield-alt"></i>
|
|
</div>
|
|
<div id="lowRiskCount" class="stat-value">0</div>
|
|
<div class="stat-label">Low Risk</div>
|
|
</div>
|
|
<div class="stat-card high-risk">
|
|
<div class="stat-icon">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<div id="highRiskCount" class="stat-value">0</div>
|
|
<div class="stat-label">High Risk</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="control-footer">
|
|
<div id="currentStatus" class="current-status">
|
|
<i class="fas fa-info-circle"></i>
|
|
Ready to start batch processing of mental health responses...
|
|
</div>
|
|
<div class="control-buttons">
|
|
<button id="startButton" type="button" class="btn-nexgen success" onclick="startBatchAnalysis()">
|
|
<i class="fas fa-play"></i>START ANALYSIS
|
|
</button>
|
|
<button id="stopButton" type="button" class="btn-nexgen danger d-none" onclick="stopBatchAnalysis()">
|
|
<i class="fas fa-stop"></i>STOP PROCESSING
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Results Section (Hidden until complete) -->
|
|
<div id="resultsSection" class="results-section d-none">
|
|
<div class="results-header">
|
|
<h2 class="results-title">
|
|
<i class="fas fa-check-circle"></i>
|
|
Batch Analysis Complete
|
|
</h2>
|
|
</div>
|
|
<div class="results-body">
|
|
<div class="results-stats">
|
|
<div class="result-stat processed">
|
|
<div class="result-icon">
|
|
<i class="fas fa-check-double"></i>
|
|
</div>
|
|
<div id="totalProcessed" class="result-value">0</div>
|
|
<div class="result-label">Responses Processed</div>
|
|
</div>
|
|
<div class="result-stat high-risk">
|
|
<div class="result-icon">
|
|
<i class="fas fa-exclamation-triangle"></i>
|
|
</div>
|
|
<div id="finalHighRisk" class="result-value">0</div>
|
|
<div class="result-label">High Risk Cases Found</div>
|
|
</div>
|
|
<div class="result-stat positive">
|
|
<div class="result-icon">
|
|
<i class="fas fa-smile"></i>
|
|
</div>
|
|
<div id="finalPositive" class="result-value">0</div>
|
|
<div class="result-label">Positive Responses</div>
|
|
</div>
|
|
<div class="result-stat time">
|
|
<div class="result-icon">
|
|
<i class="fas fa-clock"></i>
|
|
</div>
|
|
<div id="processingTime" class="result-value">0s</div>
|
|
<div class="result-label">Total Processing Time</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="completion-alert">
|
|
<h3 class="alert-title">
|
|
<i class="fas fa-brain"></i>
|
|
Analysis Successfully Completed!
|
|
</h3>
|
|
<p class="alert-description">
|
|
Your mental health survey responses have been analyzed using advanced AI.
|
|
The system has identified sentiment patterns, risk levels, and workplace insights
|
|
to help NVKN provide targeted mental health interventions.
|
|
</p>
|
|
<div class="result-actions">
|
|
<a id="viewResultsButton" href="@Url.Action("AnalyzeQuestionnaire", new { id = ViewBag.QuestionnaireId })" class="btn-nexgen primary">
|
|
<i class="fas fa-chart-line"></i> VIEW COMPLETE ANALYSIS
|
|
</a>
|
|
<a id="viewHighRiskButton" href="@Url.Action("HighRiskResponses", new { id = ViewBag.QuestionnaireId })" class="btn-nexgen danger d-none">
|
|
<i class="fas fa-shield-alt"></i> VIEW HIGH RISK CASES
|
|
</a>
|
|
<a id="generateReportButton" href="@Url.Action("GenerateReport", new { id = ViewBag.QuestionnaireId })" class="btn-nexgen success">
|
|
<i class="fas fa-file-medical"></i> GENERATE REPORT
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Processing Log -->
|
|
<div class="log-section">
|
|
<div class="log-header">
|
|
<h3 class="log-title">
|
|
<i class="fas fa-terminal"></i>
|
|
Processing Log
|
|
</h3>
|
|
<button type="button" class="log-toggle" onclick="toggleLog()">
|
|
<i class="fas fa-chevron-down"></i> SHOW DETAILS
|
|
</button>
|
|
</div>
|
|
<div id="logContainer" class="log-container d-none">
|
|
<div id="processingLog">
|
|
<div class="log-entry info">
|
|
[<span class="timestamp"></span>] Batch analysis system initialized and ready...
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<script>
|
|
let batchProcessing = false;
|
|
let startTime = null;
|
|
let processedCount = 0;
|
|
let totalRequests = @ViewBag.TotalRequests;
|
|
let questionnaireId = @ViewBag.QuestionnaireId;
|
|
|
|
// Start batch analysis
|
|
function startBatchAnalysis() {
|
|
if (batchProcessing) return;
|
|
|
|
batchProcessing = true;
|
|
startTime = new Date();
|
|
processedCount = 0;
|
|
|
|
// Update UI
|
|
document.getElementById('startButton').classList.add('d-none');
|
|
document.getElementById('stopButton').classList.remove('d-none');
|
|
updateStatusBadge('processing', 'fa-spinner fa-spin', 'PROCESSING...');
|
|
|
|
// Start processing steps animation
|
|
animateProcessingSteps();
|
|
|
|
// Add log entry
|
|
addLogEntry('Starting batch analysis of ' + totalRequests + ' mental health responses...', 'info');
|
|
updateCurrentStatus('Initializing Azure AI services...');
|
|
|
|
// Start the actual batch processing
|
|
processBatch();
|
|
}
|
|
|
|
// Stop batch analysis
|
|
function stopBatchAnalysis() {
|
|
batchProcessing = false;
|
|
|
|
document.getElementById('startButton').classList.remove('d-none');
|
|
document.getElementById('stopButton').classList.add('d-none');
|
|
updateStatusBadge('', 'fa-pause', 'STOPPED');
|
|
|
|
updateCurrentStatus('Batch processing stopped by user');
|
|
addLogEntry('Batch processing stopped by user', 'warning');
|
|
}
|
|
|
|
// Process batch via AJAX
|
|
function processBatch() {
|
|
if (!batchProcessing) return;
|
|
|
|
addLogEntry('Connecting to Azure AI services...', 'info');
|
|
updateCurrentStatus('Processing responses through AI pipeline...');
|
|
|
|
$.post('@Url.Action("ProcessBatchAnalysis")', { questionnaireId: questionnaireId })
|
|
.done(function(data) {
|
|
if (data.success && batchProcessing) {
|
|
addLogEntry(`Successfully processed ${data.processedCount} responses`, 'success');
|
|
|
|
if (data.highRiskCount > 0) {
|
|
addLogEntry(`🚨 ALERT: Found ${data.highRiskCount} high-risk cases requiring immediate attention`, 'warning');
|
|
}
|
|
|
|
completeBatchProcessing(data);
|
|
} else {
|
|
handleProcessingError(data.message || 'Unknown error occurred');
|
|
}
|
|
})
|
|
.fail(function(xhr, status, error) {
|
|
handleProcessingError('Network error: ' + error);
|
|
});
|
|
}
|
|
|
|
// Simulate progress for better UX (since processing happens server-side)
|
|
function simulateProgress(finalCount, highRiskCount) {
|
|
let currentProgress = 0;
|
|
const progressInterval = setInterval(() => {
|
|
if (!batchProcessing || currentProgress >= 95) {
|
|
clearInterval(progressInterval);
|
|
return;
|
|
}
|
|
|
|
currentProgress += Math.random() * 12 + 3; // Random increment between 3-15
|
|
currentProgress = Math.min(currentProgress, 95); // Stop at 95% until actual completion
|
|
|
|
updateProgress(currentProgress);
|
|
|
|
// Update simulated stats
|
|
const simulatedProcessed = Math.floor((currentProgress / 100) * totalRequests);
|
|
document.getElementById('processedCount').textContent = simulatedProcessed;
|
|
|
|
// Simulate finding results
|
|
if (currentProgress > 50) {
|
|
const simPositive = Math.floor(simulatedProcessed * 0.6);
|
|
const simNegative = Math.floor(simulatedProcessed * 0.3);
|
|
const simLowRisk = Math.floor(simulatedProcessed * 0.7);
|
|
const simHighRisk = Math.floor(simulatedProcessed * 0.1);
|
|
|
|
document.getElementById('positiveCount').textContent = simPositive;
|
|
document.getElementById('negativeCount').textContent = simNegative;
|
|
document.getElementById('lowRiskCount').textContent = simLowRisk;
|
|
document.getElementById('highRiskCount').textContent = simHighRisk;
|
|
}
|
|
|
|
// Update estimated time
|
|
const elapsed = (new Date() - startTime) / 1000;
|
|
const estimated = Math.max(0, (elapsed / currentProgress) * (100 - currentProgress));
|
|
document.getElementById('estimatedTime').textContent = `Estimated time: ${Math.round(estimated)}s remaining`;
|
|
|
|
}, 800 + Math.random() * 1500); // Random interval between 0.8-2.3 seconds
|
|
}
|
|
|
|
// Complete batch processing
|
|
function completeBatchProcessing(data) {
|
|
batchProcessing = false;
|
|
|
|
// Final progress update
|
|
updateProgress(100);
|
|
document.getElementById('processedCount').textContent = data.processedCount;
|
|
document.getElementById('estimatedTime').textContent = 'Analysis Complete!';
|
|
|
|
// Update final stats
|
|
document.getElementById('totalProcessed').textContent = data.processedCount;
|
|
document.getElementById('finalHighRisk').textContent = data.highRiskCount;
|
|
|
|
// Calculate processing time
|
|
const processingTime = Math.round((new Date() - startTime) / 1000);
|
|
document.getElementById('processingTime').textContent = processingTime + 's';
|
|
|
|
// Update status
|
|
updateStatusBadge('success', 'fa-check', 'COMPLETE');
|
|
|
|
// Complete all steps
|
|
completeAllSteps();
|
|
|
|
// Show results section
|
|
document.getElementById('resultsSection').classList.remove('d-none');
|
|
|
|
// Show high risk button if needed
|
|
if (data.highRiskCount > 0) {
|
|
document.getElementById('viewHighRiskButton').classList.remove('d-none');
|
|
}
|
|
|
|
// Update UI
|
|
document.getElementById('stopButton').classList.add('d-none');
|
|
updateCurrentStatus(`✅ Successfully analyzed ${data.processedCount} mental health responses!`);
|
|
|
|
addLogEntry(`🎉 Batch processing completed successfully in ${processingTime} seconds`, 'success');
|
|
|
|
// Auto-scroll to results
|
|
setTimeout(() => {
|
|
document.getElementById('resultsSection').scrollIntoView({ behavior: 'smooth' });
|
|
}, 1000);
|
|
}
|
|
|
|
// Handle processing errors
|
|
function handleProcessingError(message) {
|
|
batchProcessing = false;
|
|
|
|
updateStatusBadge('error', 'fa-times', 'ERROR');
|
|
|
|
document.getElementById('startButton').classList.remove('d-none');
|
|
document.getElementById('stopButton').classList.add('d-none');
|
|
|
|
updateCurrentStatus('❌ Error: ' + message);
|
|
addLogEntry('❌ Error: ' + message, 'error');
|
|
|
|
Swal.fire({
|
|
title: 'Processing Error',
|
|
text: message,
|
|
icon: 'error',
|
|
confirmButtonText: 'OK',
|
|
customClass: {
|
|
popup: 'swal-nexgen',
|
|
title: 'swal-title-nexgen'
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update progress bar
|
|
function updateProgress(percentage) {
|
|
const progressBar = document.getElementById('progressBar');
|
|
const progressPercentage = document.getElementById('progressPercentage');
|
|
const progressText = document.getElementById('progressText');
|
|
|
|
progressBar.style.width = percentage + '%';
|
|
progressPercentage.textContent = Math.round(percentage) + '%';
|
|
|
|
if (percentage >= 100) {
|
|
progressBar.classList.remove('animated');
|
|
progressBar.classList.add('complete');
|
|
progressText.textContent = 'Complete!';
|
|
} else {
|
|
progressText.textContent = 'Processing...';
|
|
}
|
|
}
|
|
|
|
// Update status badge
|
|
function updateStatusBadge(type, icon, text) {
|
|
const badge = document.getElementById('statusBadge');
|
|
|
|
badge.className = `status-badge ${type}`;
|
|
badge.innerHTML = `<i class="fas ${icon}"></i> ${text}`;
|
|
}
|
|
|
|
// Animate processing steps
|
|
function animateProcessingSteps() {
|
|
const steps = ['step1', 'step2', 'step3', 'step4', 'step5', 'step6', 'step7'];
|
|
let currentStep = 0;
|
|
|
|
const stepInterval = setInterval(() => {
|
|
if (!batchProcessing || currentStep >= steps.length) {
|
|
clearInterval(stepInterval);
|
|
return;
|
|
}
|
|
|
|
// Complete previous step
|
|
if (currentStep > 0) {
|
|
const prevStep = document.getElementById(steps[currentStep - 1]);
|
|
prevStep.querySelector('.step-icon i').className = 'fas fa-check-circle';
|
|
prevStep.classList.remove('active');
|
|
prevStep.classList.add('completed');
|
|
}
|
|
|
|
// Start current step
|
|
if (currentStep < steps.length) {
|
|
const nextStep = document.getElementById(steps[currentStep]);
|
|
nextStep.querySelector('.step-icon i').className = 'fas fa-circle-notch';
|
|
nextStep.classList.add('active');
|
|
}
|
|
|
|
currentStep++;
|
|
}, 1500 + Math.random() * 2000); // Random interval between 1.5-3.5 seconds
|
|
}
|
|
|
|
// Complete all steps
|
|
function completeAllSteps() {
|
|
const steps = ['step1', 'step2', 'step3', 'step4', 'step5', 'step6', 'step7'];
|
|
steps.forEach(stepId => {
|
|
const step = document.getElementById(stepId);
|
|
step.querySelector('.step-icon i').className = 'fas fa-check-circle';
|
|
step.classList.remove('active');
|
|
step.classList.add('completed');
|
|
});
|
|
}
|
|
|
|
// Update current status message
|
|
function updateCurrentStatus(message) {
|
|
document.getElementById('currentStatus').innerHTML = '<i class="fas fa-info-circle"></i>' + message;
|
|
}
|
|
|
|
// Add log entry
|
|
function addLogEntry(message, type = 'info') {
|
|
const log = document.getElementById('processingLog');
|
|
const timestamp = new Date().toLocaleTimeString();
|
|
|
|
const entry = document.createElement('div');
|
|
entry.className = 'log-entry ' + type;
|
|
entry.innerHTML = `[<span class="timestamp">${timestamp}</span>] ${message}`;
|
|
|
|
log.appendChild(entry);
|
|
|
|
// Auto-scroll to bottom
|
|
const container = document.getElementById('logContainer');
|
|
if (!container.classList.contains('d-none')) {
|
|
container.scrollTop = container.scrollHeight;
|
|
}
|
|
}
|
|
|
|
// Toggle log visibility
|
|
function toggleLog() {
|
|
const logContainer = document.getElementById('logContainer');
|
|
const toggleButton = event.target.closest('button');
|
|
|
|
logContainer.classList.toggle('d-none');
|
|
|
|
if (logContainer.classList.contains('d-none')) {
|
|
toggleButton.innerHTML = '<i class="fas fa-chevron-down"></i> SHOW DETAILS';
|
|
} else {
|
|
toggleButton.innerHTML = '<i class="fas fa-chevron-up"></i> HIDE DETAILS';
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
}
|
|
|
|
// Go back to analysis
|
|
function goBack() {
|
|
if (batchProcessing) {
|
|
Swal.fire({
|
|
title: 'Processing in Progress',
|
|
text: 'Batch analysis is currently running. Do you want to stop and go back?',
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonText: 'Stop and Go Back',
|
|
cancelButtonText: 'Continue Processing',
|
|
customClass: {
|
|
popup: 'swal-nexgen',
|
|
title: 'swal-title-nexgen'
|
|
}
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
stopBatchAnalysis();
|
|
window.location.href = '@Url.Action("AnalyzeQuestionnaire", new { id = ViewBag.QuestionnaireId })';
|
|
}
|
|
});
|
|
} else {
|
|
window.location.href = '@Url.Action("AnalyzeQuestionnaire", new { id = ViewBag.QuestionnaireId })';
|
|
}
|
|
}
|
|
|
|
// Custom SweetAlert styling
|
|
const swalStyle = document.createElement('style');
|
|
swalStyle.textContent = `
|
|
.swal-nexgen {
|
|
background: rgba(15, 23, 42, 0.95) !important;
|
|
backdrop-filter: blur(20px) !important;
|
|
border: 1px solid rgba(34, 211, 238, 0.3) !important;
|
|
border-radius: 1rem !important;
|
|
color: #e2e8f0 !important;
|
|
}
|
|
.swal-title-nexgen {
|
|
color: #22d3ee !important;
|
|
font-weight: 700 !important;
|
|
letter-spacing: 0.05em !important;
|
|
}
|
|
`;
|
|
document.head.appendChild(swalStyle);
|
|
|
|
// Initialize timestamps
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
document.querySelectorAll('.timestamp').forEach(el => {
|
|
el.textContent = new Date().toLocaleTimeString();
|
|
});
|
|
|
|
// Start processing automatically if we have responses
|
|
if (totalRequests > 0) {
|
|
setTimeout(() => {
|
|
addLogEntry('Auto-starting batch analysis...', 'info');
|
|
startBatchAnalysis();
|
|
simulateProgress(totalRequests, 0); // Start UI simulation
|
|
}, 1000);
|
|
}
|
|
});
|
|
|
|
// Prevent page refresh during processing
|
|
window.addEventListener('beforeunload', function(e) {
|
|
if (batchProcessing) {
|
|
e.preventDefault();
|
|
e.returnValue = 'Mental health analysis is in progress. Leaving now may interrupt the process.';
|
|
}
|
|
});
|
|
</script>
|
|
} |