tracking
This commit is contained in:
59
src/Modal.vue
Normal file
59
src/Modal.vue
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { useEventListener, useVModel } from '@vueuse/core';
|
||||||
|
import { watch } from 'vue';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
open: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'update:open', value: boolean): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
open: false,
|
||||||
|
});
|
||||||
|
const emit = defineEmits<Emit>();
|
||||||
|
|
||||||
|
const isOpen = useVModel(props, 'open', emit, {passive: true});
|
||||||
|
|
||||||
|
watch(isOpen, value => {
|
||||||
|
if (value) {
|
||||||
|
document.body.classList.add('overflow-hidden');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('overflow-hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
useEventListener('keyup', e => {
|
||||||
|
if (e.key === 'Escape') {
|
||||||
|
isOpen.value = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Transition name="fade">
|
||||||
|
<template v-if="isOpen">
|
||||||
|
<div class="fixed inset-0" @click="isOpen = false">
|
||||||
|
<div class="absolute bg-black opacity-80 inset-0 z-0" />
|
||||||
|
<div class="absolute grid inset-0">
|
||||||
|
<div class="justify-self-center" @click.stop>
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</Transition>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.fade-enter-from, .fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-active, .fade-leave-active {
|
||||||
|
transition: opacity 100ms ease-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
15
src/market/appraisal.ts
Normal file
15
src/market/appraisal.ts
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import { evepraisalAxiosInstance } from '@/service';
|
||||||
|
import { MarketType } from "./type";
|
||||||
|
|
||||||
|
export type MarketTypePrice = {
|
||||||
|
type: MarketType;
|
||||||
|
buy: number,
|
||||||
|
sell: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getPrice = async (type: MarketType): Promise<MarketTypePrice> => (await getPrices([type]))[0];
|
||||||
|
export const getPrices = async (types: MarketType[]): Promise<MarketTypePrice[]> => (await evepraisalAxiosInstance.post(`/appraisal.json?market=jita&persist=no&raw_textarea=${types.map(t => t.name).join("%0A")}`)).data.appraisal.items.map((item: any) => ({
|
||||||
|
type: types.find(t => t.name === item.typeName),
|
||||||
|
buy: item.prices.buy.max,
|
||||||
|
sell: item.prices.sell.min
|
||||||
|
}));
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
export * from './MarketOrderHistory';
|
|
||||||
export * from './market';
|
|
||||||
export * from './type';
|
export * from './type';
|
||||||
|
|
||||||
|
export * from './MarketOrderHistory';
|
||||||
|
export * from './appraisal';
|
||||||
|
export * from './market';
|
||||||
|
|
||||||
|
|||||||
87
src/market/scan/BuyModal.vue
Normal file
87
src/market/scan/BuyModal.vue
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Modal from '@/Modal.vue';
|
||||||
|
import { formatIsk } from '@/formaters';
|
||||||
|
import { MarketType } from '@/market';
|
||||||
|
import { useTrackedItemsStorage } from '@/market/track';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'added'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>();
|
||||||
|
|
||||||
|
const itemsStorage = useTrackedItemsStorage();
|
||||||
|
|
||||||
|
const modalOpen = ref<boolean>(false);
|
||||||
|
const type = ref<MarketType>();
|
||||||
|
const suggestions = ref<Record<string, number>>({});
|
||||||
|
const price = ref(1000000);
|
||||||
|
const count = ref(1);
|
||||||
|
|
||||||
|
const open = (t: MarketType, s?: Record<string, number> | number) => {
|
||||||
|
type.value = t;
|
||||||
|
count.value = 1;
|
||||||
|
|
||||||
|
if (typeof s === 'number') {
|
||||||
|
suggestions.value = {};
|
||||||
|
price.value = s;
|
||||||
|
} else if (s) {
|
||||||
|
suggestions.value = s;
|
||||||
|
price.value = Object.values(s)[0];
|
||||||
|
} else {
|
||||||
|
suggestions.value = {};
|
||||||
|
price.value = 1000000;
|
||||||
|
}
|
||||||
|
modalOpen.value = true;
|
||||||
|
}
|
||||||
|
const add = () => {
|
||||||
|
const id = type.value?.id;
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
modalOpen.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldItem = itemsStorage.value.find(i => i.typeID === id);
|
||||||
|
|
||||||
|
if (oldItem) {
|
||||||
|
const item = {
|
||||||
|
typeID: id,
|
||||||
|
count: count.value + oldItem.count,
|
||||||
|
averagePrice: ((price.value * count.value) + (oldItem.averagePrice * oldItem.count)) / (count.value + oldItem.count)
|
||||||
|
};
|
||||||
|
itemsStorage.value = itemsStorage.value.map(i => i.typeID === id ? item : i);
|
||||||
|
} else {
|
||||||
|
const item = {
|
||||||
|
typeID: id,
|
||||||
|
count: count.value,
|
||||||
|
averagePrice: price.value
|
||||||
|
};
|
||||||
|
itemsStorage.value = [ ...itemsStorage.value, item ];
|
||||||
|
}
|
||||||
|
emit('added');
|
||||||
|
modalOpen.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal v-model:open="modalOpen">
|
||||||
|
<div class="p-4 bg-slate-800 rounded mt-20 flex">
|
||||||
|
<div class="flex me-2">
|
||||||
|
<span>Price: </span>
|
||||||
|
<div class="ms-2">
|
||||||
|
<input type="number" min="0" step="1" v-model="price" />
|
||||||
|
<div class="px-2 mt-2 bg-slate-600 hover:bg-slate-700 border rounded cursor-pointer" v-for="(p, n) of suggestions" :key="n" @click="price = p">{{ n }}: {{ formatIsk(p) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex me-2 mb-auto">
|
||||||
|
<span>Count: </span>
|
||||||
|
<input class="ms-2" type="number" min="0" step="1" v-model="count" />
|
||||||
|
</div>
|
||||||
|
<button class="mb-auto" @click="add">Add</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
import { formatIsk, percentFormater } from '@/formaters';
|
import { formatIsk, percentFormater } from '@/formaters';
|
||||||
import { MarketType, MarketTypeLabel } from "@/market";
|
import { MarketType, MarketTypeLabel } from "@/market";
|
||||||
import { SortableHeader, useSort } from '@/table';
|
import { SortableHeader, useSort } from '@/table';
|
||||||
import { ArrowPathIcon } from '@heroicons/vue/24/outline';
|
import { ArrowPathIcon, ShoppingCartIcon } 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 { ScanResult, getHistoryQuartils } from '.';
|
import { ScanResult, getHistoryQuartils } from '.';
|
||||||
@@ -26,6 +26,7 @@ interface Props {
|
|||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'relaod', type: MarketType): void;
|
(e: 'relaod', type: MarketType): void;
|
||||||
(e: 'relaodAll'): void;
|
(e: 'relaodAll'): void;
|
||||||
|
(e: 'buy', type: MarketType, buy: number, sell: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -113,7 +114,8 @@ const getLineColor = (result: Result) => {
|
|||||||
<td class="text-right">{{ formatIsk(r.q3) }}</td>
|
<td class="text-right">{{ formatIsk(r.q3) }}</td>
|
||||||
<td class="text-right">{{ percentFormater.format(r.profit) }}</td>
|
<td class="text-right">{{ percentFormater.format(r.profit) }}</td>
|
||||||
<td class="text-right">
|
<td class="text-right">
|
||||||
<button class="btn-icon-stroke" @click="$emit('relaod', r.type)"><ArrowPathIcon /></button>
|
<button class="btn-icon-stroke me-1" @click="$emit('buy', r.type, r.buy, r.sell)"><ShoppingCartIcon /></button>
|
||||||
|
<button class="btn-icon-stroke me-1" @click="$emit('relaod', r.type)"><ArrowPathIcon /></button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
export * from './HistoryQuartils';
|
export * from './HistoryQuartils';
|
||||||
export * from './scan';
|
export * from './scan';
|
||||||
|
|
||||||
|
export { default as BuyModal } from './BuyModal.vue';
|
||||||
export { default as ScanResultTable } from './ScanResultTable.vue';
|
export { default as ScanResultTable } from './ScanResultTable.vue';
|
||||||
|
|
||||||
|
|||||||
68
src/market/track/SellModal.vue
Normal file
68
src/market/track/SellModal.vue
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import Modal from '@/Modal.vue';
|
||||||
|
import { MarketType } from '@/market';
|
||||||
|
import { useTrackedItemsStorage } from '@/market/track';
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
|
interface Emit {
|
||||||
|
(e: 'removed'): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emit>();
|
||||||
|
|
||||||
|
const itemsStorage = useTrackedItemsStorage();
|
||||||
|
|
||||||
|
const modalOpen = ref<boolean>(false);
|
||||||
|
const type = ref<MarketType>();
|
||||||
|
const count = ref(1);
|
||||||
|
|
||||||
|
const open = (t: MarketType) => {
|
||||||
|
type.value = t;
|
||||||
|
count.value = 1;
|
||||||
|
modalOpen.value = true;
|
||||||
|
}
|
||||||
|
const remove = () => {
|
||||||
|
const id = type.value?.id;
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
modalOpen.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldItem = itemsStorage.value.find(i => i.typeID === id);
|
||||||
|
|
||||||
|
if (!oldItem) {
|
||||||
|
modalOpen.value = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const c = oldItem.count - count.value;
|
||||||
|
|
||||||
|
if (c > 0) {
|
||||||
|
const item = {
|
||||||
|
typeID: id,
|
||||||
|
count: oldItem.count - count.value,
|
||||||
|
averagePrice: oldItem.averagePrice
|
||||||
|
};
|
||||||
|
itemsStorage.value = itemsStorage.value.map(i => i.typeID === id ? item : i);
|
||||||
|
} else {
|
||||||
|
itemsStorage.value = itemsStorage.value.filter(i => i.typeID !== id);
|
||||||
|
}
|
||||||
|
emit('removed');
|
||||||
|
modalOpen.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Modal v-model:open="modalOpen">
|
||||||
|
<div class="p-4 bg-slate-800 rounded mt-20 flex">
|
||||||
|
<div class="flex me-2 mb-auto">
|
||||||
|
<span>Count: </span>
|
||||||
|
<input class="ms-2" type="number" min="0" step="1" v-model="count" />
|
||||||
|
</div>
|
||||||
|
<button class="mb-auto" @click="remove">Remove</button>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
</template>
|
||||||
116
src/market/track/TrackResultTable.vue
Normal file
116
src/market/track/TrackResultTable.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { formatIsk, percentFormater } from '@/formaters';
|
||||||
|
import { MarketType, MarketTypeLabel } from "@/market";
|
||||||
|
import { SortableHeader, useSort } from '@/table';
|
||||||
|
import { MinusIcon, PlusIcon } from '@heroicons/vue/24/outline';
|
||||||
|
import { useStorage } from '@vueuse/core';
|
||||||
|
import { computed, ref } from 'vue';
|
||||||
|
import { TrackedItem } from '.';
|
||||||
|
|
||||||
|
type Result = {
|
||||||
|
type: MarketType;
|
||||||
|
typeID: number;
|
||||||
|
name: string;
|
||||||
|
buy: number;
|
||||||
|
sell: number;
|
||||||
|
price: number;
|
||||||
|
count: number;
|
||||||
|
precentProfit: number;
|
||||||
|
iskProfit: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
items?: TrackedItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'buy', type: MarketType, price: number, buy: number, sell: number): void;
|
||||||
|
(e: 'sell', type: MarketType): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
items: () => []
|
||||||
|
});
|
||||||
|
defineEmits<Emits>();
|
||||||
|
|
||||||
|
const threshold = useStorage('market-track-threshold', 10);
|
||||||
|
const filter = ref("");
|
||||||
|
const { sortedArray, headerProps } = useSort<Result>(computed(() => props.items
|
||||||
|
.filter(r => r.type.name.toLowerCase().includes(filter.value.toLowerCase()))
|
||||||
|
.map(r => {
|
||||||
|
const precentProfit = (r.sell / r.buy) - 1;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: r.type,
|
||||||
|
typeID: r.type.id,
|
||||||
|
name: r.type.name,
|
||||||
|
buy: r.buy,
|
||||||
|
sell: r.sell,
|
||||||
|
price: r.averagePrice,
|
||||||
|
count: r.count,
|
||||||
|
precentProfit,
|
||||||
|
iskProfit: r.averagePrice * precentProfit
|
||||||
|
};
|
||||||
|
})), {
|
||||||
|
defaultSortKey: 'name',
|
||||||
|
defaultSortDirection: 'asc'
|
||||||
|
})
|
||||||
|
const getLineColor = (result: Result) => {
|
||||||
|
if (result.precentProfit >= (threshold.value / 100)) {
|
||||||
|
return 'line-green';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="flex">
|
||||||
|
<div class="flex justify-self-end mb-2 mt-4 ms-auto">
|
||||||
|
<div class="end">
|
||||||
|
<span>Profit Threshold: </span>
|
||||||
|
<input type="number" min="0" max="1000" step="1" v-model="threshold" />
|
||||||
|
</div>
|
||||||
|
<div class="end">
|
||||||
|
<span>Filter: </span>
|
||||||
|
<input type="search" class="w-96" v-model="filter" >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="name">Item</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="buy">Buy</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="sell">Sell</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="price">Bought Price</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="count">Bought Amount</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="precentProfit">Profit (%)</SortableHeader>
|
||||||
|
<SortableHeader v-bind="headerProps" sortKey="iskProfit">Profit (ISK)</SortableHeader>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="r in sortedArray" :key="r.typeID" :class="getLineColor(r)">
|
||||||
|
<td>
|
||||||
|
<MarketTypeLabel :id="r.typeID" :name="r.name" />
|
||||||
|
</td>
|
||||||
|
<td class="text-right">{{ formatIsk(r.buy) }}</td>
|
||||||
|
<td class="text-right">{{ formatIsk(r.sell) }}</td>
|
||||||
|
<td class="text-right">{{ formatIsk(r.price) }}</td>
|
||||||
|
<td class="text-right">{{ r.count }}</td>
|
||||||
|
<td class="text-right">{{ percentFormater.format(r.precentProfit) }}</td>
|
||||||
|
<td class="text-right">{{ formatIsk(r.iskProfit) }}</td>
|
||||||
|
<td class="text-right">
|
||||||
|
<button class="btn-icon-stroke me-1" @click="$emit('buy', r.type, r.price, r.buy, r.sell)"><PlusIcon /></button>
|
||||||
|
<button class="btn-icon-stroke me-1" @click="$emit('sell', r.type)"><MinusIcon /></button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
div.end {
|
||||||
|
@apply justify-self-end ms-2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
9
src/market/track/TrackedItem.ts
Normal file
9
src/market/track/TrackedItem.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { MarketType } from "@/market";
|
||||||
|
|
||||||
|
export type TrackedItem = {
|
||||||
|
type: MarketType;
|
||||||
|
count: number;
|
||||||
|
averagePrice: number;
|
||||||
|
buy: number,
|
||||||
|
sell: number
|
||||||
|
}
|
||||||
6
src/market/track/index.ts
Normal file
6
src/market/track/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * from './TrackedItem';
|
||||||
|
export * from './storage';
|
||||||
|
|
||||||
|
export { default as SellModal } from './SellModal.vue';
|
||||||
|
export { default as TrackResultTable } from './TrackResultTable.vue';
|
||||||
|
|
||||||
9
src/market/track/storage.ts
Normal file
9
src/market/track/storage.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { createSharedComposable, useLocalStorage } from '@vueuse/core';
|
||||||
|
|
||||||
|
export type TrackedMarketItemStorage = {
|
||||||
|
typeID: number;
|
||||||
|
count: number;
|
||||||
|
averagePrice: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTrackedItemsStorage = createSharedComposable(() => useLocalStorage<TrackedMarketItemStorage[]>('market-track-items', []));
|
||||||
@@ -5,7 +5,7 @@ import { RouterLink, RouterView } from 'vue-router';
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div class="flex border-b-2">
|
<div class="flex border-b-2 border-emerald-500">
|
||||||
<RouterLink to="/market/scan" class="tab">
|
<RouterLink to="/market/scan" class="tab">
|
||||||
<span>Scan</span>
|
<span>Scan</span>
|
||||||
</RouterLink>
|
</RouterLink>
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { MarketOrderHistory, MarketType, getHistory, getMarketType, getMarketTypes, jitaId } from "@/market";
|
import { MarketOrderHistory, MarketType, MarketTypePrice, getHistory, getMarketType, getMarketTypes, getPrice, getPrices, jitaId } from "@/market";
|
||||||
import { ScanResult, ScanResultTable } from '@/market/scan';
|
import { BuyModal, ScanResult, ScanResultTable } from '@/market/scan';
|
||||||
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';
|
||||||
|
|
||||||
@@ -10,6 +9,8 @@ type MarketItemStorage = {
|
|||||||
history: MarketOrderHistory[];
|
history: MarketOrderHistory[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const buyModal = ref<typeof BuyModal>();
|
||||||
|
|
||||||
const item = ref("");
|
const item = ref("");
|
||||||
/**
|
/**
|
||||||
* @deprecated use itemsStorage instead
|
* @deprecated use itemsStorage instead
|
||||||
@@ -23,13 +24,13 @@ 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([
|
||||||
getHistory(jitaId, typeID),
|
getHistory(jitaId, typeID),
|
||||||
evepraisalAxiosInstance.post(`/appraisal.json?market=jita&persist=no&raw_textarea=${type.name}`)
|
getPrice(type)
|
||||||
]);
|
]);
|
||||||
const item = {
|
const item = {
|
||||||
type,
|
type,
|
||||||
history,
|
history,
|
||||||
buy: price.data.appraisal.items[0].prices.buy.max,
|
buy: price.buy,
|
||||||
sell: price.data.appraisal.items[0].prices.sell.min
|
sell: price.sell
|
||||||
};
|
};
|
||||||
|
|
||||||
if (items.value.some(i => i.type.id === typeID)) {
|
if (items.value.some(i => i.type.id === typeID)) {
|
||||||
@@ -61,21 +62,15 @@ onMounted(async () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const types = await getMarketTypes(itemsStorage.value.map(i => i.typeID));
|
const prices = await getPrices(await getMarketTypes(itemsStorage.value.map(i => i.typeID)));
|
||||||
const prices: any = (await evepraisalAxiosInstance.post(`/appraisal.json?market=jita&persist=no&raw_textarea=${types.map(t => t.name).join("%0A")}`)).data;
|
|
||||||
|
|
||||||
items.value = itemsStorage.value.map(i => {
|
items.value = itemsStorage.value.map(i => {
|
||||||
const type = types.find(t => t.id === i.typeID) as MarketType;
|
const price = prices.find(p => p.type.id === i.typeID) as MarketTypePrice;
|
||||||
const price = prices.appraisal.items.find((p: any) => p.typeID === i.typeID);
|
|
||||||
|
|
||||||
return {
|
return { ...i, ...price };
|
||||||
...i,
|
|
||||||
type: type,
|
|
||||||
buy: price.prices.buy.max,
|
|
||||||
sell: price.prices.sell.min
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -88,6 +83,7 @@ onMounted(async () => {
|
|||||||
</div>
|
</div>
|
||||||
<template v-if="items.length > 0">
|
<template v-if="items.length > 0">
|
||||||
<hr />
|
<hr />
|
||||||
<ScanResultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" />
|
<ScanResultTable :items="items" @relaod="type => addOrRelaod(type)" @relaodAll="reloadAll" @buy="(type, buy, sell) => buyModal?.open(type, { 'Buy': buy, 'Sell': sell })" />
|
||||||
|
<BuyModal ref="buyModal" />
|
||||||
</template>
|
</template>
|
||||||
</template>
|
</template>
|
||||||
@@ -1,6 +1,41 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { MarketTypePrice, getMarketTypes, getPrices } from "@/market";
|
||||||
|
import { BuyModal } from '@/market/scan';
|
||||||
|
import { SellModal, TrackResultTable, TrackedItem, useTrackedItemsStorage } from '@/market/track';
|
||||||
|
import { onMounted, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
const buyModal = ref<typeof BuyModal>();
|
||||||
|
const sellModal = ref<typeof SellModal>();
|
||||||
|
|
||||||
|
const itemsStorage = useTrackedItemsStorage();
|
||||||
|
const items = ref<TrackedItem[]>([]);
|
||||||
|
|
||||||
|
const relaod = async () => {
|
||||||
|
if (itemsStorage.value.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const prices = await getPrices(await getMarketTypes(itemsStorage.value.map(i => i.typeID)));
|
||||||
|
|
||||||
|
items.value = itemsStorage.value.map(i => {
|
||||||
|
const price = prices.find(p => p.type.id === i.typeID) as MarketTypePrice;
|
||||||
|
|
||||||
|
return { ...i, ...price };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(items, itms => itemsStorage.value = itms.map(i => ({ typeID: i.type.id, count: i.count, averagePrice: i.averagePrice })));
|
||||||
|
onMounted(relaod);
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div></div>
|
<div class="mt-4">
|
||||||
|
<template v-if="items.length > 0">
|
||||||
|
<hr />
|
||||||
|
<TrackResultTable :items="items" @buy="(type, price, buy, sell) => buyModal?.open(type, { 'Price': price, 'Buy': buy, 'Sell': sell })" @sell="type => sellModal?.open(type)" />
|
||||||
|
<BuyModal ref="buyModal" @added="relaod" />
|
||||||
|
<SellModal ref="sellModal" @removed="relaod" />
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -9,7 +9,7 @@ const links = [
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<aside class="fixed top-0 left-0 z-40 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0">
|
<aside class="fixed top-0 left-0 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0">
|
||||||
<div class="h-full px-3 py-4 overflow-y-auto bg-slate-700">
|
<div class="h-full px-3 py-4 overflow-y-auto bg-slate-700">
|
||||||
<ul class="space-y-2 font-medium">
|
<ul class="space-y-2 font-medium">
|
||||||
<li v-for="link in links" :key="link.name">
|
<li v-for="link in links" :key="link.name">
|
||||||
|
|||||||
Reference in New Issue
Block a user