Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/**
* Comparison table component - displays analytical vs simulation comparison.
*/
import type { NetworkComparison, QueueComparison } from '../../types/simulation';
interface ComparisonTableProps {
comparison: NetworkComparison;
}
interface ComparisonRowProps {
label: string;
analytical: number;
simulation: number;
diffPercent: number;
decimals?: number;
}
function ComparisonRow({
label,
analytical,
simulation,
diffPercent,
decimals = 4,
}: ComparisonRowProps) {
const absDiff = Math.abs(diffPercent);
const isGoodMatch = absDiff < 5; // Less than 5% difference is good
const isOkMatch = absDiff < 10; // Less than 10% is acceptable
return (
<tr className="border-b border-gray-200">
<td className="py-2 px-3 text-sm text-gray-900">{label}</td>
<td className="py-2 px-3 text-sm font-mono text-right text-gray-700">
{analytical.toFixed(decimals)}
</td>
<td className="py-2 px-3 text-sm font-mono text-right text-gray-700">
{simulation.toFixed(decimals)}
</td>
<td
className={`py-2 px-3 text-sm font-mono text-right font-medium ${
isGoodMatch
? 'text-green-600'
: isOkMatch
? 'text-yellow-600'
: 'text-red-600'
}`}
>
{diffPercent >= 0 ? '+' : ''}
{diffPercent.toFixed(2)}%
</td>
</tr>
);
}
function QueueComparisonSection({
queueName,
queueComparison,
}: {
queueName: string;
queueComparison: QueueComparison;
}) {
return (
<>
<tr className="bg-gray-100">
<td colSpan={4} className="py-2 px-3 text-sm font-semibold text-gray-700">
{queueName}
</td>
</tr>
<ComparisonRow
label=" Utilisation (ρ)"
analytical={queueComparison.utilization.analytical}
simulation={queueComparison.utilization.simulation}
diffPercent={queueComparison.utilization.difference_percent}
/>
<ComparisonRow
label=" Nombre moyen (L)"
analytical={queueComparison.average_customers.analytical}
simulation={queueComparison.average_customers.simulation}
diffPercent={queueComparison.average_customers.difference_percent}
/>
<ComparisonRow
label=" Temps moyen (W)"
analytical={queueComparison.average_time.analytical}
simulation={queueComparison.average_time.simulation}
diffPercent={queueComparison.average_time.difference_percent}
/>
<ComparisonRow
label=" Temps d'attente (Wq)"
analytical={queueComparison.average_wait.analytical}
simulation={queueComparison.average_wait.simulation}
diffPercent={queueComparison.average_wait.difference_percent}
/>
</>
);
}
export default function ComparisonTable({ comparison }: ComparisonTableProps) {
return (
<div className="overflow-x-auto">
<table className="min-w-full divide-y divide-gray-300 bg-white border border-gray-200 rounded-lg">
<thead className="bg-gray-50">
<tr>
<th className="py-3 px-3 text-left text-xs font-semibold text-gray-700 uppercase tracking-wider">
Métrique
</th>
<th className="py-3 px-3 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider">
Analytique
</th>
<th className="py-3 px-3 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider">
Simulation
</th>
<th className="py-3 px-3 text-right text-xs font-semibold text-gray-700 uppercase tracking-wider">
Différence
</th>
</tr>
</thead>
<tbody>
{/* System totals */}
<tr className="bg-blue-50">
<td colSpan={4} className="py-2 px-3 text-sm font-bold text-blue-900">
Système total
</td>
</tr>
<ComparisonRow
label=" L total"
analytical={comparison.total_L.analytical}
simulation={comparison.total_L.simulation}
diffPercent={comparison.total_L.difference_percent}
/>
<ComparisonRow
label=" W total"
analytical={comparison.total_W.analytical}
simulation={comparison.total_W.simulation}
diffPercent={comparison.total_W.difference_percent}
/>
{/* Coordinator */}
<QueueComparisonSection
queueName="Coordinateur"
queueComparison={comparison.coordinator}
/>
{/* Servers */}
{Object.entries(comparison.servers).map(([serverId, serverComparison]) => (
<QueueComparisonSection
key={serverId}
queueName={
serverId.replace('_', ' ').charAt(0).toUpperCase() +
serverId.replace('_', ' ').slice(1)
}
queueComparison={serverComparison}
/>
))}
</tbody>
</table>
{/* Legend */}
<div className="mt-3 flex items-center justify-end space-x-4 text-xs">
<div className="flex items-center">
<div className="w-3 h-3 bg-green-600 rounded mr-1"></div>
<span className="text-gray-600">< 5% (excellent)</span>
</div>
<div className="flex items-center">
<div className="w-3 h-3 bg-yellow-600 rounded mr-1"></div>
<span className="text-gray-600">5-10% (acceptable)</span>
</div>
<div className="flex items-center">
<div className="w-3 h-3 bg-red-600 rounded mr-1"></div>
<span className="text-gray-600">> 10% (important)</span>
</div>
</div>
</div>
);
}