rework hierarchy
This commit is contained in:
11
src/main.ts
11
src/main.ts
@@ -4,10 +4,13 @@ import App from './App.vue';
|
||||
import './style.css';
|
||||
|
||||
const routes = [
|
||||
{ path: '/', component: () => import('@/Index.vue') },
|
||||
{ path: '/reprocess', component: () => import('@/reprocess/Reprocess.vue') },
|
||||
{ path: '/market', component: () => import('@/market/Market.vue') },
|
||||
{ path: '/tools', component: () => import('@/tools/Tools.vue') },
|
||||
{ path: '/', component: () => import('@/pages/Index.vue') },
|
||||
{ path: '/reprocess', component: () => import('@/pages/Reprocess.vue') },
|
||||
{ path: '/market', component: () => import('@/pages/Market.vue'), children: [
|
||||
{ path: '', redirect: '/market/scan' },
|
||||
{ path: 'scan', component: () => import('@/pages/market/Scan.vue') },
|
||||
] },
|
||||
{ path: '/tools', component: () => import('@/pages/Tools.vue') },
|
||||
];
|
||||
|
||||
const router = createRouter({
|
||||
|
||||
13
src/market/MarketOrderHistory.ts
Normal file
13
src/market/MarketOrderHistory.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { esiAxiosInstance } from "@/service";
|
||||
|
||||
|
||||
export type MarketOrderHistory = {
|
||||
average: number;
|
||||
date: string;
|
||||
highest: number;
|
||||
lowest: number;
|
||||
order_count: number;
|
||||
volume: number;
|
||||
}
|
||||
|
||||
export const getHistory = async (regionId: number, tyeId: number): Promise<MarketOrderHistory[]> => (await esiAxiosInstance.get(`/markets/${regionId}/history/`, { params: { type_id: tyeId } })).data;
|
||||
@@ -1,2 +1,4 @@
|
||||
export * from './MarketOrderHistory';
|
||||
export * from './market';
|
||||
export * from './type';
|
||||
|
||||
|
||||
@@ -1,80 +1,3 @@
|
||||
import { esiAxiosInstance } from "@/service";
|
||||
import { MarketType } from "./type";
|
||||
|
||||
export const jitaId = 10000002;
|
||||
|
||||
export type MarketOrderHistory = {
|
||||
average: number;
|
||||
date: string;
|
||||
highest: number;
|
||||
lowest: number;
|
||||
order_count: number;
|
||||
volume: number;
|
||||
}
|
||||
|
||||
export type MarketResult = {
|
||||
type: MarketType;
|
||||
history: MarketOrderHistory[];
|
||||
buy: number,
|
||||
sell: number
|
||||
}
|
||||
|
||||
export type HistoryQuartils = {
|
||||
totalVolume: number,
|
||||
q1: number,
|
||||
median: number,
|
||||
q3: number,
|
||||
}
|
||||
|
||||
export const getHistory = async (regionId: number, tyeId: number): Promise<MarketOrderHistory[]> => (await esiAxiosInstance.get(`/markets/${regionId}/history/`, { params: { type_id: tyeId } })).data;
|
||||
|
||||
export const getHistoryQuartils = (history: MarketOrderHistory[], days?: number): HistoryQuartils => {
|
||||
const now = Date.now();
|
||||
|
||||
const volumes = history
|
||||
.flatMap(h => {
|
||||
const volume = h.volume;
|
||||
|
||||
if (volume === 0 || (days && new Date(h.date).getTime() < now - days * 24 * 60 * 60 * 1000)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const e = estimateVolume(h);
|
||||
|
||||
return [[h.highest, e], [h.lowest, volume - e]];
|
||||
})
|
||||
.filter(h => h[1] > 0)
|
||||
.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const totalVolume = volumes.reduce((acc, [_, v]) => acc + v, 0);
|
||||
const quartilVolume = totalVolume / 4;
|
||||
const quartils: [number, number, number] = [0, 0, 0];
|
||||
|
||||
let currentVolume = 0;
|
||||
let quartil = 0;
|
||||
|
||||
for (const [price, volume] of volumes) {
|
||||
currentVolume += volume;
|
||||
|
||||
if (currentVolume >= quartilVolume * (quartil + 1)) {
|
||||
quartils[quartil] = price;
|
||||
if (quartil === 2) {
|
||||
break;
|
||||
}
|
||||
quartil++;
|
||||
}
|
||||
}
|
||||
return {
|
||||
totalVolume,
|
||||
q1: quartils[0],
|
||||
median: quartils[1],
|
||||
q3: quartils[2],
|
||||
};
|
||||
}
|
||||
|
||||
const estimateVolume = (history: MarketOrderHistory): number => {
|
||||
if (history.volume === 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(1, Math.round(history.volume * ((history.average - history.lowest) / (history.highest - history.lowest))));
|
||||
}
|
||||
59
src/market/scan/HistoryQuartils.ts
Normal file
59
src/market/scan/HistoryQuartils.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { MarketOrderHistory } from "@/market";
|
||||
|
||||
export type HistoryQuartils = {
|
||||
totalVolume: number,
|
||||
q1: number,
|
||||
median: number,
|
||||
q3: number,
|
||||
}
|
||||
|
||||
export const getHistoryQuartils = (history: MarketOrderHistory[], days?: number): HistoryQuartils => {
|
||||
const now = Date.now();
|
||||
|
||||
const volumes = history
|
||||
.flatMap(h => {
|
||||
const volume = h.volume;
|
||||
|
||||
if (volume === 0 || (days && new Date(h.date).getTime() < now - days * 24 * 60 * 60 * 1000)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const e = estimateVolume(h);
|
||||
|
||||
return [[h.highest, e], [h.lowest, volume - e]];
|
||||
})
|
||||
.filter(h => h[1] > 0)
|
||||
.sort((a, b) => a[0] - b[0]);
|
||||
|
||||
const totalVolume = volumes.reduce((acc, [_, v]) => acc + v, 0);
|
||||
const quartilVolume = totalVolume / 4;
|
||||
const quartils: [number, number, number] = [0, 0, 0];
|
||||
|
||||
let currentVolume = 0;
|
||||
let quartil = 0;
|
||||
|
||||
for (const [price, volume] of volumes) {
|
||||
currentVolume += volume;
|
||||
|
||||
if (currentVolume >= quartilVolume * (quartil + 1)) {
|
||||
quartils[quartil] = price;
|
||||
if (quartil === 2) {
|
||||
break;
|
||||
}
|
||||
quartil++;
|
||||
}
|
||||
}
|
||||
return {
|
||||
totalVolume,
|
||||
q1: quartils[0],
|
||||
median: quartils[1],
|
||||
q3: quartils[2],
|
||||
};
|
||||
}
|
||||
|
||||
const estimateVolume = (history: MarketOrderHistory): number => {
|
||||
if (history.volume === 0) {
|
||||
return 0;
|
||||
}
|
||||
return Math.max(1, Math.round(history.volume * ((history.average - history.lowest) / (history.highest - history.lowest))));
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
import { formatIsk, percentFormater } from '@/formaters';
|
||||
import { MarketType, MarketTypeLabel } from "@/market";
|
||||
import { SortableHeader, useSort } from '@/table';
|
||||
import { ArrowPathIcon } from '@heroicons/vue/24/outline';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { computed, ref } from 'vue';
|
||||
import { MarketResult, getHistoryQuartils } from ".";
|
||||
import { MarketType, MarketTypeLabel } from "./type";
|
||||
import { ScanResult, getHistoryQuartils } from '.';
|
||||
|
||||
type Result = {
|
||||
type: MarketType;
|
||||
@@ -20,7 +20,7 @@ type Result = {
|
||||
}
|
||||
|
||||
interface Props {
|
||||
items?: MarketResult[];
|
||||
items?: ScanResult[];
|
||||
}
|
||||
|
||||
interface Emits {
|
||||
4
src/market/scan/index.ts
Normal file
4
src/market/scan/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from './HistoryQuartils';
|
||||
export * from './scan';
|
||||
|
||||
export { default as ScanResultTable } from './ScanResultTable.vue';
|
||||
9
src/market/scan/scan.ts
Normal file
9
src/market/scan/scan.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { MarketOrderHistory, MarketType } from "@/market";
|
||||
|
||||
export type ScanResult = {
|
||||
type: MarketType;
|
||||
history: MarketOrderHistory[];
|
||||
buy: number,
|
||||
sell: number
|
||||
}
|
||||
|
||||
27
src/pages/Market.vue
Normal file
27
src/pages/Market.vue
Normal file
@@ -0,0 +1,27 @@
|
||||
<script setup lang="ts">
|
||||
import { RouterLink, RouterView } from 'vue-router';
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<div class="flex border-b-2">
|
||||
<RouterLink to="/market/scan" class="tab">
|
||||
<span>Scan</span>
|
||||
</RouterLink>
|
||||
<RouterLink to="/market/track" class="tab">
|
||||
<span>Tracking</span>
|
||||
</RouterLink>
|
||||
</div>
|
||||
<RouterView />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
a.tab {
|
||||
@apply flex items-center p-2 me-2 rounded-t-md bg-slate-600 hover:bg-slate-700;
|
||||
&.router-link-active {
|
||||
@apply bg-emerald-500 hover:bg-emerald-700;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,9 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ReprocessInput, ReprocessItemValues, ReprocessResultTable, reprocess } from '@/reprocess';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { ref } from 'vue';
|
||||
import ReprocessInput from './ReprocessInput.vue';
|
||||
import ReprocessResultTable from './ReprocessResultTable.vue';
|
||||
import { ReprocessItemValues, reprocess } from './reprocess';
|
||||
|
||||
const items = ref("");
|
||||
const minerals = ref("");
|
||||
@@ -1,9 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import HaulerTank from './HaulerTank.vue';
|
||||
import ModuleDamage from './ModuleDamage.vue';
|
||||
|
||||
|
||||
|
||||
import { HaulerTank, ModuleDamage } from '@/tools';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -1,10 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { MarketOrderHistory, MarketType, getHistory, getMarketType, getMarketTypes, jitaId } from "@/market";
|
||||
import { ScanResult, ScanResultTable } from '@/market/scan';
|
||||
import { evepraisalAxiosInstance } from '@/service';
|
||||
import { useStorage } from '@vueuse/core';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { MarketOrderHistory, MarketResult, getHistory, jitaId } from ".";
|
||||
import MarketReultTable from "./MarketResultTable.vue";
|
||||
import { MarketType, getMarketType, getMarketTypes } from "./type";
|
||||
|
||||
type MarketItemStorage = {
|
||||
typeID: number;
|
||||
@@ -19,7 +18,7 @@ const item = ref("");
|
||||
*/
|
||||
const oldStorage = useStorage<MarketItemStorage[]>('market-items', []);
|
||||
const itemsStorage = useStorage<MarketItemStorage[]>('market-scan-items', []);
|
||||
const items = ref<MarketResult[]>([]);
|
||||
const items = ref<ScanResult[]>([]);
|
||||
const addOrRelaod = async (type: MarketType) => {
|
||||
const typeID = type.id;
|
||||
const [history, price] = await Promise.all([
|
||||
@@ -89,6 +88,6 @@ onMounted(async () => {
|
||||
</div>
|
||||
<template v-if="items.length > 0">
|
||||
<hr />
|
||||
<MarketReultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" />
|
||||
<ScanResultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" />
|
||||
</template>
|
||||
</template>
|
||||
@@ -1,2 +1,5 @@
|
||||
export * from './reprocess';
|
||||
|
||||
export { default as ReprocessInput } from './ReprocessInput.vue';
|
||||
export { default as ReprocessResultTable } from './ReprocessResultTable.vue';
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
}
|
||||
|
||||
button {
|
||||
@apply py-0.5 px-2 border rounded bg-slate-600 hover:bg-slate-800;
|
||||
@apply py-0.5 px-2 border rounded bg-slate-600 hover:bg-slate-700;
|
||||
}
|
||||
input {
|
||||
@apply border bg-slate-500 rounded px-1;
|
||||
@@ -52,7 +52,7 @@
|
||||
@apply bg-slate-500;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
@apply bg-slate-600 hover:bg-slate-800;
|
||||
@apply bg-slate-600 hover:bg-slate-700;
|
||||
border-radius: 5px;
|
||||
}
|
||||
input[type=search] {
|
||||
@@ -61,7 +61,7 @@
|
||||
.btn-icon {
|
||||
@apply p-0 border-none bg-transparent hover:text-slate-400 hover:bg-transparent;
|
||||
> svg {
|
||||
@apply w-6 h-6 hover:text-slate-400;
|
||||
@apply w-6 h-6;
|
||||
}
|
||||
}
|
||||
.btn-icon-stroke {
|
||||
|
||||
2
src/tools/index.ts
Normal file
2
src/tools/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as HaulerTank } from './HaulerTank.vue';
|
||||
export { default as ModuleDamage } from './ModuleDamage.vue';
|
||||
Reference in New Issue
Block a user