Delete templates
Browse files- templates/index.html +0 -504
templates/index.html
DELETED
@@ -1,504 +0,0 @@
|
|
1 |
-
<!DOCTYPE html>
|
2 |
-
<html lang="en">
|
3 |
-
<head>
|
4 |
-
<meta charset="UTF-8">
|
5 |
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
-
<title>Jailbreak Trading Data Analysis</title>
|
7 |
-
<script src="https://cdn.tailwindcss.com"></script>
|
8 |
-
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
9 |
-
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js" defer></script>
|
10 |
-
<style>
|
11 |
-
[x-cloak] { display: none !important; }
|
12 |
-
.chart-container {
|
13 |
-
position: relative;
|
14 |
-
height: 300px;
|
15 |
-
width: 100%;
|
16 |
-
}
|
17 |
-
</style>
|
18 |
-
</head>
|
19 |
-
<body class="bg-gray-100 dark:bg-gray-900" x-data="{ darkMode: localStorage.getItem('darkMode') === 'true' }"
|
20 |
-
x-init="$watch('darkMode', val => localStorage.setItem('darkMode', val))"
|
21 |
-
:class="{ 'dark': darkMode }">
|
22 |
-
|
23 |
-
<div class="min-h-screen dark:text-gray-100">
|
24 |
-
<!-- Navigation -->
|
25 |
-
<nav class="bg-white shadow-md dark:bg-gray-800 p-4">
|
26 |
-
<div class="container mx-auto flex justify-between items-center">
|
27 |
-
<div class="flex items-center space-x-2">
|
28 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-blue-600 dark:text-blue-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
29 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" />
|
30 |
-
</svg>
|
31 |
-
<h1 class="text-xl font-bold">Jailbreak Trading Analytics</h1>
|
32 |
-
</div>
|
33 |
-
<div class="flex items-center space-x-4">
|
34 |
-
<button @click="darkMode = !darkMode" class="p-2 rounded-full hover:bg-gray-200 dark:hover:bg-gray-700">
|
35 |
-
<svg x-show="!darkMode" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
36 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z" />
|
37 |
-
</svg>
|
38 |
-
<svg x-show="darkMode" xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
39 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z" />
|
40 |
-
</svg>
|
41 |
-
</button>
|
42 |
-
<a href="https://github.com" target="_blank" class="text-blue-600 dark:text-blue-400 hover:underline">GitHub</a>
|
43 |
-
</div>
|
44 |
-
</div>
|
45 |
-
</nav>
|
46 |
-
|
47 |
-
<!-- Dashboard -->
|
48 |
-
<div class="container mx-auto px-4 py-6" x-data="dashboard()">
|
49 |
-
<!-- Stats Overview -->
|
50 |
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-6">
|
51 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition hover:shadow-lg">
|
52 |
-
<div class="flex items-center justify-between">
|
53 |
-
<h2 class="text-lg font-semibold">Total Items</h2>
|
54 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-blue-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
55 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20 7l-8-4-8 4m16 0l-8 4m8-4v10l-8 4m0-10L4 7m8 4v10" />
|
56 |
-
</svg>
|
57 |
-
</div>
|
58 |
-
<p class="text-3xl font-bold mt-2" x-text="stats.totalItems">--</p>
|
59 |
-
</div>
|
60 |
-
|
61 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition hover:shadow-lg">
|
62 |
-
<div class="flex items-center justify-between">
|
63 |
-
<h2 class="text-lg font-semibold">Total Trades</h2>
|
64 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
65 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7h12m0 0l-4-4m4 4l-4 4m0 6H4m0 0l4 4m-4-4l4-4" />
|
66 |
-
</svg>
|
67 |
-
</div>
|
68 |
-
<p class="text-3xl font-bold mt-2" x-text="stats.totalTrades">--</p>
|
69 |
-
</div>
|
70 |
-
|
71 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition hover:shadow-lg">
|
72 |
-
<div class="flex items-center justify-between">
|
73 |
-
<h2 class="text-lg font-semibold">Unique Items</h2>
|
74 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-purple-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
75 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z" />
|
76 |
-
</svg>
|
77 |
-
</div>
|
78 |
-
<p class="text-3xl font-bold mt-2" x-text="stats.totalCirculation">--</p>
|
79 |
-
</div>
|
80 |
-
|
81 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6 transition hover:shadow-lg">
|
82 |
-
<div class="flex items-center justify-between">
|
83 |
-
<h2 class="text-lg font-semibold">Avg Demand</h2>
|
84 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-8 w-8 text-yellow-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
85 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6" />
|
86 |
-
</svg>
|
87 |
-
</div>
|
88 |
-
<p class="text-3xl font-bold mt-2" x-text="stats.avgDemand">--</p>
|
89 |
-
</div>
|
90 |
-
</div>
|
91 |
-
|
92 |
-
<!-- Chart Section -->
|
93 |
-
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
|
94 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
|
95 |
-
<h2 class="text-lg font-semibold mb-4">Top Items by Demand Multiple</h2>
|
96 |
-
<div class="chart-container">
|
97 |
-
<canvas id="demandChart"></canvas>
|
98 |
-
</div>
|
99 |
-
</div>
|
100 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-4">
|
101 |
-
<h2 class="text-lg font-semibold mb-4">Items by Type</h2>
|
102 |
-
<div class="chart-container">
|
103 |
-
<canvas id="typeChart"></canvas>
|
104 |
-
</div>
|
105 |
-
</div>
|
106 |
-
</div>
|
107 |
-
|
108 |
-
<!-- Data Table Section -->
|
109 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md mb-6">
|
110 |
-
<div class="p-4 border-b dark:border-gray-700">
|
111 |
-
<div class="flex flex-col md:flex-row md:items-center md:justify-between">
|
112 |
-
<h2 class="text-lg font-semibold">Jailbreak Trading Data</h2>
|
113 |
-
<div class="mt-3 md:mt-0 flex flex-col md:flex-row space-y-3 md:space-y-0 md:space-x-3">
|
114 |
-
<div class="relative">
|
115 |
-
<input
|
116 |
-
type="text"
|
117 |
-
placeholder="Search items..."
|
118 |
-
class="pl-10 pr-4 py-2 border rounded-lg w-full dark:bg-gray-700 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
119 |
-
x-model="searchQuery"
|
120 |
-
@input="filterData()"
|
121 |
-
>
|
122 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 text-gray-400 absolute left-3 top-2.5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
123 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
|
124 |
-
</svg>
|
125 |
-
</div>
|
126 |
-
<div>
|
127 |
-
<select
|
128 |
-
class="py-2 px-3 border rounded-lg w-full dark:bg-gray-700 dark:border-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
129 |
-
x-model="selectedType"
|
130 |
-
@change="filterData()"
|
131 |
-
>
|
132 |
-
<option value="">All Types</option>
|
133 |
-
<template x-for="type in types" :key="type">
|
134 |
-
<option x-text="type"></option>
|
135 |
-
</template>
|
136 |
-
</select>
|
137 |
-
</div>
|
138 |
-
</div>
|
139 |
-
</div>
|
140 |
-
</div>
|
141 |
-
<div class="overflow-x-auto" x-show="!loading">
|
142 |
-
<table class="min-w-full divide-y divide-gray-200 dark:divide-gray-700">
|
143 |
-
<thead class="bg-gray-50 dark:bg-gray-700">
|
144 |
-
<tr>
|
145 |
-
<template x-for="(column, index) in columns" :key="index">
|
146 |
-
<th
|
147 |
-
scope="col"
|
148 |
-
class="px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-300 uppercase tracking-wider cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-600"
|
149 |
-
@click="sortBy(column.key)"
|
150 |
-
>
|
151 |
-
<div class="flex items-center space-x-1">
|
152 |
-
<span x-text="column.label"></span>
|
153 |
-
<span class="flex flex-col">
|
154 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" :class="sortColumn === column.key && sortDirection === 'asc' ? 'text-blue-500' : 'text-gray-400'" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
155 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 15l7-7 7 7" />
|
156 |
-
</svg>
|
157 |
-
<svg xmlns="http://www.w3.org/2000/svg" class="h-3 w-3" :class="sortColumn === column.key && sortDirection === 'desc' ? 'text-blue-500' : 'text-gray-400'" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
158 |
-
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
159 |
-
</svg>
|
160 |
-
</span>
|
161 |
-
</div>
|
162 |
-
</th>
|
163 |
-
</template>
|
164 |
-
</tr>
|
165 |
-
</thead>
|
166 |
-
<tbody class="bg-white dark:bg-gray-800 divide-y divide-gray-200 dark:divide-gray-700">
|
167 |
-
<template x-for="(item, index) in paginatedData" :key="index">
|
168 |
-
<tr class="hover:bg-gray-50 dark:hover:bg-gray-700">
|
169 |
-
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium" x-text="item.Name"></td>
|
170 |
-
<td class="px-6 py-4 whitespace-nowrap text-sm" x-text="item.Type"></td>
|
171 |
-
<td class="px-6 py-4 whitespace-nowrap text-sm text-right" x-text="formatNumber(item.TimesTraded)"></td>
|
172 |
-
<td class="px-6 py-4 whitespace-nowrap text-sm text-right" x-text="formatNumber(item.UniqueCirculation)"></td>
|
173 |
-
<td class="px-6 py-4 whitespace-nowrap text-sm text-right">
|
174 |
-
<span
|
175 |
-
class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full"
|
176 |
-
:class="getDemandClass(item.DemandMultiple)"
|
177 |
-
x-text="formatDecimal(item.DemandMultiple)"
|
178 |
-
></span>
|
179 |
-
</td>
|
180 |
-
</tr>
|
181 |
-
</template>
|
182 |
-
</tbody>
|
183 |
-
</table>
|
184 |
-
</div>
|
185 |
-
|
186 |
-
<!-- Loading Spinner -->
|
187 |
-
<div class="flex justify-center items-center py-10" x-show="loading">
|
188 |
-
<svg class="animate-spin h-10 w-10 text-blue-500" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
189 |
-
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
190 |
-
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
191 |
-
</svg>
|
192 |
-
</div>
|
193 |
-
|
194 |
-
<!-- Pagination -->
|
195 |
-
<div class="px-4 py-3 flex items-center justify-between border-t dark:border-gray-700" x-show="!loading">
|
196 |
-
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
197 |
-
<div>
|
198 |
-
<p class="text-sm text-gray-700 dark:text-gray-300">
|
199 |
-
Showing <span class="font-medium" x-text="(currentPage - 1) * pageSize + 1"></span> to
|
200 |
-
<span class="font-medium" x-text="Math.min(currentPage * pageSize, filteredData.length)"></span> of
|
201 |
-
<span class="font-medium" x-text="filteredData.length"></span> results
|
202 |
-
</p>
|
203 |
-
</div>
|
204 |
-
<div>
|
205 |
-
<nav class="relative z-0 inline-flex rounded-md shadow-sm -space-x-px" aria-label="Pagination">
|
206 |
-
<button
|
207 |
-
class="relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm font-medium text-gray-500 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600"
|
208 |
-
:disabled="currentPage === 1"
|
209 |
-
@click="currentPage--"
|
210 |
-
:class="{'opacity-50 cursor-not-allowed': currentPage === 1}"
|
211 |
-
>
|
212 |
-
<span class="sr-only">Previous</span>
|
213 |
-
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
214 |
-
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd" />
|
215 |
-
</svg>
|
216 |
-
</button>
|
217 |
-
<template x-for="page in totalPages" :key="page">
|
218 |
-
<button
|
219 |
-
class="relative inline-flex items-center px-4 py-2 border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-600"
|
220 |
-
:class="{'bg-blue-50 dark:bg-blue-900 text-blue-600 dark:text-blue-300': currentPage === page, 'text-gray-700 dark:text-gray-300': currentPage !== page}"
|
221 |
-
@click="currentPage = page"
|
222 |
-
x-text="page"
|
223 |
-
></button>
|
224 |
-
</template>
|
225 |
-
<button
|
226 |
-
class="relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-sm font-medium text-gray-500 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-600"
|
227 |
-
:disabled="currentPage === totalPages"
|
228 |
-
@click="currentPage++"
|
229 |
-
:class="{'opacity-50 cursor-not-allowed': currentPage === totalPages}"
|
230 |
-
>
|
231 |
-
<span class="sr-only">Next</span>
|
232 |
-
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
|
233 |
-
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd" />
|
234 |
-
</svg>
|
235 |
-
</button>
|
236 |
-
</nav>
|
237 |
-
</div>
|
238 |
-
</div>
|
239 |
-
</div>
|
240 |
-
</div>
|
241 |
-
|
242 |
-
<!-- Analytics Insights -->
|
243 |
-
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
|
244 |
-
<h2 class="text-lg font-semibold mb-4">Data Insights</h2>
|
245 |
-
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
246 |
-
<div>
|
247 |
-
<h3 class="font-medium mb-2">Top Demand Vehicles</h3>
|
248 |
-
<ul class="space-y-2">
|
249 |
-
<template x-for="(item, index) in topDemandVehicles.slice(0, 5)" :key="index">
|
250 |
-
<li class="flex justify-between items-center">
|
251 |
-
<span x-text="item.Name"></span>
|
252 |
-
<span class="font-semibold" x-text="formatDecimal(item.DemandMultiple)"></span>
|
253 |
-
</li>
|
254 |
-
</template>
|
255 |
-
</ul>
|
256 |
-
</div>
|
257 |
-
<div>
|
258 |
-
<h3 class="font-medium mb-2">Most Traded Items</h3>
|
259 |
-
<ul class="space-y-2">
|
260 |
-
<template x-for="(item, index) in mostTradedItems.slice(0, 5)" :key="index">
|
261 |
-
<li class="flex justify-between items-center">
|
262 |
-
<span x-text="item.Name"></span>
|
263 |
-
<span class="font-semibold" x-text="formatNumber(item.TimesTraded)"></span>
|
264 |
-
</li>
|
265 |
-
</template>
|
266 |
-
</ul>
|
267 |
-
</div>
|
268 |
-
</div>
|
269 |
-
</div>
|
270 |
-
</div>
|
271 |
-
</div>
|
272 |
-
|
273 |
-
<script>
|
274 |
-
function dashboard() {
|
275 |
-
return {
|
276 |
-
data: [],
|
277 |
-
filteredData: [],
|
278 |
-
loading: true,
|
279 |
-
columns: [
|
280 |
-
{ key: 'Name', label: 'Item Name' },
|
281 |
-
{ key: 'Type', label: 'Type' },
|
282 |
-
{ key: 'TimesTraded', label: 'Times Traded' },
|
283 |
-
{ key: 'UniqueCirculation', label: 'Circulation' },
|
284 |
-
{ key: 'DemandMultiple', label: 'Demand' }
|
285 |
-
],
|
286 |
-
sortColumn: 'DemandMultiple',
|
287 |
-
sortDirection: 'desc',
|
288 |
-
currentPage: 1,
|
289 |
-
pageSize: 10,
|
290 |
-
searchQuery: '',
|
291 |
-
selectedType: '',
|
292 |
-
types: [],
|
293 |
-
stats: {
|
294 |
-
totalItems: 0,
|
295 |
-
totalTrades: 0,
|
296 |
-
totalCirculation: 0,
|
297 |
-
avgDemand: 0
|
298 |
-
},
|
299 |
-
|
300 |
-
init() {
|
301 |
-
this.fetchData();
|
302 |
-
},
|
303 |
-
|
304 |
-
async fetchData() {
|
305 |
-
try {
|
306 |
-
const response = await fetch('/api/data');
|
307 |
-
this.data = await response.json();
|
308 |
-
|
309 |
-
// Extract unique types
|
310 |
-
this.types = [...new Set(this.data.map(item => item.Type))];
|
311 |
-
|
312 |
-
// Calculate stats
|
313 |
-
this.stats.totalItems = this.data.length;
|
314 |
-
this.stats.totalTrades = this.data.reduce((sum, item) => sum + item.TimesTraded, 0);
|
315 |
-
this.stats.totalCirculation = this.data.reduce((sum, item) => sum + item.UniqueCirculation, 0);
|
316 |
-
this.stats.avgDemand = this.formatDecimal(this.data.reduce((sum, item) => sum + item.DemandMultiple, 0) / this.data.length);
|
317 |
-
|
318 |
-
this.sortData();
|
319 |
-
this.filterData();
|
320 |
-
|
321 |
-
// Initialize charts
|
322 |
-
this.initCharts();
|
323 |
-
|
324 |
-
this.loading = false;
|
325 |
-
} catch (error) {
|
326 |
-
console.error("Error fetching data:", error);
|
327 |
-
this.loading = false;
|
328 |
-
}
|
329 |
-
},
|
330 |
-
|
331 |
-
sortData() {
|
332 |
-
const column = this.sortColumn;
|
333 |
-
const direction = this.sortDirection === 'asc' ? 1 : -1;
|
334 |
-
|
335 |
-
this.data.sort((a, b) => {
|
336 |
-
if (typeof a[column] === 'string') {
|
337 |
-
return direction * a[column].localeCompare(b[column]);
|
338 |
-
} else {
|
339 |
-
return direction * (a[column] - b[column]);
|
340 |
-
}
|
341 |
-
});
|
342 |
-
},
|
343 |
-
|
344 |
-
sortBy(column) {
|
345 |
-
if (this.sortColumn === column) {
|
346 |
-
this.sortDirection = this.sortDirection === 'asc' ? 'desc' : 'asc';
|
347 |
-
} else {
|
348 |
-
this.sortColumn = column;
|
349 |
-
this.sortDirection = 'desc';
|
350 |
-
}
|
351 |
-
|
352 |
-
this.sortBy(column);
|
353 |
-
this.filterData();
|
354 |
-
},
|
355 |
-
|
356 |
-
filterData() {
|
357 |
-
this.currentPage = 1;
|
358 |
-
|
359 |
-
this.filteredData = this.data.filter(item => {
|
360 |
-
const matchesSearch = this.searchQuery === '' ||
|
361 |
-
item.Name.toLowerCase().includes(this.searchQuery.toLowerCase()) ||
|
362 |
-
item.Type.toLowerCase().includes(this.searchQuery.toLowerCase());
|
363 |
-
|
364 |
-
const matchesType = this.selectedType === '' || item.Type === this.selectedType;
|
365 |
-
|
366 |
-
return matchesSearch && matchesType;
|
367 |
-
});
|
368 |
-
},
|
369 |
-
|
370 |
-
get paginatedData() {
|
371 |
-
const start = (this.currentPage - 1) * this.pageSize;
|
372 |
-
const end = start + this.pageSize;
|
373 |
-
return this.filteredData.slice(start, end);
|
374 |
-
},
|
375 |
-
|
376 |
-
get totalPages() {
|
377 |
-
return Math.max(1, Math.ceil(this.filteredData.length / this.pageSize));
|
378 |
-
},
|
379 |
-
|
380 |
-
formatNumber(num) {
|
381 |
-
return num.toLocaleString();
|
382 |
-
},
|
383 |
-
|
384 |
-
formatDecimal(num) {
|
385 |
-
return Number(num).toFixed(2);
|
386 |
-
},
|
387 |
-
|
388 |
-
getDemandClass(value) {
|
389 |
-
if (value >= 5) return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200';
|
390 |
-
if (value >= 3) return 'bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200';
|
391 |
-
if (value >= 2) return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200';
|
392 |
-
return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200';
|
393 |
-
},
|
394 |
-
|
395 |
-
get topDemandVehicles() {
|
396 |
-
return [...this.data]
|
397 |
-
.filter(item => item.Type === 'Vehicle')
|
398 |
-
.sort((a, b) => b.DemandMultiple - a.DemandMultiple);
|
399 |
-
},
|
400 |
-
|
401 |
-
get mostTradedItems() {
|
402 |
-
return [...this.data].sort((a, b) => b.TimesTraded - a.TimesTraded);
|
403 |
-
},
|
404 |
-
|
405 |
-
initCharts() {
|
406 |
-
// Chart for top demand items
|
407 |
-
const topItems = [...this.data]
|
408 |
-
.sort((a, b) => b.DemandMultiple - a.DemandMultiple)
|
409 |
-
.slice(0, 10);
|
410 |
-
|
411 |
-
new Chart(document.getElementById('demandChart'), {
|
412 |
-
type: 'bar',
|
413 |
-
data: {
|
414 |
-
labels: topItems.map(item => item.Name),
|
415 |
-
datasets: [{
|
416 |
-
label: 'Demand Multiple',
|
417 |
-
data: topItems.map(item => item.DemandMultiple),
|
418 |
-
backgroundColor: 'rgba(59, 130, 246, 0.8)',
|
419 |
-
borderColor: 'rgb(59, 130, 246)',
|
420 |
-
borderWidth: 1
|
421 |
-
}]
|
422 |
-
},
|
423 |
-
options: {
|
424 |
-
indexAxis: 'y',
|
425 |
-
responsive: true,
|
426 |
-
maintainAspectRatio: false,
|
427 |
-
plugins: {
|
428 |
-
legend: {
|
429 |
-
display: false
|
430 |
-
},
|
431 |
-
tooltip: {
|
432 |
-
callbacks: {
|
433 |
-
label: function(context) {
|
434 |
-
return `Demand: ${context.raw.toFixed(2)}`;
|
435 |
-
}
|
436 |
-
}
|
437 |
-
}
|
438 |
-
},
|
439 |
-
scales: {
|
440 |
-
x: {
|
441 |
-
grid: {
|
442 |
-
color: 'rgba(156, 163, 175, 0.1)'
|
443 |
-
}
|
444 |
-
},
|
445 |
-
y: {
|
446 |
-
grid: {
|
447 |
-
display: false
|
448 |
-
}
|
449 |
-
}
|
450 |
-
}
|
451 |
-
}
|
452 |
-
});
|
453 |
-
|
454 |
-
// Chart for item types distribution
|
455 |
-
const typeData = {};
|
456 |
-
this.data.forEach(item => {
|
457 |
-
if (!typeData[item.Type]) {
|
458 |
-
typeData[item.Type] = 0;
|
459 |
-
}
|
460 |
-
typeData[item.Type]++;
|
461 |
-
});
|
462 |
-
|
463 |
-
const typeLabels = Object.keys(typeData);
|
464 |
-
const typeCounts = Object.values(typeData);
|
465 |
-
|
466 |
-
const colors = [
|
467 |
-
'rgba(59, 130, 246, 0.8)',
|
468 |
-
'rgba(16, 185, 129, 0.8)',
|
469 |
-
'rgba(245, 158, 11, 0.8)',
|
470 |
-
'rgba(239, 68, 68, 0.8)',
|
471 |
-
'rgba(139, 92, 246, 0.8)',
|
472 |
-
'rgba(236, 72, 153, 0.8)'
|
473 |
-
];
|
474 |
-
|
475 |
-
new Chart(document.getElementById('typeChart'), {
|
476 |
-
type: 'pie',
|
477 |
-
data: {
|
478 |
-
labels: typeLabels,
|
479 |
-
datasets: [{
|
480 |
-
data: typeCounts,
|
481 |
-
backgroundColor: colors.slice(0, typeLabels.length),
|
482 |
-
borderColor: 'rgba(255, 255, 255, 0.5)',
|
483 |
-
borderWidth: 2
|
484 |
-
}]
|
485 |
-
},
|
486 |
-
options: {
|
487 |
-
responsive: true,
|
488 |
-
maintainAspectRatio: false,
|
489 |
-
plugins: {
|
490 |
-
legend: {
|
491 |
-
position: 'bottom',
|
492 |
-
labels: {
|
493 |
-
padding: 20
|
494 |
-
}
|
495 |
-
}
|
496 |
-
}
|
497 |
-
}
|
498 |
-
});
|
499 |
-
}
|
500 |
-
};
|
501 |
-
}
|
502 |
-
</script>
|
503 |
-
</body>
|
504 |
-
</html>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|