fix tx isdone checkbox text size

This commit is contained in:
xds
2025-11-19 10:09:06 +03:00
parent 64197636f0
commit 749214bab7
6 changed files with 258 additions and 11 deletions

View File

@@ -0,0 +1,76 @@
<script setup lang="ts">
import {onMounted, ref} from "vue";
import {Target} from "@/models/targets";
import {useRouter} from "vue-router";
import {useToolbarStore} from "@/stores/toolbar-store";
import {useSpaceStore} from "@/stores/spaceStore";
import {targetService} from "@/services/targets-service";
import {useToast} from "primevue/usetoast";
import {ProgressBar} from "primevue";
import {TargetTypeIcon, TargetTypeName} from "@/models/enums";
import {formatAmount} from "@/utils/utils";
const toast = useToast();
const router = useRouter()
const toolbar = useToolbarStore()
const spaceStore = useSpaceStore()
const targets = ref<Target[]>([])
const fetchData = async () => {
try {
if (spaceStore.selectedSpaceId) {
targets.value = await targetService.fetchTargets(spaceStore.selectedSpaceId)
}
} catch (e) {
console.error(e)
toast.add({
severity: 'error',
summary: 'Failed to fetch target list.',
detail: e.message
})
}
}
onMounted(async () => {
await fetchData()
toolbar.registerHandler('openTargetCreation', () => {
router.push('/targets/create')
})
})
</script>
<template>
<div class="targets-list">
<div v-for="target in targets" class="card w-full">
<div class="flex flex-col items-start justify-items-start justify-start w-full px-4 pb-4">
<div class="flex flex-row items-center gap-2">
<span class="text-4xl ">{{ TargetTypeIcon[target.type] }}</span>
<div class="flex flex-col">
<h2 class="text-2xl !font-semibold">{{ target.name }}</h2>
<span class="text-sm text-gray-200"> {{ target.description }} | {{ TargetTypeName[target.type] }}</span>
</div>
</div>
<div class="flex flex-col w-full">
<div class="flex flex-row justify-between !w-full">
<span> {{formatAmount(target.currentAmount)}} </span>
<span>{{formatAmount(target.amount)}} </span>
</div>
<ProgressBar :value="((target.currentAmount / target.amount)*100).toFixed(0)" />
</div>
</div>
</div>
</div>
</template>
<style scoped>
.targets-list {
display: flex;
flex-direction: column;
gap: 1.5rem;
padding-bottom: 2.5rem;
}
</style>

View File

@@ -206,7 +206,9 @@ const deleteTransaction = async () => {
if (spaceStore.selectedSpaceId && transactionId.value) {
await transactionService.deleteTransaction(spaceStore.selectedSpaceId, Number(transactionId.value))
await transactionStore.fetchTransactions(spaceStore.selectedSpaceId)
await moveUser()
if (openMode && openMode === "from_bot") {
tgApp.close()
} else await moveUser()
}
}

View File

@@ -21,6 +21,7 @@ export enum TransactionType {
INCOME = "INCOME",
EXPENSE = "EXPENSE",
}
export const TransactionTypeName: Record<TransactionType, string> = {
[TransactionType.EXPENSE]: 'Расходы',
[TransactionType.INCOME]: 'Поступления',
@@ -30,9 +31,33 @@ export enum TransactionKind {
PLANNING = "PLANNING",
INSTANT = "INSTANT",
}
export const TransactionKindName: Record<TransactionKind, string> = {
[TransactionKind.INSTANT]: 'Текущие',
[TransactionKind.PLANNING]: 'Плановые',
}
export enum TargetType {
AUTO = "AUTO",
LEISURE = "LEISURE",
VACATION = "VACATION",
GOODS = "GOODS",
OTHER = "OTHER",
}
export const TargetTypeName: Record<TargetType, string> = {
[TargetType.AUTO]: 'Авто',
[TargetType.LEISURE]: 'Досуг',
[TargetType.VACATION]: 'Отпуск',
[TargetType.GOODS]: 'Покупка',
[TargetType.OTHER]: 'Другое'
}
export const TargetTypeIcon: Record<TargetType, string> = {
[TargetType.AUTO]: '🏎️',
[TargetType.LEISURE]: '💃',
[TargetType.VACATION]: '🏖',
[TargetType.GOODS]: '🛍️',
[TargetType.OTHER]: '💸'
}

63
src/models/targets.ts Normal file
View File

@@ -0,0 +1,63 @@
import {Transaction} from "@/models/transaction";
import {User} from "@/models/user";
import {TargetType} from "@/models/enums";
export interface Target {
id: number,
type: TargetType,
name: string,
description: string | null,
amount: number,
currentAmount: number,
date: Date | string,
components: TargetComponent[],
transactions: Transaction[],
createdBy: User,
createdAt: Date,
updatedBy: User | null,
updatedAt: Date | null,
}
export interface CreateTargetDTO {
type: TargetType,
name: string,
description: string | null,
amount: number,
date: Date | string,
}
export interface UpdateTargetDTO {
type: TargetType,
name: string,
description: string | null,
amount: number,
date: Date | string,
}
export interface TargetComponent {
id: number,
name: string,
amount: number,
isDone: boolean,
date: Date | string,
}
export interface CreateTargetComponent {
name: string,
amount: number,
date: Date | string,
}
export interface UpdateTargetComponent {
name: string,
amount: number,
isDone: boolean,
date: Date | string,
}

View File

@@ -8,6 +8,7 @@ import RecurrentyCreateUpdate from "@/components/settings/RecurrentyCreateUpdate
import TransactionList from "@/components/transactions/TransactionList.vue";
import LoginPage from "@/components/auth/LoginPage.vue";
import TransactionCreateUpdate from "@/components/transactions/TransactionCreateUpdate.vue";
import TargetList from "@/components/targets/TargetList.vue";
// 📝 Расширяем тип меты роутов (типобезопасный toolbar, requiresAuth, guestOnly)
declare module 'vue-router' {
@@ -32,6 +33,9 @@ export const enum RouteName {
TransactionList = 'transaction-list',
TransactionCreate = 'transaction-create',
TransactionUpdate = 'transaction-update',
TargetList = 'target-list',
TargetCreate = 'target-create',
TargetUpdate = 'target-update',
SettingsList = 'settings-list',
CategoriesList = 'categories-list',
CategoryCreate = 'category-create',
@@ -45,7 +49,12 @@ export const enum RouteName {
const routes: RouteRecordRaw[] = [
{path: '/login', name: RouteName.Login, component: LoginPage, meta: {requiresAuth: false, navStack: 'auth'}},
{path: '/', name: RouteName.Dashboard, component: DashboardView, meta: {requiresAuth: true, navStack: 'dashboard', title: "Home"}},
{
path: '/',
name: RouteName.Dashboard,
component: DashboardView,
meta: {requiresAuth: true, navStack: 'dashboard', title: "Home"}
},
{
path: '/transactions',
name: RouteName.TransactionList,
@@ -53,7 +62,7 @@ const routes: RouteRecordRaw[] = [
meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'openTransactionCreation', text: '', icon: 'pi pi-plus', onClickId: 'openTransactionCreation'},
],
navStack: 'transactions',
@@ -75,7 +84,7 @@ const routes: RouteRecordRaw[] = [
path: '/transactions/:id/edit', name: RouteName.TransactionUpdate, component: TransactionCreateUpdate, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'deleteTransaction', text: '', icon: 'pi pi-trash', onClickId: 'deleteTransaction'},
{id: 'updateTransaction', text: '', icon: 'pi pi-save', onClickId: 'updateTransaction'},
],
@@ -83,17 +92,56 @@ const routes: RouteRecordRaw[] = [
title: "Edit transaction"
}
},
{
path: '/targets',
name: RouteName.TargetList,
component: TargetList,
meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'openTargetCreation', text: '', icon: 'pi pi-plus', onClickId: 'openTargetCreation'},
],
navStack: 'targets',
title: "Targets"
}
},
// {
// path: '/transactions/create', name: RouteName.TransactionCreate, component: TransactionCreateUpdate, meta: {
// requiresAuth: true,
// toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
// {id: 'createTransaction', text: '', icon: 'pi pi-save', onClickId: 'createTransaction'},
// ],
// navStack: 'transactions',
// title: "Create transaction"
// }
// },
// {
// path: '/transactions/:id/edit', name: RouteName.TransactionUpdate, component: TransactionCreateUpdate, meta: {
// requiresAuth: true,
// toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
//
// {id: 'deleteTransaction', text: '', icon: 'pi pi-trash', onClickId: 'deleteTransaction'},
// {id: 'updateTransaction', text: '', icon: 'pi pi-save', onClickId: 'updateTransaction'},
// ],
// navStack: 'settings',
// title: "Edit transaction"
// }
// },
{
path: '/settings',
name: RouteName.SettingsList,
component: SettingsList,
meta: {requiresAuth: true, navStack: 'settings', title: "Settings"}
meta: {requiresAuth: true, navStack: 'settings', title: "Settings"}
},
{
path: '/categories', name: RouteName.CategoriesList, component: CategoriesList, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'openCategoryCreation', text: '', icon: 'pi pi-plus', onClickId: 'openCategoryCreation'},
],
navStack: 'settings',
@@ -104,7 +152,7 @@ const routes: RouteRecordRaw[] = [
path: '/categories/create', name: RouteName.CategoryCreate, component: CategoryCreateUpdate, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'createCategory', text: '', icon: 'pi pi-save', onClickId: 'createCategory'},
],
navStack: 'settings',
@@ -115,7 +163,7 @@ const routes: RouteRecordRaw[] = [
path: '/categories/:id/edit', name: RouteName.CategoryUpdate, component: CategoryCreateUpdate, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'deleteCategory', text: '', icon: 'pi pi-trash', onClickId: 'deleteCategory'},
{id: 'updateCategory', text: '', icon: 'pi pi-save', onClickId: 'updateCategory'},
],
@@ -129,7 +177,7 @@ const routes: RouteRecordRaw[] = [
path: '/recurrents', name: RouteName.RecurrentsList, component: RecurrentsList, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'openRecurrentCreation', text: '', icon: 'pi pi-plus', onClickId: 'openRecurrentCreation'},
],
navStack: 'settings',
@@ -140,7 +188,7 @@ const routes: RouteRecordRaw[] = [
path: '/recurrents/create', name: RouteName.RecurrentCreate, component: RecurrentyCreateUpdate, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'createRecurrent', text: '', icon: 'pi pi-save', onClickId: 'createRecurrent'},
],
navStack: 'settings',
@@ -151,7 +199,7 @@ const routes: RouteRecordRaw[] = [
path: '/recurrents/:id/edit', name: RouteName.RecurrentUpdate, component: RecurrentyCreateUpdate, meta: {
requiresAuth: true,
toolbar: ({spaceStore}: { spaceStore: ReturnType<typeof useSpaceStore> }) => [
{id: 'deleteRecurrent', text: '', icon: 'pi pi-trash', onClickId: 'deleteRecurrent'},
{id: 'updateRecurrent', text: '', icon: 'pi pi-save', onClickId: 'updateRecurrent'},
],

View File

@@ -0,0 +1,33 @@
import {Target} from "@/models/targets";
import {TargetType} from "@/models/enums";
import {User} from "@/models/user";
async function fetchTargets(spaceId: number): Promise<Target[]> {
const targets = [];
for (var i = 0; i < 10; i++) {
const rand = Math.floor(Math.random() * 5);
const now = new Date();
const amount = Math.floor(Math.random() * 100000);
now.setDate(Math.floor(Math.random() * 30))
targets.push({
id: i,
type: rand == 1 ? TargetType.AUTO : rand == 2 ? TargetType.LEISURE : rand == 3 ? TargetType.VACATION : rand == 4 ? TargetType.GOODS : TargetType.OTHER,
name: `Target ${i}`,
description: `Target ${i} description`,
amount: amount,
currentAmount: Math.floor(Math.random() * amount),
date: now,
components: [],
transactions: [],
createdBy: {} as User,
createdAt: new Date(),
updatedBy: {} as User,
updatedAt: new Date(),
} as Target)
}
return targets;
}
export const targetService = {
fetchTargets
};