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';
|
import './style.css';
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: '/', component: () => import('@/Index.vue') },
|
{ path: '/', component: () => import('@/pages/Index.vue') },
|
||||||
{ path: '/reprocess', component: () => import('@/reprocess/Reprocess.vue') },
|
{ path: '/reprocess', component: () => import('@/pages/Reprocess.vue') },
|
||||||
{ path: '/market', component: () => import('@/market/Market.vue') },
|
{ path: '/market', component: () => import('@/pages/Market.vue'), children: [
|
||||||
{ path: '/tools', component: () => import('@/tools/Tools.vue') },
|
{ path: '', redirect: '/market/scan' },
|
||||||
|
{ path: 'scan', component: () => import('@/pages/market/Scan.vue') },
|
||||||
|
] },
|
||||||
|
{ path: '/tools', component: () => import('@/pages/Tools.vue') },
|
||||||
];
|
];
|
||||||
|
|
||||||
const router = createRouter({
|
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 './market';
|
||||||
|
export * from './type';
|
||||||
|
|
||||||
|
|||||||
@@ -1,80 +1,3 @@
|
|||||||
import { esiAxiosInstance } from "@/service";
|
|
||||||
import { MarketType } from "./type";
|
|
||||||
|
|
||||||
export const jitaId = 10000002;
|
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">
|
<script setup lang="ts">
|
||||||
import { formatIsk, percentFormater } from '@/formaters';
|
import { formatIsk, percentFormater } from '@/formaters';
|
||||||
|
import { MarketType, MarketTypeLabel } from "@/market";
|
||||||
import { SortableHeader, useSort } from '@/table';
|
import { SortableHeader, useSort } from '@/table';
|
||||||
import { ArrowPathIcon } from '@heroicons/vue/24/outline';
|
import { ArrowPathIcon } from '@heroicons/vue/24/outline';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { MarketResult, getHistoryQuartils } from ".";
|
import { ScanResult, getHistoryQuartils } from '.';
|
||||||
import { MarketType, MarketTypeLabel } from "./type";
|
|
||||||
|
|
||||||
type Result = {
|
type Result = {
|
||||||
type: MarketType;
|
type: MarketType;
|
||||||
@@ -20,7 +20,7 @@ type Result = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
items?: MarketResult[];
|
items?: ScanResult[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Emits {
|
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">
|
<script setup lang="ts">
|
||||||
|
import { ReprocessInput, ReprocessItemValues, ReprocessResultTable, reprocess } from '@/reprocess';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { ref } from 'vue';
|
import { ref } from 'vue';
|
||||||
import ReprocessInput from './ReprocessInput.vue';
|
|
||||||
import ReprocessResultTable from './ReprocessResultTable.vue';
|
|
||||||
import { ReprocessItemValues, reprocess } from './reprocess';
|
|
||||||
|
|
||||||
const items = ref("");
|
const items = ref("");
|
||||||
const minerals = ref("");
|
const minerals = ref("");
|
||||||
@@ -1,9 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import HaulerTank from './HaulerTank.vue';
|
import { HaulerTank, ModuleDamage } from '@/tools';
|
||||||
import ModuleDamage from './ModuleDamage.vue';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -1,10 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { MarketOrderHistory, MarketType, getHistory, getMarketType, getMarketTypes, jitaId } from "@/market";
|
||||||
|
import { ScanResult, ScanResultTable } from '@/market/scan';
|
||||||
import { evepraisalAxiosInstance } from '@/service';
|
import { evepraisalAxiosInstance } from '@/service';
|
||||||
import { useStorage } from '@vueuse/core';
|
import { useStorage } from '@vueuse/core';
|
||||||
import { onMounted, ref, watch } from 'vue';
|
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 = {
|
type MarketItemStorage = {
|
||||||
typeID: number;
|
typeID: number;
|
||||||
@@ -19,7 +18,7 @@ const item = ref("");
|
|||||||
*/
|
*/
|
||||||
const oldStorage = useStorage<MarketItemStorage[]>('market-items', []);
|
const oldStorage = useStorage<MarketItemStorage[]>('market-items', []);
|
||||||
const itemsStorage = useStorage<MarketItemStorage[]>('market-scan-items', []);
|
const itemsStorage = useStorage<MarketItemStorage[]>('market-scan-items', []);
|
||||||
const items = ref<MarketResult[]>([]);
|
const items = ref<ScanResult[]>([]);
|
||||||
const addOrRelaod = async (type: MarketType) => {
|
const addOrRelaod = async (type: MarketType) => {
|
||||||
const typeID = type.id;
|
const typeID = type.id;
|
||||||
const [history, price] = await Promise.all([
|
const [history, price] = await Promise.all([
|
||||||
@@ -89,6 +88,6 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<template v-if="items.length > 0">
|
<template v-if="items.length > 0">
|
||||||
<hr />
|
<hr />
|
||||||
<MarketReultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" />
|
<ScanResultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" />
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,2 +1,5 @@
|
|||||||
export * from './reprocess';
|
export * from './reprocess';
|
||||||
|
|
||||||
|
export { default as ReprocessInput } from './ReprocessInput.vue';
|
||||||
|
export { default as ReprocessResultTable } from './ReprocessResultTable.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
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 {
|
input {
|
||||||
@apply border bg-slate-500 rounded px-1;
|
@apply border bg-slate-500 rounded px-1;
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
@apply bg-slate-500;
|
@apply bg-slate-500;
|
||||||
}
|
}
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
@apply bg-slate-600 hover:bg-slate-800;
|
@apply bg-slate-600 hover:bg-slate-700;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
input[type=search] {
|
input[type=search] {
|
||||||
@@ -61,7 +61,7 @@
|
|||||||
.btn-icon {
|
.btn-icon {
|
||||||
@apply p-0 border-none bg-transparent hover:text-slate-400 hover:bg-transparent;
|
@apply p-0 border-none bg-transparent hover:text-slate-400 hover:bg-transparent;
|
||||||
> svg {
|
> svg {
|
||||||
@apply w-6 h-6 hover:text-slate-400;
|
@apply w-6 h-6;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.btn-icon-stroke {
|
.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