(computed(() => props.items
name: r.type.name,
buy: r.buy,
sell: r.sell,
- price: r.averagePrice,
- count: r.count,
+ price: r.price,
+ count: r.remaining,
precentProfit,
- iskProfit: r.averagePrice * precentProfit * r.count
+ iskProfit: r.price * precentProfit * r.remaining
};
})), {
defaultSortKey: 'precentProfit',
@@ -100,14 +100,14 @@ const getLineColor = (result: Result) => {
{{ formatIsk(r.buy) }}
{{ formatIsk(r.sell) }}
{{ formatIsk(r.price) }}
{{ r.count }}
- {{ percentFormater.format(r.precentProfit) }}
+ {{ percentFormater.format(r.precentProfit) }}
{{ formatIsk(r.iskProfit) }}
@@ -122,4 +122,4 @@ const getLineColor = (result: Result) => {
div.end {
@apply justify-self-end ms-2;
}
-@/components/table
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/market/track/BuyModal.vue b/src/market/acquisition/BuyModal.vue
similarity index 92%
rename from src/market/track/BuyModal.vue
rename to src/market/acquisition/BuyModal.vue
index 23b0847..9ae1d85 100644
--- a/src/market/track/BuyModal.vue
+++ b/src/market/acquisition/BuyModal.vue
@@ -3,10 +3,10 @@ import { Modal } from '@/components';
import { formatIsk } from '@/formaters';
import { MarketType, MarketTypeLabel } from '@/market';
import { ref } from 'vue';
-import { useTrackedItemStore } from './track';
+import { useAcquiredTypesStore } from './acquisition';
-const trackedItemStore = useTrackedItemStore();
+const acquiredTypesStore = useAcquiredTypesStore();
const modalOpen = ref(false);
const type = ref();
@@ -38,7 +38,7 @@ const add = () => {
return;
}
- trackedItemStore.addTrackedItem(id, count.value, price.value);
+ acquiredTypesStore.addType(id, count.value, price.value);
modalOpen.value = false;
}
diff --git a/src/market/track/SellModal.vue b/src/market/acquisition/SellModal.vue
similarity index 87%
rename from src/market/track/SellModal.vue
rename to src/market/acquisition/SellModal.vue
index ae370dc..e974a82 100644
--- a/src/market/track/SellModal.vue
+++ b/src/market/acquisition/SellModal.vue
@@ -2,10 +2,10 @@
import { Modal } from '@/components';
import { MarketType, MarketTypeLabel } from '@/market';
import { ref } from 'vue';
-import { useTrackedItemStore } from './track';
+import { useAcquiredTypesStore } from './acquisition';
-const trackedItemStore = useTrackedItemStore();
+const acquiredTypesStore = useAcquiredTypesStore();
const modalOpen = ref(false);
const type = ref();
@@ -24,7 +24,7 @@ const remove = () => {
return;
}
- trackedItemStore.removeTrackedItem(id, count.value);
+ acquiredTypesStore.removeType(id, count.value);
modalOpen.value = false;
}
diff --git a/src/market/acquisition/acquisition.ts b/src/market/acquisition/acquisition.ts
new file mode 100644
index 0000000..3116830
--- /dev/null
+++ b/src/market/acquisition/acquisition.ts
@@ -0,0 +1,63 @@
+import { marbasAxiosInstance } from "@/service";
+import { defineStore } from "pinia";
+import { computed, ref } from "vue";
+
+export type AcquiredMarketType = {
+ id: number;
+ type: number;
+ quantity: number;
+ remaining: number;
+ price: number;
+ date: Date;
+ source: 'bo' | 'so' | 'prod';
+ user: number;
+}
+
+const endpoint = '/api/acquisitions/';
+
+export const useAcquiredTypesStore = defineStore('market-acquisition', () => {
+ const acquiredTypes = ref([]);
+
+ const types = computed(() => acquiredTypes.value);
+ const addType = async (type: number, quantity: number, price: number) => {
+ acquiredTypes.value = [...acquiredTypes.value, (await marbasAxiosInstance.post(endpoint, {
+ type: type,
+ quantity: quantity,
+ remaining: quantity,
+ price: price,
+ date: new Date(),
+ source: 'bo'
+ })).data];
+ };
+ const removeType = async (type: number, quantity: number) => {
+ const found = acquiredTypes.value.find(item => item.type === type);
+
+ if (!found) {
+ return;
+ }
+
+ if (found.remaining <= 0) {
+ acquiredTypes.value = acquiredTypes.value.filter(i => i.type !== type);
+
+ } else {
+ acquiredTypes.value = acquiredTypes.value.map(i => {
+ if (i.type === item.type) {
+ return item;
+ } else {
+ return i;
+ }
+ });
+ }
+
+ const item = {
+ ...found,
+ remaining: found.remaining - quantity
+ };
+
+ await marbasAxiosInstance.put(`${endpoint}${item.id}`, item);
+ };
+
+ marbasAxiosInstance.get(endpoint).then(res => acquiredTypes.value = res.data.filter(item => item.remaining > 0));
+
+ return { types, addType, removeType };
+});
\ No newline at end of file
diff --git a/src/market/acquisition/index.ts b/src/market/acquisition/index.ts
new file mode 100644
index 0000000..77d427d
--- /dev/null
+++ b/src/market/acquisition/index.ts
@@ -0,0 +1,7 @@
+export * from './AcquiredType';
+export * from './acquisition';
+
+export { default as AcquisitionResultTable } from './AcquisitionResultTable.vue';
+export { default as BuyModal } from './BuyModal.vue';
+export { default as SellModal } from './SellModal.vue';
+
diff --git a/src/market/appraisal/evepraisal.ts b/src/market/appraisal/evepraisal.ts
index 807dc70..b03df7b 100644
--- a/src/market/appraisal/evepraisal.ts
+++ b/src/market/appraisal/evepraisal.ts
@@ -4,7 +4,7 @@ import { MarketType } from "../type";
import { PriceGetter } from './MarketTypePrice';
export const evepraisalAxiosInstance = axios.create({
- baseURL: '/evepraisal/',
+ baseURL: import.meta.env.VITE_EVEPRAISAL_URL,
headers: {
'accept': 'application/json',
"Content-Type": "application/json"
diff --git a/src/market/appraisal/fuzzwork.ts b/src/market/appraisal/fuzzwork.ts
index dde0ac9..ffac172 100644
--- a/src/market/appraisal/fuzzwork.ts
+++ b/src/market/appraisal/fuzzwork.ts
@@ -4,7 +4,7 @@ import { MarketType } from "../type";
import { PriceGetter } from './MarketTypePrice';
export const fuzzworkAxiosInstance = axios.create({
- baseURL: '/fuzzwork/',
+ baseURL: import.meta.env.VITE_FUZZWORK_URL,
headers: {
'accept': 'application/json',
"Content-Type": "application/json"
diff --git a/src/market/scan/index.ts b/src/market/scan/index.ts
deleted file mode 100644
index 02cbf73..0000000
--- a/src/market/scan/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from './HistoryQuartils';
-export * from './scan';
-
-export { default as ScanResultTable } from './ScanResultTable.vue';
-
diff --git a/src/market/scan/scan.ts b/src/market/scan/scan.ts
deleted file mode 100644
index 2c4c306..0000000
--- a/src/market/scan/scan.ts
+++ /dev/null
@@ -1,56 +0,0 @@
-import { MarketOrderHistory, MarketType, MarketTypePrice, getHistory, jitaId } from "@/market";
-import { usePocketBase, watchCollection } from "@/pocketbase";
-import { defineStore } from "pinia";
-import { RecordModel } from "pocketbase";
-import { computed, onMounted, ref } from "vue";
-
-export type ScanResult = {
- type: MarketType;
- history: MarketOrderHistory[];
- buy: number,
- sell: number,
- orderCount: number,
-}
-
-interface MarketScan extends RecordModel {
- owner: string;
- types: number[];
-};
-
-const marketScans = 'marketScans';
-
-export const useMarketScanStore = defineStore(marketScans, () => {
- const pb = usePocketBase();
- const marketScan = ref();
-
- const types = computed(() => marketScan.value?.types ?? []);
- const setTypes = async (types: number[]) => {
- if (marketScan.value?.id) {
- marketScan.value = await pb.collection(marketScans).update(marketScan.value.id, { owner: pb.authStore.model!.id, types });
- } else {
- marketScan.value = await pb.collection(marketScans).create({ owner: pb.authStore.model!.id, types });
- }
- }
- const addType = async (type: number) => {
- if (!types.value.includes(type)) {
- await setTypes([...types.value, type]);
- }
- }
- const removeType = async (type: number) => {
- if (types.value.includes(type)) {
- await setTypes(types.value.filter(t => t !== type));
- }
- }
-
- watchCollection(marketScans, '*', data => {
- if (data.action === 'delete') {
- marketScan.value = undefined;
- } else if (!marketScan.value || data.record.id === marketScan.value.id) {
- marketScan.value = data.record;
- }
- });
- onMounted(async () => marketScan.value = await pb.collection(marketScans).getFirstListItem('').catch(() => undefined));
- return { types, setTypes, addType, removeType };
-});
-
-export const createResult = async (id: number, price: MarketTypePrice): Promise => ({ history: await getHistory(jitaId, id), ...price });
\ No newline at end of file
diff --git a/src/market/track/TrackedItem.ts b/src/market/track/TrackedItem.ts
deleted file mode 100644
index 77a0289..0000000
--- a/src/market/track/TrackedItem.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { MarketType } from "@/market";
-
-export type TrackedItem = {
- type: MarketType;
- count: number;
- averagePrice: number;
- buy: number,
- sell: number
-}
\ No newline at end of file
diff --git a/src/market/track/index.ts b/src/market/track/index.ts
deleted file mode 100644
index 7c25866..0000000
--- a/src/market/track/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export * from './TrackedItem';
-export * from './track';
-
-export { default as BuyModal } from './BuyModal.vue';
-export { default as SellModal } from './SellModal.vue';
-export { default as TrackResultTable } from './TrackResultTable.vue';
-
diff --git a/src/market/track/track.ts b/src/market/track/track.ts
deleted file mode 100644
index f8b2c7d..0000000
--- a/src/market/track/track.ts
+++ /dev/null
@@ -1,58 +0,0 @@
-import { useCollection, usePocketBase } from "@/pocketbase";
-import { createSharedComposable, useLocalStorage } from '@vueuse/core';
-import { defineStore } from "pinia";
-import { RecordModel } from "pocketbase";
-import { computed } from "vue";
-
-export type TrackedMarketItemStorage = {
- typeID: number;
- count: number;
- averagePrice: number;
-}
-
-interface TrackedMarketItem extends RecordModel {
- owner: string;
- typeID: number;
- count: number;
- averagePrice: number;
-}
-
-const marketTrackings = 'marketTrackings';
-
-export const useTrackedItemsStorage = createSharedComposable(() => useLocalStorage('market-track-items', []));
-
-export const useTrackedItemStore = defineStore(marketTrackings, () => {
- const pb = usePocketBase();
- const trackedItems = useCollection(marketTrackings);
-
- const items = computed(() => trackedItems);
- const addTrackedItem = async (typeID: number, count: number, averagePrice: number) => {
- const oldItem = trackedItems.value.find(i => i.typeID === typeID);
-
- if (oldItem?.id) {
- pb.collection(marketTrackings).update(oldItem.id, {
- ...oldItem,
- count: count + oldItem.count,
- averagePrice: ((averagePrice * count) + (oldItem.averagePrice * oldItem.count)) / (count + oldItem.count)
- });
- } else {
- pb.collection(marketTrackings).create({ owner: pb.authStore.model!.id, typeID, count, averagePrice});
- }
- };
- const removeTrackedItem = async (typeID: number, count: number) => {
- const oldItem = trackedItems.value.find(i => i.typeID === typeID);
-
- if (!oldItem?.id) {
- return;
- } else if (oldItem.count > count) {
- pb.collection(marketTrackings).update(oldItem.id, {
- ...oldItem,
- count: oldItem.count - count
- });
- } else {
- pb.collection(marketTrackings).delete(oldItem.id);
- }
- };
-
- return { items, addTrackedItem, removeTrackedItem };
-});
\ No newline at end of file
diff --git a/src/market/scan/HistoryQuartils.ts b/src/market/tracking/HistoryQuartils.ts
similarity index 100%
rename from src/market/scan/HistoryQuartils.ts
rename to src/market/tracking/HistoryQuartils.ts
diff --git a/src/market/scan/ScanResultTable.vue b/src/market/tracking/TrackingResultTable.vue
similarity index 96%
rename from src/market/scan/ScanResultTable.vue
rename to src/market/tracking/TrackingResultTable.vue
index b7eb875..36d4a88 100644
--- a/src/market/scan/ScanResultTable.vue
+++ b/src/market/tracking/TrackingResultTable.vue
@@ -6,7 +6,7 @@ import { MarketType, MarketTypeLabel, TaxInput, useMarketTaxStore } from "@/mark
import { BookmarkSlashIcon, ShoppingCartIcon } from '@heroicons/vue/24/outline';
import { useStorage } from '@vueuse/core';
import { computed, ref } from 'vue';
-import { ScanResult, getHistoryQuartils } from '.';
+import { TrackingResult, getHistoryQuartils } from '.';
type Result = {
type: MarketType;
@@ -22,7 +22,7 @@ type Result = {
}
interface Props {
- items?: ScanResult[];
+ items?: TrackingResult[];
infoOnly?: boolean;
ignoredColums?: string[];
}
@@ -45,8 +45,8 @@ defineEmits();
const marketTaxStore = useMarketTaxStore();
-const days = useStorage('market-scan-days', 365);
-const threshold = useStorage('market-scan-threshold', 10);
+const days = useStorage('market-tracking-days', 365);
+const threshold = useStorage('market-tracking-threshold', 10);
const filter = ref("");
const onlyCheap = ref(false);
const columnsToIgnore = computed(() => {
@@ -153,4 +153,4 @@ const getLineColor = (result: Result) => {
div.end {
@apply justify-self-end ms-2;
}
-@/components/table
\ No newline at end of file
+
\ No newline at end of file
diff --git a/src/market/tracking/index.ts b/src/market/tracking/index.ts
new file mode 100644
index 0000000..910e701
--- /dev/null
+++ b/src/market/tracking/index.ts
@@ -0,0 +1,5 @@
+export * from './HistoryQuartils';
+export * from './tracking';
+
+export { default as TrackingResultTable } from './TrackingResultTable.vue';
+
diff --git a/src/market/tracking/tracking.ts b/src/market/tracking/tracking.ts
new file mode 100644
index 0000000..701ffb9
--- /dev/null
+++ b/src/market/tracking/tracking.ts
@@ -0,0 +1,41 @@
+import { MarketOrderHistory, MarketType, MarketTypePrice, getHistory, jitaId } from "@/market";
+import { marbasAxiosInstance } from "@/service";
+import { defineStore } from "pinia";
+import { computed, ref } from "vue";
+
+export type TrackingResult = {
+ type: MarketType;
+ history: MarketOrderHistory[];
+ buy: number,
+ sell: number,
+ orderCount: number,
+}
+
+type MarketTracking = {
+ id: number,
+ type: number
+};
+
+const endpoint = '/api/types_tracking/';
+
+export const useMarketTrackingStore = defineStore('marketTracking', () => {
+ const trackedTypes = ref([]);
+
+ const types = computed(() => trackedTypes.value ?? []);
+ const addType = async (type: number) => {
+ if (!trackedTypes.value.includes(type)) {
+ await marbasAxiosInstance.post(endpoint, { type });
+ }
+ }
+ const removeType = async (type: number) => {
+ if (trackedTypes.value.includes(type)) {
+ await marbasAxiosInstance.delete(`${endpoint}${type}`);
+ }
+ }
+
+ marbasAxiosInstance.get(endpoint).then(res => trackedTypes.value = res.data.map(item => item.type));
+
+ return { types, addType, removeType };
+});
+
+export const createResult = async (id: number, price: MarketTypePrice): Promise => ({ history: await getHistory(jitaId, id), ...price });
\ No newline at end of file
diff --git a/src/market/type/MarketTypeInput.vue b/src/market/type/MarketTypeInput.vue
index 03df28d..5bf6ff5 100644
--- a/src/market/type/MarketTypeInput.vue
+++ b/src/market/type/MarketTypeInput.vue
@@ -96,7 +96,7 @@ watchEffect(async () => {
isOpen = true" v-on-click-outside="() => isOpen = false">
diff --git a/src/market/type/MarketTypeLabel.vue b/src/market/type/MarketTypeLabel.vue
index aafc2f4..464a27e 100644
--- a/src/market/type/MarketTypeLabel.vue
+++ b/src/market/type/MarketTypeLabel.vue
@@ -17,7 +17,7 @@ withDefaults(defineProps
(), {
-
+
{{ name }}
diff --git a/src/pages/Login.vue b/src/pages/Login.vue
deleted file mode 100644
index 009ea7b..0000000
--- a/src/pages/Login.vue
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
-
- Login:
-
-
-
- Password:
-
-
-
Login
-
-
diff --git a/src/pages/Market.vue b/src/pages/Market.vue
index f382238..9f7ccbc 100644
--- a/src/pages/Market.vue
+++ b/src/pages/Market.vue
@@ -6,15 +6,15 @@ import { RouterLink, RouterView } from 'vue-router';
-
+
Item Info
-
- Scan
-
-
+
Tracking
+
+ Acquisitions
+
diff --git a/src/pages/market/Acquisitions.vue b/src/pages/market/Acquisitions.vue
new file mode 100644
index 0000000..1bf4ce1
--- /dev/null
+++ b/src/pages/market/Acquisitions.vue
@@ -0,0 +1,43 @@
+
+
+
+
+
+ buyModal?.open(type, { 'Price': price, 'Buy': buy, 'Sell': sell })" @sell="type => sellModal?.open(type)" />
+
+
+
+
+
\ No newline at end of file
diff --git a/src/pages/market/Track.vue b/src/pages/market/Track.vue
deleted file mode 100644
index 440ceb1..0000000
--- a/src/pages/market/Track.vue
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
-
-
-
- buyModal?.open(type, { 'Price': price, 'Buy': buy, 'Sell': sell })" @sell="type => sellModal?.open(type)" />
-
-
-
-
-
\ No newline at end of file
diff --git a/src/pages/market/Scan.vue b/src/pages/market/Tracking.vue
similarity index 71%
rename from src/pages/market/Scan.vue
rename to src/pages/market/Tracking.vue
index 5398b3f..1edf66f 100644
--- a/src/pages/market/Scan.vue
+++ b/src/pages/market/Tracking.vue
@@ -1,7 +1,7 @@
@@ -70,7 +73,7 @@ watch(() => markeyScanStore.types, async t => {
- buyModal?.open(type, { 'Buy': buy, 'Sell': sell })" @remove="removeItem" />
+ buyModal?.open(type, { 'Buy': buy, 'Sell': sell })" @remove="removeItem" />
\ No newline at end of file
diff --git a/src/pages/market/TypeInfo.vue b/src/pages/market/TypeInfo.vue
index b642276..e2bbcc3 100644
--- a/src/pages/market/TypeInfo.vue
+++ b/src/pages/market/TypeInfo.vue
@@ -1,8 +1,8 @@
diff --git a/vite.config.ts b/vite.config.ts
index 2cbdca6..7e41a89 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -1,94 +1,25 @@
import vue from '@vitejs/plugin-vue';
import * as path from "path";
-import { defineConfig, loadEnv } from 'vite';
-import zlib from 'zlib';
+import { defineConfig } from 'vite';
+import runtimeEnv from 'vite-plugin-runtime-env';
-export default defineConfig(({ mode }) => {
- const env = loadEnv(mode, process.cwd(), '');
-
- return {
- plugins: [vue()],
- resolve: {
- alias: {
- 'src': path.resolve(__dirname, './src/'),
- '@': path.resolve(__dirname, './src/'),
- },
- extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
+export default defineConfig({
+ plugins: [
+ runtimeEnv(),
+ vue(),
+ ],
+ resolve: {
+ alias: {
+ 'src': path.resolve(__dirname, './src/'),
+ '@': path.resolve(__dirname, './src/'),
},
- server: {
- port: 3000,
- strictPort: true,
- watch: {
- usePolling: true
- },
- proxy: {
- '/marbas/': {
- target: env.MARBAS_URL,
- changeOrigin: true,
- followRedirects: true,
- rewrite: path => path.replace(/^\/marbas/, ''),
- selfHandleResponse: true,
- configure: proxy => {
- proxy.on('proxyRes', (proxyRes, req, res) => {
- const chunks = [];
-
- proxyRes.on("data", (chunk) => chunks.push(chunk));
- proxyRes.on("end", () => {
- const buffer = Buffer.concat(chunks);
- const encoding = proxyRes.headers["content-encoding"];
- const relace = (b: Buffer) => {
- let remoteBody = b.toString();
- const modifiedBody = remoteBody.replace(env.MARBAS_URL, '/marbas/');
-
- res.write(modifiedBody);
- res.end();
- }
-
- if (!encoding) {
- relace(buffer);
- } else if (encoding === "gzip" || encoding === "deflate") {
- zlib.unzip(buffer, (err, b) => {
- if (!err) {
- relace(b);
- } else {
- console.error(err);
- }
- });
- } else {
- console.error(`Unsupported encoding: ${encoding}`);
- }
- });
- });
- }
- },
- '/pocketbase/': {
- target: env.POCKET_BASE_URL,
- changeOrigin: true,
- followRedirects: true,
- rewrite: path => path.replace(/^\/pocketbase/, ''),
- },
- '/evepraisal/': {
- target: env.EVEPRAISAL_URL,
- changeOrigin: true,
- followRedirects: true,
- rewrite: path => path.replace(/^\/evepraisal/, ''),
- },
- '/fuzzwork/': {
- target: env.FUZZWORK_URL,
- changeOrigin: true,
- followRedirects: true,
- rewrite: path => path.replace(/^\/fuzzwork/, ''),
- },
- '/esi/': {
- target: env.ESI_URL,
- changeOrigin: true,
- followRedirects: true,
- rewrite: path => path.replace(/^\/esi/, ''),
- headers: {
- 'User-Agent': env.ESI_USER_AGENT
- },
- }
- }
+ extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
+ },
+ server: {
+ port: 3000,
+ strictPort: true,
+ watch: {
+ usePolling: true
}
- };
-})
+ }
+});