Files
nuxt-claude/app/pages/index.vue
NEW_GIL_HOME\hyeon e66321386a
Some checks failed
ci / ci (22, ubuntu-latest) (push) Failing after 25m52s
feat: nuxt-claude 프로젝트 초기 커밋
Made-with: Cursor
2026-03-08 16:36:13 +09:00

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>