Some checks failed
ci / ci (22, ubuntu-latest) (push) Failing after 25m52s
Made-with: Cursor
130 lines
4.6 KiB
Vue
130 lines
4.6 KiB
Vue
<script setup lang="ts">
|
|
import { CATEGORY_LABELS } from '~/types/purchase'
|
|
import { STATUS_LABELS, PLATFORM_LABELS } from '~/types/used-sale'
|
|
import type { EquipmentCategory } from '~/types/purchase'
|
|
import type { SaleStatus, SalePlatform } from '~/types/used-sale'
|
|
|
|
definePageMeta({ middleware: 'auth' })
|
|
|
|
const { purchases, totalSpent, fetchPurchases } = usePurchases()
|
|
const { sales, totalRevenue, byStatus, fetchSales } = useUsedSales()
|
|
|
|
await Promise.all([fetchPurchases(), fetchSales()])
|
|
|
|
const recentPurchases = computed(() => purchases.value.slice(0, 5))
|
|
const recentSales = computed(() => sales.value.slice(0, 5))
|
|
|
|
const stats = computed(() => [
|
|
{
|
|
label: '총 구매금액',
|
|
value: totalSpent.value.toLocaleString('ko-KR') + '원',
|
|
icon: 'i-lucide-shopping-cart',
|
|
color: 'text-blue-500'
|
|
},
|
|
{
|
|
label: '보유 장비',
|
|
value: purchases.value.length + '개',
|
|
icon: 'i-lucide-tent',
|
|
color: 'text-green-500'
|
|
},
|
|
{
|
|
label: '판매 수익',
|
|
value: totalRevenue.value.toLocaleString('ko-KR') + '원',
|
|
icon: 'i-lucide-coins',
|
|
color: 'text-yellow-500'
|
|
},
|
|
{
|
|
label: '판매중',
|
|
value: byStatus.value.listing.length + '개',
|
|
icon: 'i-lucide-tag',
|
|
color: 'text-purple-500'
|
|
}
|
|
])
|
|
|
|
function formatPrice(price: number) {
|
|
return price.toLocaleString('ko-KR') + '원'
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="p-6 space-y-6">
|
|
<div>
|
|
<h1 class="text-2xl font-bold text-gray-900 dark:text-white">대시보드</h1>
|
|
<p class="text-gray-500 dark:text-gray-400 mt-1">캠핑 장비 현황을 한눈에 확인하세요</p>
|
|
</div>
|
|
|
|
<!-- Stats -->
|
|
<div class="grid grid-cols-2 lg:grid-cols-4 gap-4">
|
|
<UCard v-for="stat in stats" :key="stat.label">
|
|
<div class="flex items-center gap-3">
|
|
<UIcon :name="stat.icon" class="text-2xl shrink-0" :class="stat.color" />
|
|
<div>
|
|
<p class="text-xs text-gray-500 dark:text-gray-400">{{ stat.label }}</p>
|
|
<p class="text-lg font-bold text-gray-900 dark:text-white">{{ stat.value }}</p>
|
|
</div>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
<!-- Recent Purchases -->
|
|
<UCard>
|
|
<template #header>
|
|
<div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-800">
|
|
<h3 class="font-semibold text-gray-900 dark:text-white">최근 구매 장비</h3>
|
|
<NuxtLink to="/purchases" class="text-sm text-primary-500 hover:text-primary-600">전체보기</NuxtLink>
|
|
</div>
|
|
</template>
|
|
<div class="divide-y divide-gray-100 dark:divide-gray-800">
|
|
<div
|
|
v-for="p in recentPurchases"
|
|
:key="p.id"
|
|
class="flex items-center justify-between py-3 px-4"
|
|
>
|
|
<div>
|
|
<p class="font-medium text-sm text-gray-900 dark:text-white">{{ p.name }}</p>
|
|
<p class="text-xs text-gray-500">
|
|
{{ CATEGORY_LABELS[p.category as EquipmentCategory] }} · {{ p.purchase_date }}
|
|
</p>
|
|
</div>
|
|
<span class="text-sm font-semibold text-gray-900 dark:text-white">
|
|
{{ formatPrice(p.price) }}
|
|
</span>
|
|
</div>
|
|
<p v-if="recentPurchases.length === 0" class="text-sm text-gray-400 text-center py-6">
|
|
구매한 장비가 없습니다
|
|
</p>
|
|
</div>
|
|
</UCard>
|
|
|
|
<!-- Recent Sales -->
|
|
<UCard>
|
|
<template #header>
|
|
<div class="flex items-center justify-between px-4 py-3 border-b border-gray-200 dark:border-gray-800">
|
|
<h3 class="font-semibold text-gray-900 dark:text-white">중고 판매 현황</h3>
|
|
<NuxtLink to="/used-sales" class="text-sm text-primary-500 hover:text-primary-600">전체보기</NuxtLink>
|
|
</div>
|
|
</template>
|
|
<div class="divide-y divide-gray-100 dark:divide-gray-800">
|
|
<div
|
|
v-for="s in recentSales"
|
|
:key="s.id"
|
|
class="flex items-center justify-between py-3 px-4"
|
|
>
|
|
<div>
|
|
<p class="font-medium text-sm text-gray-900 dark:text-white">{{ s.item_name }}</p>
|
|
<p class="text-xs text-gray-500">
|
|
{{ PLATFORM_LABELS[s.platform as SalePlatform] }} · {{ s.listed_at }}
|
|
</p>
|
|
</div>
|
|
<UsedSalesUsedSaleBadge :status="s.status as SaleStatus" />
|
|
</div>
|
|
<p v-if="recentSales.length === 0" class="text-sm text-gray-400 text-center py-6">
|
|
판매 등록된 장비가 없습니다
|
|
</p>
|
|
</div>
|
|
</UCard>
|
|
</div>
|
|
</div>
|
|
</template>
|