transaction list display
This commit is contained in:
@@ -6,7 +6,7 @@ import {ref} from 'vue';
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
inline?: boolean;
|
inline?: boolean;
|
||||||
autoClose: boolean;
|
autoClose?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
import {isCombined, Ledger} from "@/ledger/ledger.ts";
|
import {isCombined, Ledger} from "@/ledger/ledger.ts";
|
||||||
import {FolderOpenIcon} from '@heroicons/vue/24/outline';
|
import {FolderOpenIcon} from '@heroicons/vue/24/outline';
|
||||||
|
import {RouterLink} from "vue-router";
|
||||||
|
import {routeNames} from "@/routes.ts";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
ledger: Ledger;
|
ledger: Ledger;
|
||||||
|
link?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>();
|
const props = defineProps<Props>();
|
||||||
@@ -14,6 +17,7 @@ const props = defineProps<Props>();
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<FolderOpenIcon v-if="isCombined(ledger)" class="w-4 me-1" />
|
<FolderOpenIcon v-if="isCombined(ledger)" class="w-4 me-1" />
|
||||||
<div v-else class="w-4 me-1"/>
|
<div v-else class="w-4 me-1"/>
|
||||||
<span>{{ ledger.name }}</span>
|
<RouterLink v-if="link" :to="{name: routeNames.listLedgerTransactions, params: {ledgerId: ledger.ledgerId}}">{{ ledger.name }}</RouterLink>
|
||||||
|
<span v-else>{{ ledger.name }}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import {
|
|||||||
LedgerResponseTypeEnum,
|
LedgerResponseTypeEnum,
|
||||||
MainLedgerResponse,
|
MainLedgerResponse,
|
||||||
MainLedgerResponseTypeEnum,
|
MainLedgerResponseTypeEnum,
|
||||||
|
TransactionResponse,
|
||||||
|
TransferResponseTypeEnum,
|
||||||
UpdateCombinedLedgerRequest,
|
UpdateCombinedLedgerRequest,
|
||||||
UpdateMainLedgerRequest
|
UpdateMainLedgerRequest
|
||||||
} from "@/generated/mammon";
|
} from "@/generated/mammon";
|
||||||
import {defineStore} from "pinia";
|
import {defineStore} from "pinia";
|
||||||
import {ref, triggerRef} from "vue";
|
import {ref, triggerRef} from "vue";
|
||||||
import {ledgerApi} from "@/mammon";
|
import {ledgerApi, transactionApi} from "@/mammon";
|
||||||
|
|
||||||
export const LedgerTypes = LedgerResponseTypeEnum;
|
export const LedgerTypes = LedgerResponseTypeEnum;
|
||||||
|
|
||||||
@@ -20,6 +22,7 @@ export type MainLedger = MainLedgerResponse & {type: MainLedgerResponseTypeEnum}
|
|||||||
export type CombinedLedger = CombinedLedgerResponse & {type: CombinedLedgerResponseTypeEnum}
|
export type CombinedLedger = CombinedLedgerResponse & {type: CombinedLedgerResponseTypeEnum}
|
||||||
export type Ledger = MainLedger | CombinedLedger;
|
export type Ledger = MainLedger | CombinedLedger;
|
||||||
|
|
||||||
|
export const TransferTypes = TransferResponseTypeEnum;
|
||||||
|
|
||||||
export const systemLedgerRef = 'system';
|
export const systemLedgerRef = 'system';
|
||||||
export const systemLedger = {
|
export const systemLedger = {
|
||||||
@@ -71,3 +74,5 @@ export const useLedgersStore = defineStore('ledgers', () => {
|
|||||||
return {ledgers, findById, findAllById, createMain, createCombined, updateMain, updateCombined, refresh};
|
return {ledgers, findById, findAllById, createMain, createCombined, updateMain, updateCombined, refresh};
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const findAllTransactionInLeger = (ledger: Ledger | string): Promise<TransactionResponse[]> => transactionApi.finAllTransactionsInLedger(typeof ledger == 'string' ? ledger : ledger.ledgerId).then(response => response.data)
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import {
|
|||||||
CharacterRuleBookApi,
|
CharacterRuleBookApi,
|
||||||
LedgerApi,
|
LedgerApi,
|
||||||
ProcessingApi,
|
ProcessingApi,
|
||||||
RuleBookApi
|
RuleBookApi,
|
||||||
|
TransactionApi
|
||||||
} from "@/generated/mammon";
|
} from "@/generated/mammon";
|
||||||
|
|
||||||
export const mammonUrl = import.meta.env.VITE_MAMMON_URL;
|
export const mammonUrl = import.meta.env.VITE_MAMMON_URL;
|
||||||
@@ -22,6 +23,7 @@ const mammonAxiosInstance = axios.create({
|
|||||||
logResource(mammonAxiosInstance)
|
logResource(mammonAxiosInstance)
|
||||||
|
|
||||||
export const ledgerApi = new LedgerApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const ledgerApi = new LedgerApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
|
export const transactionApi = new TransactionApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const characterApi = new CharacterApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const characterApi = new CharacterApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const ruleBookApi = new RuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const ruleBookApi = new RuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
export const characterRuleBookApi = new CharacterRuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
export const characterRuleBookApi = new CharacterRuleBookApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import {formatIsk} from "@/formaters";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
amount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { amount } = defineProps<Props>();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<span :class="amount >= 0 ? 'text-emerald-400' : 'text-amber-700'">{{ formatIsk(amount) }}</span>
|
||||||
|
</template>
|
||||||
@@ -6,3 +6,5 @@ export * from './type';
|
|||||||
export * from './appraisal';
|
export * from './appraisal';
|
||||||
export * from './market';
|
export * from './market';
|
||||||
|
|
||||||
|
export { default as IskLabel } from './IskLabel.vue';
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +1,40 @@
|
|||||||
|
import {esiAxiosInstance} from '@/service';
|
||||||
|
|
||||||
export type MarketType = {
|
export type MarketType = {
|
||||||
id: number;
|
type_id: number;
|
||||||
group_id: number;
|
group_id: number;
|
||||||
marketgroup_id: number;
|
market_group_id: number;
|
||||||
name: string;
|
name: string;
|
||||||
published: boolean;
|
published: boolean;
|
||||||
description: string;
|
description: string;
|
||||||
basePrice: number;
|
base_price: number;
|
||||||
icon_id: number;
|
icon_id: number;
|
||||||
volume: number;
|
volume: number;
|
||||||
portionSize: number;
|
portion_size: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const cache = new Map<number, MarketType>(); // TODO move to pinia store
|
||||||
|
|
||||||
|
const fetchType = (id: number): Promise<MarketType> => {
|
||||||
|
if (cache.has(id)) {
|
||||||
|
return Promise.resolve(cache.get(id)!);
|
||||||
|
}
|
||||||
|
return esiAxiosInstance.get<MarketType>(`/universe/types/${id}/`).then(r => {
|
||||||
|
cache.set(id, r.data);
|
||||||
|
return r.data;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const getMarketType = async (type: string | number): Promise<MarketType> => (await getMarketTypes([type]))[0];
|
export const getMarketType = async (type: string | number): Promise<MarketType> => (await getMarketTypes([type]))[0];
|
||||||
export const getMarketTypes = async (types: (string | number)[]): Promise<MarketType[]> => {
|
export const getMarketTypes = async (types: (string | number)[]): Promise<MarketType[]> => {
|
||||||
if (types.length === 0) {
|
if (types.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
} else if (types.length === 1 && typeof types[0] === "number") {
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
return []
|
const ids = types.filter((t): t is number => typeof t === 'number');
|
||||||
|
return Promise.all(ids.map(fetchType));
|
||||||
}
|
}
|
||||||
|
|
||||||
const blueprintMarketGrous = [ // TODO add all groups
|
const blueprintMarketGroups = [ // TODO add all groups
|
||||||
2,
|
2,
|
||||||
2157,
|
2157,
|
||||||
2159,
|
2159,
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
import {ref, watch} from "vue";
|
||||||
|
import {useRoute} from "vue-router";
|
||||||
|
import log from "loglevel";
|
||||||
|
import {findAllTransactionInLeger, Ledger, TransferTypes, useLedgersStore} from "@/ledger";
|
||||||
|
import {computedAsync} from "@vueuse/core";
|
||||||
|
import {TransactionResponse} from "@/generated/mammon";
|
||||||
|
import {formatEveDate} from "@/formaters.ts";
|
||||||
|
import {IskLabel} from "@/market";
|
||||||
|
|
||||||
|
const {findById, refresh} = useLedgersStore();
|
||||||
|
|
||||||
|
const ledger = ref<Ledger>();
|
||||||
|
|
||||||
|
const transactions = computedAsync<TransactionResponse[]>(async () => {
|
||||||
|
if (ledger.value) {
|
||||||
|
return await findAllTransactionInLeger(ledger.value.ledgerId);
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getIskBalance = (transaction: TransactionResponse) => {
|
||||||
|
const ledgerId = ledger.value?.ledgerId;
|
||||||
|
|
||||||
|
if (!ledgerId) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
let balance = 0;
|
||||||
|
|
||||||
|
for (const transfer of transaction.transfers) {
|
||||||
|
if (transfer.type === TransferTypes.Isk) {
|
||||||
|
if (transfer.toLedgerId === ledgerId) {
|
||||||
|
balance += transfer.amount;
|
||||||
|
} else if (transfer.fromLedgerId === ledgerId) {
|
||||||
|
balance -= transfer.amount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(useRoute(), async route => {
|
||||||
|
if (route.params.ledgerId) {
|
||||||
|
const id = typeof route.params.ledgerId === 'string' ? route.params.ledgerId : route.params.ledgerId[0];
|
||||||
|
|
||||||
|
await refresh() // FIXME
|
||||||
|
|
||||||
|
ledger.value = findById(id)
|
||||||
|
log.info('Loaded ledger:', ledger.value);
|
||||||
|
} else {
|
||||||
|
ledger.value = undefined;
|
||||||
|
log.info('No ledger to load');
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="mt-4">
|
||||||
|
<div class="flex items-end gap-2 mt-2" v-for="transaction in transactions" :key="transaction.transactionId">
|
||||||
|
<span>{{formatEveDate(new Date(transaction.datetime))}}</span>
|
||||||
|
<IskLabel :amount="getIskBalance(transaction)" />
|
||||||
|
<span>{{transaction.description}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -4,7 +4,7 @@ import {EditLedgerModal, LedgerLabel, useLedgersStore} from "@/ledger";
|
|||||||
import {storeToRefs} from "pinia";
|
import {storeToRefs} from "pinia";
|
||||||
import {nextTick, ref} from "vue";
|
import {nextTick, ref} from "vue";
|
||||||
import {PencilSquareIcon} from "@heroicons/vue/24/outline";
|
import {PencilSquareIcon} from "@heroicons/vue/24/outline";
|
||||||
import {formatIsk} from "@/formaters.ts";
|
import {IskLabel} from "@/market";
|
||||||
|
|
||||||
const {ledgers} = storeToRefs(useLedgersStore());
|
const {ledgers} = storeToRefs(useLedgersStore());
|
||||||
|
|
||||||
@@ -22,9 +22,9 @@ const openEdit = async (ledgerId: string) => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<div v-for="ledger in ledgers" :key="ledger.ledgerId" class="flex items-center mb-2">
|
<div v-for="ledger in ledgers" :key="ledger.ledgerId" class="flex items-center mb-2">
|
||||||
<LedgerLabel :ledger="ledger" />
|
<LedgerLabel :ledger="ledger" :link="true" />
|
||||||
<div class="flex grow">
|
<div class="flex grow">
|
||||||
<span class="ms-2">{{ formatIsk(ledger.balance) }}</span>
|
<IskLabel class="ms-2" :amount="ledger.balance" />
|
||||||
</div>
|
</div>
|
||||||
<button class="btn-icon ms-2" @click="openEdit(ledger.ledgerId)"><PencilSquareIcon /></button>
|
<button class="btn-icon ms-2" @click="openEdit(ledger.ledgerId)"><PencilSquareIcon /></button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const {characters} = storeToRefs(useCharactersStore());
|
|||||||
<div class="grid mb-2 mt-4">
|
<div class="grid mb-2 mt-4">
|
||||||
<div v-for="character in characters" :key="character.characterId" class="flex items-center mb-2">
|
<div v-for="character in characters" :key="character.characterId" class="flex items-center mb-2">
|
||||||
<CharacterLabel class="flex grow" :character="character" />
|
<CharacterLabel class="flex grow" :character="character" />
|
||||||
<RouterLink class="btn-icon ms-2" :to="{ name: routeNames.characterRulebook, params: { characterId: character.characterId } }"><PencilSquareIcon /></RouterLink>
|
<RouterLink class="btn-icon ms-2" :to="{ name: routeNames.editCharacterRulebook, params: { characterId: character.characterId } }"><PencilSquareIcon /></RouterLink>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
+4
-2
@@ -3,10 +3,11 @@ import {RouteRecordRaw} from 'vue-router';
|
|||||||
export const routeNames = {
|
export const routeNames = {
|
||||||
home: 'home',
|
home: 'home',
|
||||||
callback: 'callback',
|
callback: 'callback',
|
||||||
|
listLedgerTransactions: 'list-ledger-tTransactions',
|
||||||
listRuleBooks: 'list-rule-books',
|
listRuleBooks: 'list-rule-books',
|
||||||
newRuleBook: 'new-rule-book',
|
newRuleBook: 'new-rule-book',
|
||||||
editRuleBook: 'edit-rule-book',
|
editRuleBook: 'edit-rule-book',
|
||||||
characterRulebook: 'character-rulebook',
|
editCharacterRulebook: 'edit-character-rule-book',
|
||||||
marketTypes: 'market-types',
|
marketTypes: 'market-types',
|
||||||
about: 'about',
|
about: 'about',
|
||||||
} as const;
|
} as const;
|
||||||
@@ -17,6 +18,7 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
|
|
||||||
{path: '/ledgers', component: () => import('@/pages/Ledgers.vue'), children: [
|
{path: '/ledgers', component: () => import('@/pages/Ledgers.vue'), children: [
|
||||||
{path: '', component: () => import('@/pages/ledger/ListLedgers.vue')},
|
{path: '', component: () => import('@/pages/ledger/ListLedgers.vue')},
|
||||||
|
{path: ':ledgerId/transactions', name: routeNames.listLedgerTransactions, component: () => import('@/pages/ledger/ListLedgerTransactions.vue')},
|
||||||
]},
|
]},
|
||||||
|
|
||||||
{path: '/rules', component: () => import('@/pages/Rules.vue'), children: [
|
{path: '/rules', component: () => import('@/pages/Rules.vue'), children: [
|
||||||
@@ -28,7 +30,7 @@ export const routes: RouteRecordRaw[] = [
|
|||||||
]},
|
]},
|
||||||
{path: '/characters/rules', children: [
|
{path: '/characters/rules', children: [
|
||||||
{path: '', component: () => import('@/pages/rules/ListCharacterRuleBooks.vue')},
|
{path: '', component: () => import('@/pages/rules/ListCharacterRuleBooks.vue')},
|
||||||
{path: '/characters/:characterId/rules', name: routeNames.characterRulebook, component: () => import('@/pages/rules/EditCharacterRuleBook.vue')},
|
{path: '/characters/:characterId/rules', name: routeNames.editCharacterRulebook, component: () => import('@/pages/rules/EditCharacterRuleBook.vue')},
|
||||||
]}
|
]}
|
||||||
]},
|
]},
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user