Files
web-frontend/app/pages/bonus-system/index.vue
2026-04-03 19:23:08 +07:00

140 lines
5.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { useQuery } from '@vue/apollo-composable';
import {
ReferralStatsDocument,
type ReferralStatsQuery,
} from '~/composables/graphql/generated';
definePageMeta({
middleware: ['manager-only'],
});
type TransactionItem = ReferralStatsQuery['referralStats']['transactions'][number];
type WithdrawalItem = ReferralStatsQuery['referralStats']['pendingWithdrawals'][number];
const bonusQuery = useQuery(ReferralStatsDocument);
const search = ref('');
const transactions = computed<TransactionItem[]>(() => bonusQuery.result.value?.referralStats.transactions ?? []);
const withdrawals = computed<WithdrawalItem[]>(() => bonusQuery.result.value?.referralStats.pendingWithdrawals ?? []);
const filteredTransactions = computed(() => {
const query = search.value.trim().toLowerCase();
return transactions.value.filter((transaction) => {
if (!query) {
return true;
}
return [
transaction.userId,
transaction.reason,
transaction.orderId || '',
String(transaction.amount),
]
.join(' ')
.toLowerCase()
.includes(query);
});
});
</script>
<template>
<section class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
<div class="manager-hero">
<p class="manager-eyebrow">Бонусы</p>
<h1 class="manager-title">Отдельный раздел для бонусной системы</h1>
<p class="manager-copy">Здесь остаются история начислений и заявки на вывод, без смешивания с клиентами.</p>
</div>
<div class="flex flex-wrap gap-2">
<NuxtLink to="/bonus-system/referrals/new" class="btn btn-secondary border-0">Создать связь</NuxtLink>
<NuxtLink to="/bonus-system/transactions/new" class="btn btn-primary border-0">Добавить бонус</NuxtLink>
</div>
</div>
<div class="grid gap-4 lg:grid-cols-3">
<div class="manager-stat-card">
<p class="manager-stat-label">Баланс</p>
<p class="manager-stat-value">{{ bonusQuery.result.value?.referralStats.availableBalance ?? 0 }}</p>
</div>
<div class="manager-stat-card">
<p class="manager-stat-label">Рефералы</p>
<p class="manager-stat-value">{{ bonusQuery.result.value?.referralStats.referralsCount ?? 0 }}</p>
</div>
<div class="manager-stat-card">
<p class="manager-stat-label">Заявки на вывод</p>
<p class="manager-stat-value">{{ withdrawals.length }}</p>
</div>
</div>
<div class="surface-card rounded-3xl p-4 md:p-5">
<label class="form-control">
<span class="label-text">Search</span>
<input
v-model="search"
type="text"
class="input manager-field w-full"
placeholder="Пользователь, причина, заказ или сумма"
>
</label>
</div>
<div class="grid gap-4 xl:grid-cols-[1.1fr_0.9fr]">
<div class="surface-card rounded-3xl p-5">
<h2 class="text-xl font-bold text-[#123824]">История транзакций</h2>
<div v-if="bonusQuery.loading.value" class="manager-empty-state mt-4">
Загружаем историю...
</div>
<div v-else-if="filteredTransactions.length === 0" class="manager-empty-state mt-4">
Транзакции по текущему запросу не найдены.
</div>
<div v-else class="mt-4 space-y-3">
<article v-for="transaction in filteredTransactions" :key="transaction.id" class="surface-subcard p-4">
<div class="flex flex-wrap items-start justify-between gap-3">
<div>
<p class="text-sm font-semibold text-[#123824]">{{ transaction.reason }}</p>
<p class="mt-1 text-sm text-[#5c7b69]">Пользователь: {{ transaction.userId }}</p>
</div>
<div class="manager-mini-card text-sm font-semibold text-[#123824]">
{{ transaction.amount }}
</div>
</div>
<div class="mt-3 flex flex-wrap gap-3 text-xs text-[#5c7b69]">
<span>{{ new Date(transaction.createdAt).toLocaleString() }}</span>
<span v-if="transaction.orderId">Заказ: {{ transaction.orderId }}</span>
</div>
</article>
</div>
</div>
<div class="surface-card rounded-3xl p-5">
<h2 class="text-xl font-bold text-[#123824]">Заявки на вывод</h2>
<div v-if="bonusQuery.loading.value" class="manager-empty-state mt-4">
Загружаем заявки...
</div>
<div v-else-if="withdrawals.length === 0" class="manager-empty-state mt-4">
Активных заявок на вывод сейчас нет.
</div>
<div v-else class="mt-4 space-y-3">
<article v-for="withdrawal in withdrawals" :key="withdrawal.id" class="surface-subcard p-4">
<div class="space-y-2">
<p class="text-sm font-semibold text-[#123824]">Пользователь: {{ withdrawal.requesterId }}</p>
<p class="text-sm text-[#355947]">Сумма: {{ withdrawal.amount }}</p>
<p class="text-xs text-[#5c7b69]">{{ new Date(withdrawal.createdAt).toLocaleString() }}</p>
</div>
<div class="mt-4">
<NuxtLink :to="`/bonus-system/withdrawals/${withdrawal.id}`" class="btn btn-accent btn-sm border-0">
Проверить вывод
</NuxtLink>
</div>
</article>
</div>
</div>
</div>
</section>
</template>